diff --git a/pkg/cli/errors.go b/pkg/cli/errors.go index 9a41e064f..6b668d465 100644 --- a/pkg/cli/errors.go +++ b/pkg/cli/errors.go @@ -1,6 +1,9 @@ package cli -import "errors" +import ( + "errors" + "fmt" +) // ErrHelpRequested is returned by verb ParseCLIFunc when -h or --help is used. // The caller (CLI layer) should exit with code 0 after the verb has printed its @@ -11,3 +14,11 @@ var ErrHelpRequested = errors.New("help requested") // verb has already printed its usage to stderr. The caller should exit 1 // without printing the error again. var ErrUsagePrinted = errors.New("usage printed") + +// FlagErrorf is for user-facing main-flag errors (the counterpart of +// VerbErrorf for verb flags). The message is complete prose, ready for the +// entrypoint layer to print as-is: it should carry the "mlr: " prefix and may +// span multiple lines. +func FlagErrorf(format string, args ...interface{}) error { + return fmt.Errorf(format, args...) +} diff --git a/pkg/cli/flag_types.go b/pkg/cli/flag_types.go index 1bb2c7af7..09e87249e 100644 --- a/pkg/cli/flag_types.go +++ b/pkg/cli/flag_types.go @@ -55,12 +55,15 @@ import ( // the latter case, and mutating the options struct. // - Successful handling of the flag is indicated by this function making a // non-zero increment of *pargi. +// - Invalid or missing flag arguments are reported by returning a non-nil +// error, which the caller propagates up to the entrypoint layer (see +// plans/exit.md); parsers must not call os.Exit. type FlagParser func( args []string, argc int, pargi *int, options *TOptions, -) +) error // FlagTable holds all the flags for Miller, organized into sections. type FlagTable struct { @@ -132,13 +135,15 @@ func (ft *FlagTable) Sort() { // Parse is for parsing a flag on the command line. Given say `--foo`, if a // Flag object is found which owns the flag, and if its parser accepts it (e.g. // `bar` is present and spelt correctly if the flag-parser expects `--foo bar`) -// then the return value is true, else false. +// then the boolean return value is true, else false. A non-nil error means the +// flag was recognized but its argument was missing or invalid; the caller +// should propagate it rather than continuing to parse. func (ft *FlagTable) Parse( args []string, argc int, pargi *int, options *TOptions, -) bool { +) (bool, error) { for _, section := range ft.sections { for _, flag := range section.flags { if flag.Owns(args[*pargi]) { @@ -146,13 +151,15 @@ func (ft *FlagTable) Parse( // arguments follow the flag. E.g. `--ifs pipe` will advance // *pargi by 2; `-I` will advance it by 1. oargi := *pargi - flag.parser(args, argc, pargi, options) + if err := flag.parser(args, argc, pargi, options); err != nil { + return false, err + } nargi := *pargi - return nargi > oargi + return nargi > oargi, nil } } } - return false + return false, nil } // ShowHelp prints all-in-one on-line help, nominally for `mlr help flags`. @@ -517,14 +524,15 @@ func (flag *Flag) NilCheck() { // NoOpParse1 is a helper function for flags which take no argument and are // backward-compatibility no-ops. -func NoOpParse1(args []string, argc int, pargi *int, options *TOptions) { +func NoOpParse1(args []string, argc int, pargi *int, options *TOptions) error { *pargi += 1 + return nil } // Introspection accessors for shell-completion support // (pkg/terminals/completion). These expose flag names and arity without -// invoking the parser functions, which is important since some flag parsers -// os.Exit on missing arguments. +// invoking the parser functions, which is important since the parser +// functions mutate the options struct (and can consume arguments). // TakesArg reports whether the flag consumes a following argument value, e.g. // `--ifs {string}` takes an argument whereas `--repifs` does not. @@ -559,8 +567,8 @@ func (ft *FlagTable) GetFlagNames() []string { // FlagTakesArg looks up a main flag by any of its spellings. The first return // value reports whether the flag is a recognized main flag; the second reports // whether it consumes a following argument value. This drives the -// shell-completion command-line walk without calling the (possibly -// os.Exit-ing) parser functions. +// shell-completion command-line walk without calling the (options-mutating) +// parser functions. func (ft *FlagTable) FlagTakesArg(name string) (found bool, takesArg bool) { for _, section := range ft.sections { for _, flag := range section.flags { diff --git a/pkg/cli/mlrcli_util.go b/pkg/cli/mlrcli_util.go index f7051feec..d4fa1cb5c 100644 --- a/pkg/cli/mlrcli_util.go +++ b/pkg/cli/mlrcli_util.go @@ -1,18 +1,16 @@ package cli -import ( - "fmt" - "os" -) - // CheckArgCount is for flags with values, e.g. ["-n" "10"], while we're -// looking at the "-n": this let us see if the "10" slot exists. -func CheckArgCount(args []string, argi int, argc int, n int) { +// looking at the "-n": this let us see if the "10" slot exists. A non-nil +// return is a (multi-line) user-facing error, ready for printing as-is by the +// entrypoint layer. +func CheckArgCount(args []string, argi int, argc int, n int) error { if (argc - argi) < n { - fmt.Fprintf(os.Stderr, "%s: option \"%s\" missing argument(s).\n", "mlr", args[argi]) - fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for detailed usage information.\n", "mlr") - os.Exit(1) + return FlagErrorf( + "%s: option \"%s\" missing argument(s).\nPlease run \"%s --help\" for detailed usage information.", + "mlr", args[argi], "mlr") } + return nil } // SeparatorFromArg is for letting people do things like `--ifs pipe` diff --git a/pkg/cli/option_parse.go b/pkg/cli/option_parse.go index e9083bc95..e9e24036b 100644 --- a/pkg/cli/option_parse.go +++ b/pkg/cli/option_parse.go @@ -257,8 +257,10 @@ var SeparatorFlagSection = FlagSection{ name: "--ifs", arg: "{string}", help: "Specify FS for input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -267,6 +269,7 @@ var SeparatorFlagSection = FlagSection{ options.ReaderOptions.ifsWasSpecified = true } *pargi += 2 + return nil }, }, @@ -274,8 +277,10 @@ var SeparatorFlagSection = FlagSection{ name: "--ifs-regex", arg: "{string}", help: "Specify FS for input as a regular expression.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -284,6 +289,7 @@ var SeparatorFlagSection = FlagSection{ options.ReaderOptions.ifsWasSpecified = true } *pargi += 2 + return nil }, }, @@ -291,11 +297,14 @@ var SeparatorFlagSection = FlagSection{ name: "--ips", arg: "{string}", help: "Specify PS for input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.IPS = SeparatorFromArg(args[*pargi+1]) options.ReaderOptions.ipsWasSpecified = true *pargi += 2 + return nil }, }, @@ -303,11 +312,14 @@ var SeparatorFlagSection = FlagSection{ name: "--ips-regex", arg: "{string}", help: "Specify PS for input as a regular expression.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.IPSRegex = lib.CompileMillerRegexOrDie(SeparatorRegexFromArg(args[*pargi+1])) options.ReaderOptions.ipsWasSpecified = true *pargi += 2 + return nil }, }, @@ -315,8 +327,10 @@ var SeparatorFlagSection = FlagSection{ name: "--irs", arg: "{string}", help: "Specify RS for input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -325,16 +339,18 @@ var SeparatorFlagSection = FlagSection{ options.ReaderOptions.irsWasSpecified = true } *pargi += 2 + return nil }, }, { name: "--repifs", help: "Let IFS be repeated: e.g. for splitting on multiple spaces.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.AllowRepeatIFS = true options.ReaderOptions.allowRepeatIFSWasSpecified = true *pargi += 1 + return nil }, }, @@ -342,8 +358,10 @@ var SeparatorFlagSection = FlagSection{ name: "--ors", arg: "{string}", help: "Specify RS for output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -352,6 +370,7 @@ var SeparatorFlagSection = FlagSection{ options.WriterOptions.orsWasSpecified = true } *pargi += 2 + return nil }, }, @@ -359,11 +378,14 @@ var SeparatorFlagSection = FlagSection{ name: "--ofs", arg: "{string}", help: "Specify FS for output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.OFS = SeparatorFromArg(args[*pargi+1]) options.WriterOptions.ofsWasSpecified = true *pargi += 2 + return nil }, }, @@ -371,11 +393,14 @@ var SeparatorFlagSection = FlagSection{ name: "--ops", arg: "{string}", help: "Specify PS for output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.OPS = SeparatorFromArg(args[*pargi+1]) options.WriterOptions.opsWasSpecified = true *pargi += 2 + return nil }, }, @@ -383,8 +408,10 @@ var SeparatorFlagSection = FlagSection{ name: "--rs", arg: "{string}", help: "Specify RS for input and output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -395,6 +422,7 @@ var SeparatorFlagSection = FlagSection{ options.WriterOptions.orsWasSpecified = true } *pargi += 2 + return nil }, }, @@ -402,8 +430,10 @@ var SeparatorFlagSection = FlagSection{ name: "--fs", arg: "{string}", help: "Specify FS for input and output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // Backward compatibility with Miller <= 5. Auto-inference of // LF vs CR/LF line endings is handled within Go libraries so // we needn't do anything ourselves. @@ -414,6 +444,7 @@ var SeparatorFlagSection = FlagSection{ options.WriterOptions.ofsWasSpecified = true } *pargi += 2 + return nil }, }, @@ -421,13 +452,16 @@ var SeparatorFlagSection = FlagSection{ name: "--ps", arg: "{string}", help: "Specify PS for input and output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.IPS = SeparatorFromArg(args[*pargi+1]) options.WriterOptions.OPS = SeparatorFromArg(args[*pargi+1]) options.ReaderOptions.ipsWasSpecified = true options.WriterOptions.opsWasSpecified = true *pargi += 2 + return nil }, }, }, @@ -449,18 +483,20 @@ var JSONOnlyFlagSection = FlagSection{ { name: "--jvstack", help: "Put one key-value pair per line for JSON output (multi-line output). This is the default for JSON output format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { name: "--no-jvstack", help: "Put objects/arrays all on one line for JSON output. This is the default for JSON Lines output format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, @@ -468,18 +504,20 @@ var JSONOnlyFlagSection = FlagSection{ name: "--jlistwrap", altNames: []string{"--jl"}, help: "Wrap JSON output in outermost `[ ]`. This is the default for JSON output format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.WrapJSONOutputInOuterList = true *pargi += 1 + return nil }, }, { name: "--no-jlistwrap", help: "Do not wrap JSON output in outermost `[ ]`. This is the default for JSON Lines output format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.WrapJSONOutputInOuterList = false *pargi += 1 + return nil }, }, @@ -487,26 +525,29 @@ var JSONOnlyFlagSection = FlagSection{ name: "--yarray", altNames: []string{"--ya"}, help: "Wrap YAML output in a single top-level array document. This is the default for YAML output format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { name: "--no-yarray", help: "Do not wrap YAML output in a single array document; emit one YAML document per record with `---` between.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.WrapYAMLOutputInOuterList = false *pargi += 1 + return nil }, }, { name: "--jvquoteall", help: "Force all JSON values -- recursively into lists and object -- to string.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.JVQuoteAll = true *pargi += 1 + return nil }, }, }, @@ -528,9 +569,10 @@ var PPRINTOnlyFlagSection = FlagSection{ { name: "--right", help: "Right-justifies all fields for PPRINT output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.RightAlignedPPRINTOutput = true *pargi += 1 + return nil }, }, @@ -541,9 +583,10 @@ var PPRINTOnlyFlagSection = FlagSection{ "whose values are all numeric, so that header and data share the same " + "alignment. Also applies to markdown output, where numeric columns get " + "right-alignment markers (`---:`) in the header-separator line.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.RightAlignNumericOutput = true *pargi += 1 + return nil }, }, @@ -551,29 +594,32 @@ var PPRINTOnlyFlagSection = FlagSection{ name: "--barred", altNames: []string{"--barred-output"}, help: "Prints a border around PPRINT output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { name: "--barred-unicode", help: "Uses unicode printing chars for barred output", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.BarredPprintOutput = true options.WriterOptions.BarredUseUnicode = true *pargi += 1 + return nil }, }, { name: "--barred-input", help: "When used in conjunction with --pprint, accepts barred input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.BarredPprintInput = true options.ReaderOptions.IFS = "|" *pargi += 1 + return nil }, }, @@ -581,9 +627,10 @@ var PPRINTOnlyFlagSection = FlagSection{ name: "--fixed", arg: "{string}", help: "Fixed width specification. One of 'widths:,,...', left-align, left-align-multi-word, right-align, right-align-multi-word", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FixedWidthSpec = args[*pargi+1] *pargi += 2 + return nil }, }, @@ -591,9 +638,10 @@ var PPRINTOnlyFlagSection = FlagSection{ name: "--fw", arg: "{string}", help: "Shortcut for --fixed left-align-multi-word", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FixedWidthSpec = "left-align-multi-word" *pargi += 1 + return nil }, }, }, @@ -619,10 +667,11 @@ var MarkdownOnlyFlagSection = FlagSection{ "column to a uniform width, making the raw markdown source easier " + "to read and maintain. (The rendered table is unaffected.) Implies " + "--omd, so you do not need to also pass --omd.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "markdown" options.WriterOptions.MarkdownAlignedOutput = true *pargi += 1 + return nil }, }, @@ -632,11 +681,12 @@ var MarkdownOnlyFlagSection = FlagSection{ help: "Use markdown-tabular format for input and output data, with " + "left-justified and padded columns. Implies --md, so you do not " + "need to also pass --md.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "markdown" options.WriterOptions.MarkdownAlignedOutput = true *pargi += 1 + return nil }, }, }, @@ -658,9 +708,10 @@ var DKVPOnlyFlagSection = FlagSection{ { name: "--incr-key", help: "Without this option, keyless DKVP fields are keyed by field number. For example: `a=10,b=20,30,d=40,50` is ingested as `$a=10,$b=20,$3=30,$d=40,$5=50`. With this option, they're keyed by a running counter of keyless fields. For example: `a=10,b=20,30,d=40,50` is ingested as `$a=10,$b=20,$1=30,$d=40,$2=50`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, }, @@ -786,37 +837,41 @@ var FileFormatFlagSection = FlagSection{ { name: "--icsv", help: "Use CSV format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" *pargi += 1 + return nil }, }, { name: "--icsvlite", help: "Use CSV-lite format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" *pargi += 1 + return nil }, }, { name: "--itsv", help: "Use TSV format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" *pargi += 1 + return nil }, }, { name: "--itsvlite", help: "Use TSV-lite format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.ReaderOptions.IFS = "\t" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, @@ -824,13 +879,14 @@ var FileFormatFlagSection = FlagSection{ name: "--iasv", altNames: []string{"--iasvlite"}, help: "Use ASV format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.ReaderOptions.IFS = ASV_FS options.ReaderOptions.IRS = ASV_RS options.ReaderOptions.ifsWasSpecified = true options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, @@ -838,96 +894,106 @@ var FileFormatFlagSection = FlagSection{ name: "--iusv", altNames: []string{"--iusvlite"}, help: "Use USV format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.ReaderOptions.IFS = USV_FS options.ReaderOptions.IRS = USV_RS options.ReaderOptions.ifsWasSpecified = true options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { name: "--idkvp", help: "Use DKVP format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { name: "--ijson", help: "Use JSON format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" *pargi += 1 + return nil }, }, { name: "--ijsonl", help: "Use JSON Lines format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" *pargi += 1 + return nil }, }, { name: "--iyaml", help: "Use YAML format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" *pargi += 1 + return nil }, }, { name: "--idcf", help: "Use Debian control file (DCF) format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dcf" *pargi += 1 + return nil }, }, { name: "--irecutils", help: "Use GNU recutils (.rec) format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "recutils" *pargi += 1 + return nil }, }, { name: "--inidx", help: "Use NIDX format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" *pargi += 1 + return nil }, }, { name: "--ixtab", help: "Use XTAB format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" *pargi += 1 + return nil }, }, { name: "--ipprint", help: "Use PPRINT format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, @@ -935,13 +1001,16 @@ var FileFormatFlagSection = FlagSection{ name: "-i", arg: "{format name}", help: "Use format name for input data. For example: `-i csv` is the same as `--icsv`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.InputFileFormat = args[*pargi+1] if options.ReaderOptions.InputFileFormat == "md" { options.ReaderOptions.InputFileFormat = "markdown" // alias } *pargi += 2 + return nil }, }, @@ -949,49 +1018,62 @@ var FileFormatFlagSection = FlagSection{ name: "--igen", help: `Ignore input files and instead generate sequential numeric input using --gen-field-name, --gen-start, --gen-step, and --gen-stop values. See also the seqgen verb, which is more useful/intuitive.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "gen" *pargi += 1 + return nil }, }, { name: "--gen-field-name", help: `Specify field name for --igen. Defaults to "` + DEFAULT_GEN_FIELD_NAME + `".`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "gen" - CheckArgCount(args, *pargi, argc, 2) + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.GeneratorOptions.FieldName = args[*pargi+1] *pargi += 2 + return nil }, }, { name: "--gen-start", help: "Specify start value for --igen. Defaults to " + DEFAULT_GEN_START_AS_STRING + ".", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "gen" - CheckArgCount(args, *pargi, argc, 2) + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.GeneratorOptions.StartAsString = args[*pargi+1] *pargi += 2 + return nil }, }, { name: "--gen-step", help: "Specify step value for --igen. Defaults to " + DEFAULT_GEN_STEP_AS_STRING + ".", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "gen" - CheckArgCount(args, *pargi, argc, 2) + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.GeneratorOptions.StepAsString = args[*pargi+1] *pargi += 2 + return nil }, }, { name: "--gen-stop", help: "Specify stop value for --igen. Defaults to " + DEFAULT_GEN_STOP_AS_STRING + ".", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "gen" - CheckArgCount(args, *pargi, argc, 2) + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.GeneratorOptions.StopAsString = args[*pargi+1] *pargi += 2 + return nil }, }, @@ -999,53 +1081,60 @@ var FileFormatFlagSection = FlagSection{ name: "-o", arg: "{format name}", help: "Use format name for output data. For example: `-o csv` is the same as `--ocsv`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.OutputFileFormat = args[*pargi+1] if options.WriterOptions.OutputFileFormat == "md" { options.WriterOptions.OutputFileFormat = "markdown" // alias } *pargi += 2 + return nil }, }, { name: "--ocsv", help: "Use CSV format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "csv" *pargi += 1 + return nil }, }, { name: "--ocsvlite", help: "Use CSV-lite format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "csvlite" *pargi += 1 + return nil }, }, { name: "--otsv", help: "Use TSV format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "tsv" options.WriterOptions.OFS = "\t" options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, { name: "--otsvlite", help: "Use TSV-lite format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "csvlite" options.WriterOptions.OFS = "\t" options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1053,13 +1142,14 @@ var FileFormatFlagSection = FlagSection{ name: "--oasv", altNames: []string{"--oasvlite"}, help: "Use ASV format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "csvlite" options.WriterOptions.OFS = ASV_FS options.WriterOptions.ORS = ASV_RS options.WriterOptions.ofsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1067,13 +1157,14 @@ var FileFormatFlagSection = FlagSection{ name: "--ousv", altNames: []string{"--ousvlite"}, help: "Use USV format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "csvlite" options.WriterOptions.OFS = USV_FS options.WriterOptions.ORS = USV_RS options.WriterOptions.ofsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1081,9 +1172,10 @@ var FileFormatFlagSection = FlagSection{ name: "--imd", altNames: []string{"--imarkdown"}, help: "Use markdown-tabular format for input data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -1091,9 +1183,10 @@ var FileFormatFlagSection = FlagSection{ name: "--omd", altNames: []string{"--omarkdown"}, help: "Use markdown-tabular format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -1101,96 +1194,106 @@ var FileFormatFlagSection = FlagSection{ name: "--md", altNames: []string{"--markdown"}, help: "Use markdown-tabular format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--odkvp", help: "Use DKVP format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { name: "--ojson", help: "Use JSON format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { name: "--ojsonl", help: "Use JSON Lines format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "jsonl" *pargi += 1 + return nil }, }, { name: "--oyaml", help: "Use YAML format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { name: "--odcf", help: "Use Debian control file (DCF) format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "dcf" *pargi += 1 + return nil }, }, { name: "--orecutils", help: "Use GNU recutils (.rec) format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "recutils" *pargi += 1 + return nil }, }, { name: "--onidx", help: "Use NIDX format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "nidx" options.WriterOptions.OFS = " " options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, { name: "--oxtab", help: "Use XTAB format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { name: "--opprint", help: "Use PPRINT format for output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, @@ -1198,16 +1301,17 @@ var FileFormatFlagSection = FlagSection{ name: "--io", arg: "{format name}", help: "Use format name for input and output data. For example: `--io csv` is the same as `--csv`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } if defaultFSes[args[*pargi+1]] == "" { - fmt.Fprintf(os.Stderr, "mlr: unrecognized I/O format \"%s\".\n", - args[*pargi+1]) - os.Exit(1) + return FlagErrorf("mlr: unrecognized I/O format \"%s\".", args[*pargi+1]) } options.ReaderOptions.InputFileFormat = args[*pargi+1] options.WriterOptions.OutputFileFormat = args[*pargi+1] *pargi += 2 + return nil }, }, @@ -1215,20 +1319,22 @@ var FileFormatFlagSection = FlagSection{ name: "--csv", help: "Use CSV format for input and output data.", altNames: []string{"-c", "--c2c"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "csv" *pargi += 1 + return nil }, }, { name: "--csvlite", help: "Use CSV-lite format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.WriterOptions.OutputFileFormat = "csvlite" *pargi += 1 + return nil }, }, @@ -1236,17 +1342,18 @@ var FileFormatFlagSection = FlagSection{ name: "--tsv", help: "Use TSV format for input and output data.", altNames: []string{"-t", "--t2t"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { name: "--tsvlite", help: "Use TSV-lite format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.WriterOptions.OutputFileFormat = "csvlite" options.ReaderOptions.IFS = "\t" @@ -1254,6 +1361,7 @@ var FileFormatFlagSection = FlagSection{ options.ReaderOptions.ifsWasSpecified = true options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1261,7 +1369,7 @@ var FileFormatFlagSection = FlagSection{ name: "--asv", altNames: []string{"--asvlite"}, help: "Use ASV format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.WriterOptions.OutputFileFormat = "csvlite" options.ReaderOptions.IFS = ASV_FS @@ -1275,6 +1383,7 @@ var FileFormatFlagSection = FlagSection{ options.WriterOptions.ofsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1282,7 +1391,7 @@ var FileFormatFlagSection = FlagSection{ name: "--usv", altNames: []string{"--usvlite"}, help: "Use USV format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csvlite" options.WriterOptions.OutputFileFormat = "csvlite" options.ReaderOptions.IFS = USV_FS @@ -1294,6 +1403,7 @@ var FileFormatFlagSection = FlagSection{ options.WriterOptions.ofsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1301,20 +1411,22 @@ var FileFormatFlagSection = FlagSection{ name: "--dkvp", help: "Use DKVP format for input and output data.", altNames: []string{"--d2d"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { name: "--dkvpx", help: "Use DKVPX format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvpx" options.WriterOptions.OutputFileFormat = "dkvpx" *pargi += 1 + return nil }, }, @@ -1322,12 +1434,13 @@ var FileFormatFlagSection = FlagSection{ name: "--json", help: "Use JSON format for input and output data.", altNames: []string{"-j", "--j2j"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, @@ -1335,10 +1448,11 @@ var FileFormatFlagSection = FlagSection{ name: "--jsonl", help: "Use JSON Lines format for input and output data.", altNames: []string{"--l2l"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "jsonl" *pargi += 1 + return nil }, }, @@ -1346,31 +1460,34 @@ var FileFormatFlagSection = FlagSection{ name: "--yaml", help: "Use YAML format for input and output data.", altNames: []string{"--y2y"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { name: "--dcf", help: "Use Debian control file (DCF) format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dcf" options.WriterOptions.OutputFileFormat = "dcf" *pargi += 1 + return nil }, }, { name: "--recutils", help: "Use GNU recutils (.rec) format for input and output data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "recutils" options.WriterOptions.OutputFileFormat = "recutils" *pargi += 1 + return nil }, }, @@ -1378,10 +1495,11 @@ var FileFormatFlagSection = FlagSection{ name: "--nidx", help: "Use NIDX format for input and output data.", altNames: []string{"--n2n"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "nidx" *pargi += 1 + return nil }, }, @@ -1389,19 +1507,21 @@ var FileFormatFlagSection = FlagSection{ name: "--xtab", help: "Use XTAB format for input and output data.", altNames: []string{"--x2x"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { name: "--xvright", help: "Right-justify values for XTAB format.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.RightAlignedXTABOutput = true *pargi += 1 + return nil }, }, @@ -1409,12 +1529,13 @@ var FileFormatFlagSection = FlagSection{ name: "--pprint", help: "Use PPRINT format for input and output data.", altNames: []string{"--p2p"}, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.ReaderOptions.ifsWasSpecified = true options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, }, @@ -1453,7 +1574,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ { name: "-p", help: "Keystroke-saver for `--nidx --fs space --repifs`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "nidx" options.ReaderOptions.IFS = " " @@ -1463,13 +1584,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ options.ReaderOptions.AllowRepeatIFS = true options.ReaderOptions.allowRepeatIFSWasSpecified = true *pargi += 1 + return nil }, }, { name: "-T", help: "Keystroke-saver for `--nidx --fs tab`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "nidx" options.ReaderOptions.IFS = "\t" @@ -1477,6 +1599,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ options.ReaderOptions.ifsWasSpecified = true options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1486,11 +1609,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "tsv" options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1499,11 +1623,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "dkvp" options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1512,13 +1637,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "nidx" options.WriterOptions.OFS = " " options.ReaderOptions.irsWasSpecified = true options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1527,13 +1653,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1542,13 +1669,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1557,11 +1685,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "pprint" options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1570,22 +1699,24 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--c2y", help: "Use CSV for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1594,12 +1725,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1608,11 +1740,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "xtab" options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1621,11 +1754,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "csv" options.WriterOptions.OutputFileFormat = "markdown" options.ReaderOptions.irsWasSpecified = true *pargi += 1 + return nil }, }, @@ -1635,10 +1769,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "csv" *pargi += 1 + return nil }, }, { @@ -1647,10 +1782,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { @@ -1659,13 +1795,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "nidx" options.WriterOptions.OFS = " " options.WriterOptions.ofsWasSpecified = true options.ReaderOptions.CSVLazyQuotes = true *pargi += 1 + return nil }, }, { @@ -1674,12 +1811,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { @@ -1688,12 +1826,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, { @@ -1702,10 +1841,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -1714,21 +1854,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--t2y", help: "Use TSV for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -1737,11 +1879,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -1750,10 +1893,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { @@ -1762,10 +1906,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "tsv" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -1775,10 +1920,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "csv" *pargi += 1 + return nil }, }, { @@ -1787,13 +1933,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "tsv" options.WriterOptions.OFS = "\t" options.WriterOptions.ofsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1802,12 +1949,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "nidx" options.WriterOptions.OFS = " " options.WriterOptions.ofsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1816,12 +1964,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { @@ -1830,12 +1979,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, { @@ -1844,10 +1994,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -1856,21 +2007,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--d2y", help: "Use DKVP for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -1879,11 +2032,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -1892,10 +2046,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { @@ -1904,10 +2059,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "dkvp" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -1917,11 +2073,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "csv" options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -1930,10 +2087,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { @@ -1942,10 +2100,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { @@ -1954,12 +2113,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { @@ -1968,12 +2128,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, { @@ -1982,10 +2143,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -1994,21 +2156,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--n2y", help: "Use NIDX for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -2017,11 +2181,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -2030,10 +2195,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { @@ -2042,10 +2208,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "nidx" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -2055,11 +2222,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "csv" options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2068,12 +2236,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, @@ -2083,10 +2252,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { @@ -2095,10 +2265,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { @@ -2107,10 +2278,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "nidx" *pargi += 1 + return nil }, }, { @@ -2119,10 +2291,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -2131,21 +2304,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--j2y", help: "Use JSON for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -2154,11 +2329,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -2167,10 +2343,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { @@ -2179,10 +2356,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -2192,11 +2370,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "csv" options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2205,10 +2384,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { @@ -2217,10 +2397,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { @@ -2229,10 +2410,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "json" *pargi += 1 + return nil }, }, { @@ -2241,10 +2423,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "nidx" *pargi += 1 + return nil }, }, { @@ -2253,10 +2436,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -2265,21 +2449,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--l2y", help: "Use JSON Lines for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -2288,11 +2474,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -2301,10 +2488,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { @@ -2313,10 +2501,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "json" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, @@ -2326,13 +2515,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "csv" options.ReaderOptions.ifsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2341,12 +2531,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "tsv" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2355,12 +2546,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "dkvp" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2369,12 +2561,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "nidx" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2383,7 +2576,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "json" @@ -2391,6 +2584,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ options.WriterOptions.JSONOutputMultiline = true options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2399,7 +2593,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "json" @@ -2407,6 +2601,7 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ options.WriterOptions.JSONOutputMultiline = false options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2415,12 +2610,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "xtab" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2429,25 +2625,27 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "markdown" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { name: "--p2y", help: "Use PPRINT for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "pprint" options.ReaderOptions.IFS = " " options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, @@ -2457,12 +2655,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "csv" options.ReaderOptions.ifsWasSpecified = true options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2471,11 +2670,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "tsv" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2484,11 +2684,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "dkvp" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2497,11 +2698,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "nidx" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2510,13 +2712,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2525,13 +2728,14 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2540,11 +2744,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "xtab" options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2553,22 +2758,24 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { name: "--m2y", help: "Use markdown-tabular for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "markdown" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true options.ReaderOptions.ifsWasSpecified = true *pargi += 1 + return nil }, }, @@ -2576,104 +2783,114 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ name: "--y2c", help: "Use YAML for input, CSV for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "csv" options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { name: "--y2t", help: "Use YAML for input, TSV for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { name: "--y2j", help: "Use YAML for input, JSON for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { name: "--y2l", help: "Use YAML for input, JSON Lines for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "jsonl" *pargi += 1 + return nil }, }, { name: "--y2d", help: "Use YAML for input, DKVP for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { name: "--y2n", help: "Use YAML for input, NIDX for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "nidx" *pargi += 1 + return nil }, }, { name: "--y2x", help: "Use YAML for input, XTAB for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "xtab" *pargi += 1 + return nil }, }, { name: "--y2p", help: "Use YAML for input, PPRINT for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { name: "--y2m", help: "Use YAML for input, markdown-tabular for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--y2y", help: "Use YAML for input and output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "yaml" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, @@ -2683,11 +2900,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "csv" options.WriterOptions.orsWasSpecified = true *pargi += 1 + return nil }, }, { @@ -2696,10 +2914,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "tsv" *pargi += 1 + return nil }, }, { @@ -2708,10 +2927,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "dkvp" *pargi += 1 + return nil }, }, { @@ -2720,10 +2940,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "nidx" *pargi += 1 + return nil }, }, { @@ -2732,12 +2953,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = true options.WriterOptions.JSONOutputMultiline = true *pargi += 1 + return nil }, }, { @@ -2746,12 +2968,13 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "json" options.WriterOptions.WrapJSONOutputInOuterList = false options.WriterOptions.JSONOutputMultiline = false *pargi += 1 + return nil }, }, { @@ -2760,10 +2983,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "pprint" *pargi += 1 + return nil }, }, { @@ -2772,21 +2996,23 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, { name: "--x2y", help: "Use XTAB for input, YAML for output.", suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "yaml" options.WriterOptions.WrapYAMLOutputInOuterList = true *pargi += 1 + return nil }, }, { @@ -2795,11 +3021,12 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "pprint" options.WriterOptions.BarredPprintOutput = true *pargi += 1 + return nil }, }, { @@ -2808,10 +3035,11 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{ // For format-conversion keystroke-savers, a matrix is plenty -- we don't // need to print a tedious 60-line list. suppressFlagEnumeration: true, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.InputFileFormat = "xtab" options.WriterOptions.OutputFileFormat = "markdown" *pargi += 1 + return nil }, }, }, @@ -2834,9 +3062,10 @@ var CSVTSVOnlyFlagSection = FlagSection{ name: "--no-implicit-csv-header", altNames: []string{"--no-implicit-tsv-header"}, help: "Opposite of `--implicit-csv-header`. This is the default anyway -- the main use is for the flags to `mlr join` if you have main file(s) which are headerless but you want to join in on a file which does have a CSV/TSV header. Then you could use `mlr --csv --implicit-csv-header join --no-implicit-csv-header -l your-join-in-with-header.csv ... your-headerless.csv`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.UseImplicitHeader = false *pargi += 1 + return nil }, }, @@ -2844,18 +3073,20 @@ var CSVTSVOnlyFlagSection = FlagSection{ name: "--allow-ragged-csv-input", altNames: []string{"--ragged", "--allow-ragged-tsv-input"}, help: "If a data line has fewer fields than the header line, fill remaining keys with empty string. If a data line has more fields than the header line, use integer field labels as in the implicit-header case.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.AllowRaggedCSVInput = true *pargi += 1 + return nil }, }, { name: "--no-auto-unsparsify", help: "For CSV/TSV output: if the record keys change from one row to another, emit a blank line and a new header line. This is non-compliant with RFC 4180 but it helpful for heterogeneous data.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.NoAutoUnsparsify = true *pargi += 1 + return nil }, }, @@ -2863,9 +3094,10 @@ var CSVTSVOnlyFlagSection = FlagSection{ name: "--implicit-csv-header", altNames: []string{"--headerless-csv-input", "--hi", "--implicit-tsv-header"}, help: "Use 1,2,3,... as field labels, rather than from line 1 of input files. Tip: combine with `label` to recreate missing headers.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.UseImplicitHeader = true *pargi += 1 + return nil }, }, @@ -2873,46 +3105,51 @@ var CSVTSVOnlyFlagSection = FlagSection{ name: "--headerless-csv-output", altNames: []string{"--ho", "--headerless-tsv-output"}, help: "Print only CSV/TSV data lines; do not print CSV/TSV header lines.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.HeaderlessOutput = true *pargi += 1 + return nil }, }, { name: "-N", help: "Keystroke-saver for `--implicit-csv-header --headerless-csv-output`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.UseImplicitHeader = true options.WriterOptions.HeaderlessOutput = true *pargi += 1 + return nil }, }, { name: "--lazy-quotes", help: "Accepts quotes appearing in unquoted fields, and non-doubled quotes appearing in quoted fields.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.CSVLazyQuotes = true *pargi += 1 + return nil }, }, { name: "--csv-trim-leading-space", help: `Trims leading spaces in CSV data. Use this for data like '"foo", "bar' which is non-RFC-4180 compliant, but common.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.CSVTrimLeadingSpace = true *pargi += 1 + return nil }, }, { name: "--quote-all", help: "Force double-quoting of CSV fields.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.CSVQuoteAll = true *pargi += 1 + return nil }, }, }, @@ -2963,11 +3200,14 @@ var CompressedDataFlagSection = FlagSection{ name: "--prepipe", arg: "{decompression command}", help: "You can, of course, already do without this for single input files, e.g. `gunzip < myfile.csv.gz | mlr ...`. Allowed at the command line, but not in `.mlrrc` to avoid unexpected code execution.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.Prepipe = args[*pargi+1] options.ReaderOptions.PrepipeIsRaw = false *pargi += 2 + return nil }, }, @@ -2975,87 +3215,98 @@ var CompressedDataFlagSection = FlagSection{ name: "--prepipex", arg: "{decompression command}", help: "Like `--prepipe` with one exception: doesn't insert `<` between command and filename at runtime. Useful for some commands like `unzip -qc` which don't read standard input. Allowed at the command line, but not in `.mlrrc` to avoid unexpected code execution.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.Prepipe = args[*pargi+1] options.ReaderOptions.PrepipeIsRaw = true *pargi += 2 + return nil }, }, { name: "--prepipe-gunzip", help: "Same as `--prepipe gunzip`, except this is allowed in `.mlrrc`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.Prepipe = "gunzip" options.ReaderOptions.PrepipeIsRaw = false *pargi += 1 + return nil }, }, { name: "--prepipe-zcat", help: "Same as `--prepipe zcat`, except this is allowed in `.mlrrc`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.Prepipe = "zcat" options.ReaderOptions.PrepipeIsRaw = false *pargi += 1 + return nil }, }, { name: "--prepipe-zstdcat", help: "Same as `--prepipe zstdcat`, except this is allowed in `.mlrrc`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.Prepipe = "zstdcat" options.ReaderOptions.PrepipeIsRaw = false *pargi += 1 + return nil }, }, { name: "--prepipe-bz2", help: "Same as `--prepipe bz2`, except this is allowed in `.mlrrc`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.Prepipe = "bz2" options.ReaderOptions.PrepipeIsRaw = false *pargi += 1 + return nil }, }, { name: "--gzin", help: "Uncompress gzip within the Miller process. Done by default if file ends in `.gz`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FileInputEncoding = lib.FileInputEncodingGzip *pargi += 1 + return nil }, }, { name: "--zin", help: "Uncompress zlib within the Miller process. Done by default if file ends in `.z`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FileInputEncoding = lib.FileInputEncodingZlib *pargi += 1 + return nil }, }, { name: "--bz2in", help: "Uncompress bzip2 within the Miller process. Done by default if file ends in `.bz2`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FileInputEncoding = lib.FileInputEncodingBzip2 *pargi += 1 + return nil }, }, { name: "--zstdin", help: "Uncompress zstd within the Miller process. Done by default if file ends in `.zstd`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.FileInputEncoding = lib.FileInputEncodingZstd *pargi += 1 + return nil }, }, }, @@ -3093,10 +3344,11 @@ var CommentsInDataFlagSection = FlagSection{ { name: "--skip-comments", help: "Ignore commented lines (prefixed by `" + DEFAULT_COMMENT_STRING + "`) within the input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.CommentString = DEFAULT_COMMENT_STRING options.ReaderOptions.CommentHandling = SkipComments *pargi += 1 + return nil }, }, @@ -3104,21 +3356,25 @@ var CommentsInDataFlagSection = FlagSection{ name: "--skip-comments-with", arg: "{string}", help: "Ignore commented lines within input, with specified prefix. For CSV input format, the prefix must be a single character.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.CommentString = args[*pargi+1] options.ReaderOptions.CommentHandling = SkipComments *pargi += 2 + return nil }, }, { name: "--pass-comments", help: "Immediately print commented lines (prefixed by `" + DEFAULT_COMMENT_STRING + "`) within the input.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.CommentString = DEFAULT_COMMENT_STRING options.ReaderOptions.CommentHandling = PassComments *pargi += 1 + return nil }, }, @@ -3126,11 +3382,14 @@ var CommentsInDataFlagSection = FlagSection{ name: "--pass-comments-with", arg: "{string}", help: "Immediately print commented lines within input, with specified prefix. For CSV input format, the prefix must be a single character.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.ReaderOptions.CommentString = args[*pargi+1] options.ReaderOptions.CommentHandling = PassComments *pargi += 2 + return nil }, }, }, @@ -3209,18 +3468,18 @@ var OutputColorizationFlagSection = FlagSection{ { name: "--list-color-codes", help: "Show the available color codes in the range 0..255, such as 170 for example.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { colorizer.ListColorCodes() - os.Exit(0) + return lib.NewExitZeroRequest() }, }, { name: "--list-color-names", help: "Show the names for the available color codes, such as `orchid` for example.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { colorizer.ListColorNames() - os.Exit(0) + return lib.NewExitZeroRequest() }, }, @@ -3228,9 +3487,10 @@ var OutputColorizationFlagSection = FlagSection{ name: "--no-color", altNames: []string{"-M"}, help: "Instructs Miller to not colorize any output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { colorizer.SetColorization(colorizer.ColorizeOutputNever) *pargi += 1 + return nil }, }, @@ -3238,89 +3498,95 @@ var OutputColorizationFlagSection = FlagSection{ name: "--always-color", altNames: []string{"-C"}, help: "Instructs Miller to colorize output even when it normally would not. Useful for piping output to `less -r`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { colorizer.SetColorization(colorizer.ColorizeOutputAlways) *pargi += 1 + return nil }, }, { name: "--key-color", help: "Specify the color (see `--list-color-codes` and `--list-color-names`) for record keys.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } ok := colorizer.SetKeyColor(args[*pargi+1]) if !ok { - fmt.Fprintf(os.Stderr, - "mlr: --key-color argument unrecognized; got \"%s\".\n", + return FlagErrorf("mlr: --key-color argument unrecognized; got \"%s\".", args[*pargi+1]) - os.Exit(1) } *pargi += 2 + return nil }, }, { name: "--value-color", help: "Specify the color (see `--list-color-codes` and `--list-color-names`) for record values.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } ok := colorizer.SetValueColor(args[*pargi+1]) if !ok { - fmt.Fprintf(os.Stderr, - "mlr: --value-color argument unrecognized; got \"%s\".\n", + return FlagErrorf("mlr: --value-color argument unrecognized; got \"%s\".", args[*pargi+1]) - os.Exit(1) } *pargi += 2 + return nil }, }, { name: "--pass-color", help: "Specify the color (see `--list-color-codes` and `--list-color-names`) for passing cases in `mlr regtest`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } ok := colorizer.SetPassColor(args[*pargi+1]) if !ok { - fmt.Fprintf(os.Stderr, - "mlr: --pass-color argument unrecognized; got \"%s\".\n", + return FlagErrorf("mlr: --pass-color argument unrecognized; got \"%s\".", args[*pargi+1]) - os.Exit(1) } *pargi += 2 + return nil }, }, { name: "--fail-color", help: "Specify the color (see `--list-color-codes` and `--list-color-names`) for failing cases in `mlr regtest`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } ok := colorizer.SetFailColor(args[*pargi+1]) if !ok { - fmt.Fprintf(os.Stderr, - "mlr: --fail-color argument unrecognized; got \"%s\".\n", + return FlagErrorf("mlr: --fail-color argument unrecognized; got \"%s\".", args[*pargi+1]) - os.Exit(1) } *pargi += 2 + return nil }, }, { name: "--help-color", help: "Specify the color (see `--list-color-codes` and `--list-color-names`) for highlights in `mlr help` output.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } ok := colorizer.SetHelpColor(args[*pargi+1]) if !ok { - fmt.Fprintf(os.Stderr, - "mlr: --help-color argument unrecognized; got \"%s\".\n", + return FlagErrorf("mlr: --help-color argument unrecognized; got \"%s\".", args[*pargi+1]) - os.Exit(1) } *pargi += 2 + return nil }, }, }, @@ -3346,28 +3612,33 @@ var FlattenUnflattenFlagSection = FlagSection{ altNames: []string{"--jflatsep"}, arg: "{string}", help: "Separator for flattening multi-level JSON keys, e.g. `{\"a\":{\"b\":3}}` becomes `a:b => 3` for non-JSON formats. Defaults to `" + DEFAULT_JSON_FLATTEN_SEPARATOR + "`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.FLATSEP = SeparatorFromArg(args[*pargi+1]) *pargi += 2 + return nil }, }, { name: "--no-auto-flatten", help: "When output is not JSON or YAML, suppress the default auto-flatten behavior. Default: if `$y = [7,8,9]` then this flattens to `y.1=7,y.2=8,y.3=9`, and similarly for maps. With `--no-auto-flatten`, instead we get `$y=[1, 2, 3]`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.AutoFlatten = false *pargi += 1 + return nil }, }, { name: "--no-auto-unflatten", help: "When input is not JSON or YAML and output is JSON or YAML, suppress the default auto-unflatten behavior. Default: if the input has `y.1=7,y.2=8,y.3=9` then this unflattens to `$y=[7,8,9]`. With `--no-auto-flatten`, instead we get `${y.1}=7,${y.2}=8,${y.3}=9`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.AutoUnflatten = false *pargi += 1 + return nil }, }, }, @@ -3390,9 +3661,10 @@ var ProfilingFlagSection = FlagSection{ arg: "{CPU-profile file name}", help: `Create a CPU-profile file for performance analysis. Instructions will be printed to stderr. This flag must be the very first thing after 'mlr' on the command line.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { // Already handled in main(). Nothing to do here except to accept this as valid syntax. *pargi += 2 + return nil }, }, @@ -3400,18 +3672,20 @@ This flag must be the very first thing after 'mlr' on the command line.`, name: "--traceprofile", help: `Create a trace-profile file for performance analysis. Instructions will be printed to stderr. This flag must be the very first thing after 'mlr' on the command line.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { // Already handled in main(). Nothing to do here except to accept this as valid syntax. *pargi += 1 + return nil }, }, { name: "--time", help: "Print elapsed execution time in seconds to stderr at the end of the execution of the program.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.PrintElapsedTime = true *pargi += 1 + return nil }, }, }, @@ -3433,47 +3707,52 @@ var MiscFlagSection = FlagSection{ { name: "--errors-json", help: "Emit parse errors as a JSON object to stderr instead of a plain text message. Intended for AI agents and scripts that branch on error kind rather than regex-matching prose. Equivalent to setting the `MLR_ERRORS_JSON` environment variable to a truthy value.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { // The actual effect is handled by pre-scan in pkg/entrypoint. // Registration here ensures the flag is recognized (not an // error) during pass-one flag parsing, and appears in --help. *pargi += 1 + return nil }, }, { name: "--no-shell", help: "Disable Miller's ability to run external commands: the DSL `system` and `exec` functions, piped redirects such as `tee | \"command\"`, and `--prepipe`/`--prepipex` all fail cleanly instead of executing. Equivalent to setting the `MLR_NO_SHELL` environment variable to a truthy value. Intended for running agent-constructed command lines (e.g. via `mlr mcp`) without also granting arbitrary command execution. Once disabled, shell-outs cannot be re-enabled for the rest of the process.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { lib.DisableShellOut() *pargi += 1 + return nil }, }, { name: "-x", help: "If any record has an error value in it, report it and stop the process. The default is to print the field value as `(error)` and continue.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.FailOnDataError = true *pargi += 1 + return nil }, }, { name: "-n", help: "Process no input files, nor standard input either. Useful for `mlr put` with `begin`/`end` statements only. (Same as `--from /dev/null`.) Also useful in `mlr -n put -v '...'` for analyzing abstract syntax trees (if that's your thing).", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.NoInput = true *pargi += 1 + return nil }, }, { name: "-I", help: "Process files in-place. For each file name on the command line, output is written to a temp file in the same directory, which is then renamed over the original. Each file is processed in isolation: if the output format is CSV, CSV headers will be present in each output file, statistics are only over each file's own records; and so on.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.DoInPlace = true *pargi += 1 + return nil }, }, @@ -3481,10 +3760,13 @@ var MiscFlagSection = FlagSection{ name: "--from", arg: "{filename}", help: "Use this to specify an input file before the verb(s), rather than after. May be used more than once. Example: `mlr --from a.dat --from b.dat cat` is the same as `mlr cat a.dat b.dat`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.FileNames = append(options.FileNames, args[*pargi+1]) *pargi += 2 + return nil }, }, @@ -3492,20 +3774,22 @@ var MiscFlagSection = FlagSection{ name: "--mfrom", arg: "{filenames}", help: "Use this to specify one of more input files before the verb(s), rather than after. May be used more than once. The list of filename must end with `--`. This is useful for example since `--from *.csv` doesn't do what you might hope but `--mfrom *.csv --` does.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } *pargi += 1 for *pargi < argc && args[*pargi] != "--" { options.FileNames = append(options.FileNames, args[*pargi]) *pargi += 1 } if *pargi >= argc { - fmt.Fprintf(os.Stderr, "mlr: \"--mfrom\" must be terminated by \"--\".\n") - os.Exit(1) + return FlagErrorf("mlr: \"--mfrom\" must be terminated by \"--\".") } if args[*pargi] == "--" { *pargi += 1 } + return nil }, }, @@ -3513,15 +3797,15 @@ var MiscFlagSection = FlagSection{ name: "--files", arg: "{filename}", help: "Use this to specify a file which itself contains, one per line, names of input files. May be used more than once.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } fileName := args[*pargi+1] handle, err := os.Open(fileName) if err != nil { - /// XXXX return false - fmt.Fprintf(os.Stderr, "mlr: %v\n", err) - os.Exit(1) + return err } defer func() { _ = handle.Close() }() @@ -3537,8 +3821,7 @@ var MiscFlagSection = FlagSection{ lineno++ if err != nil { - fmt.Fprintf(os.Stderr, "mlr: %v\n", err) - os.Exit(1) + return err } // This is how to do a chomp: @@ -3549,6 +3832,7 @@ var MiscFlagSection = FlagSection{ } *pargi += 2 + return nil }, }, @@ -3556,10 +3840,13 @@ var MiscFlagSection = FlagSection{ name: "--ofmt", arg: "{format}", help: "E.g. `%.18f`, `%.0f`, `%9.6e`. Please use sprintf-style codes (https://pkg.go.dev/fmt) for floating-point numbers. If not specified, default formatting is used. See also the `fmtnum` function and the `format-values` verb.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.FPOFMT = args[*pargi+1] *pargi += 2 + return nil }, }, @@ -3567,10 +3854,13 @@ var MiscFlagSection = FlagSection{ name: "--ofmte", arg: "{n}", help: "Use --ofmte 6 as shorthand for --ofmt %.6e, etc.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.FPOFMT = "%." + args[*pargi+1] + "e" *pargi += 2 + return nil }, }, @@ -3578,10 +3868,13 @@ var MiscFlagSection = FlagSection{ name: "--ofmtf", arg: "{n}", help: "Use --ofmtf 6 as shorthand for --ofmt %.6f, etc.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.FPOFMT = "%." + args[*pargi+1] + "f" *pargi += 2 + return nil }, }, @@ -3589,10 +3882,13 @@ var MiscFlagSection = FlagSection{ name: "--ofmtg", arg: "{n}", help: "Use --ofmtg 6 as shorthand for --ofmt %.6g, etc.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.WriterOptions.FPOFMT = "%." + args[*pargi+1] + "g" *pargi += 2 + return nil }, }, @@ -3600,10 +3896,13 @@ var MiscFlagSection = FlagSection{ name: "--load", arg: "{filename}", help: "Load DSL script file for all put/filter operations on the command line. If the name following `--load` is a directory, load all `*.mlr` files in that directory. This is just like `put -f` and `filter -f` except it's up-front on the command line, so you can do something like `alias mlr='mlr --load ~/myscripts'` if you like.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } options.DSLPreloadFileNames = append(options.DSLPreloadFileNames, args[*pargi+1]) *pargi += 2 + return nil }, }, @@ -3611,8 +3910,10 @@ var MiscFlagSection = FlagSection{ name: "--mload", arg: "{filenames}", help: "Like `--load` but works with more than one filename, e.g. `--mload *.mlr --`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } *pargi += 1 for *pargi < argc && args[*pargi] != "--" { options.DSLPreloadFileNames = append(options.DSLPreloadFileNames, args[*pargi]) @@ -3621,6 +3922,7 @@ var MiscFlagSection = FlagSection{ if args[*pargi] == "--" { *pargi += 1 } + return nil }, }, @@ -3628,10 +3930,13 @@ var MiscFlagSection = FlagSection{ name: "--tz", arg: "{timezone}", help: "Specify timezone, overriding `$TZ` environment variable (if any).", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } _ = os.Setenv("TZ", args[*pargi+1]) *pargi += 2 + return nil }, }, @@ -3639,17 +3944,19 @@ var MiscFlagSection = FlagSection{ name: "--nr-progress-mod", arg: "{m}", help: "With m a positive integer: print filename and record count to os.Stderr every m input records.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } nrProgressMod, ok := lib.TryIntFromString(args[*pargi+1]) if !ok || nrProgressMod <= 0 { - fmt.Fprintf(os.Stderr, - "%s: --nr-progress-mod argument must be a positive integer; got \"%s\".\n", + return FlagErrorf( + "%s: --nr-progress-mod argument must be a positive integer; got \"%s\".", "mlr", args[*pargi+1]) - os.Exit(1) } options.NRProgressMod = nrProgressMod *pargi += 2 + return nil }, }, @@ -3658,20 +3965,21 @@ var MiscFlagSection = FlagSection{ arg: "{n}", help: "with `n` of the form `12345678` or `0xcafefeed`. For `put`/`filter` `urand`, `urandint`, and `urand32`.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } randSeed, ok := lib.TryIntFromString(args[*pargi+1]) if ok { options.RandSeed = randSeed options.HaveRandSeed = true } else { - fmt.Fprintf(os.Stderr, - "mlr: --seed argument must be a decimal or hexadecimal integer; got \"%s\".\n", + return FlagErrorf( + "mlr: --seed argument must be a decimal or hexadecimal integer; got \"%s\".\nPlease run \"mlr --help\" for detailed usage information.", args[*pargi+1]) - fmt.Fprintf(os.Stderr, "Please run \"mlr --help\" for detailed usage information.\n") - os.Exit(1) } *pargi += 2 + return nil }, }, @@ -3681,9 +3989,10 @@ var MiscFlagSection = FlagSection{ another also named ` + "`x`" + `, the second will be renamed ` + "`x_2`" + `, and so on. With this flag provided, the second ` + "`x`" + `'s value will replace the first ` + "`x`" + `'s value when the record is read. This flag has no effect on JSON input records, where duplicate keys always result in the last one's value being retained.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.ReaderOptions.DedupeFieldNames = false *pargi += 1 + return nil }, }, @@ -3693,17 +4002,19 @@ on JSON input records, where duplicate keys always result in the last one's valu help: "This is an internal parameter for maximum number of records in a batch size. Normally this does not\n" + "need to be modified, except when input is from `tail -f`. See also\n" + "https://miller.readthedocs.io/en/latest/reference-main-flag-list/.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } recordsPerBatch, ok := lib.TryIntFromString(args[*pargi+1]) if !ok || recordsPerBatch <= 0 { - fmt.Fprintf(os.Stderr, - "%s: --records-per-batch argument must be a positive integer; got \"%s\".\n", + return FlagErrorf( + "%s: --records-per-batch argument must be a positive integer; got \"%s\".", "mlr", args[*pargi+1]) - os.Exit(1) } options.ReaderOptions.RecordsPerBatch = recordsPerBatch *pargi += 2 + return nil }, }, @@ -3714,18 +4025,20 @@ It controls the mechanism by which Miller accesses fields within records. In general --no-hash-records is faster, and is the default. For specific use-cases involving data having many fields, and many of them being processed during a given processing run, --hash-records might offer a slight performance benefit.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { mlrval.HashRecords(true) *pargi += 1 + return nil }, }, { name: "--no-hash-records", help: `See --hash-records.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { mlrval.HashRecords(false) *pargi += 1 + return nil }, }, @@ -3733,9 +4046,10 @@ data having many fields, and many of them being processed during a given process name: "--infer-none", altNames: []string{"-S"}, help: `Don't treat values like 123 or 456.7 in data files as int/float; leave them as strings.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { mlrval.SetInferrerStringOnly() *pargi += 1 + return nil }, }, @@ -3743,9 +4057,10 @@ data having many fields, and many of them being processed during a given process name: "--infer-int-as-float", altNames: []string{"-A"}, help: `Cast all integers in data files to floats.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { mlrval.SetInferrerIntAsFloat() *pargi += 1 + return nil }, }, @@ -3754,9 +4069,10 @@ data having many fields, and many of them being processed during a given process altNames: []string{"-O"}, help: `Treat numbers like 0123 in data files as numeric; default is string. Note that 00--07 etc scan as int; 08-09 scan as float.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { mlrval.SetInferrerOctalAsInt() *pargi += 1 + return nil }, }, @@ -3767,10 +4083,11 @@ The default is flush output after every record if the output is to the terminal, the output is to a file or a pipe. The default is a significant performance optimization for large files. Use this flag to force frequent updates even when output is to a pipe or file, at a performance cost.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.FlushOnEveryRecord = true options.WriterOptions.flushOnEveryRecordWasSpecified = true *pargi += 1 + return nil }, }, @@ -3782,10 +4099,11 @@ the output is to a file or a pipe. The default is a significant performance opti files. Use this flag to allow less-frequent updates when output is to the terminal. This is unlikely to be a noticeable performance improvement, since direct-to-screen output for large files has its own overhead.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { options.WriterOptions.FlushOnEveryRecord = false options.WriterOptions.flushOnEveryRecordWasSpecified = true *pargi += 1 + return nil }, }, @@ -3794,9 +4112,10 @@ has its own overhead.`, arg: "{file name}", help: `Take command-line flags from file name. For more information please see ` + lib.DOC_URL + `/en/latest/scripting/.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { // Already handled in main(). Nothing to do here except to accept this as valid syntax. *pargi += 2 + return nil }, }, @@ -3805,17 +4124,19 @@ has its own overhead.`, arg: "{file name}", help: `Take command-line flags from file name, like -s, but with no comment-stripping. For more information please see ` + lib.DOC_URL + `/en/latest/scripting/.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { // Already handled in main(). Nothing to do here except to accept this as valid syntax. *pargi += 2 + return nil }, }, { name: "--norc", help: "Do not load a .mlrrc file.", - parser: func(args []string, argc int, pargi *int, options *TOptions) { + parser: func(args []string, argc int, pargi *int, options *TOptions) error { *pargi += 1 + return nil }, }, @@ -3826,14 +4147,17 @@ has its own overhead.`, help: `Apply the settings from the [name] section of your .mlrrc file, after any global (pre-section) settings. It's an error if no such section exists in any .mlrrc file processed. For more information please see ` + lib.DOC_URL + `/en/latest/customization/.`, - parser: func(args []string, argc int, pargi *int, options *TOptions) { - CheckArgCount(args, *pargi, argc, 2) + parser: func(args []string, argc int, pargi *int, options *TOptions) error { + if err := CheckArgCount(args, *pargi, argc, 2); err != nil { + return err + } // The actual profile selection is handled in pkg/climain, // before the .mlrrc file is loaded, which is in turn before // main-flag sequences are parsed into the options struct. // Registration here ensures the flag is recognized (not an // error) during flag parsing, and appears in --help. *pargi += 2 + return nil }, }, }, diff --git a/pkg/climain/mlrcli_mlrrc.go b/pkg/climain/mlrcli_mlrrc.go index de09bcf61..c7eacd213 100644 --- a/pkg/climain/mlrcli_mlrrc.go +++ b/pkg/climain/mlrcli_mlrrc.go @@ -163,7 +163,11 @@ func tryLoadMlrrc( continue } - if !handleMlrrcLine(options, stripped) { + handled, err := handleMlrrcLine(options, stripped) + if err != nil { + return true, err + } + if !handled { return true, fmt.Errorf( "parse error at file \"%s\" line %d: %s", path, lineno, line, ) @@ -198,11 +202,13 @@ func parseMlrrcSectionHeader(line string) (string, bool) { } // handleMlrrcLine is a helper function for tryLoadMlrrc, handling a single -// (comment-stripped, whitespace-trimmed, non-empty) settings line. +// (comment-stripped, whitespace-trimmed, non-empty) settings line. The boolean +// return says whether the line was recognized at all; a non-nil error is a +// flag-argument error to be propagated as-is. func handleMlrrcLine( options *cli.TOptions, line string, -) bool { +) (bool, error) { // Prepend initial "--" if it's not already there if !strings.HasPrefix(line, "-") { line = "--" + line @@ -213,21 +219,18 @@ func handleMlrrcLine( argi := 0 argc := len(args) - if args[0] == "--prepipe" || args[0] == "--prepipex" { + switch args[0] { + case "--prepipe", "--prepipex": // Don't allow code execution via .mlrrc - return false - } else if args[0] == "--load" || args[0] == "--mload" { + return false, nil + case "--load", "--mload": // Don't allow code execution via .mlrrc - return false - } else if args[0] == "--profile" || args[0] == "-P" { + return false, nil + case "--profile", "-P": // Profiles are selected on the mlr command line, not from within a // .mlrrc file - return false - } else if cli.FLAG_TABLE.Parse(args, argc, &argi, options) { - // handled - } else { - return false + return false, nil } - return true + return cli.FLAG_TABLE.Parse(args, argc, &argi, options) } diff --git a/pkg/climain/mlrcli_parse.go b/pkg/climain/mlrcli_parse.go index cb4f8537b..388686143 100644 --- a/pkg/climain/mlrcli_parse.go +++ b/pkg/climain/mlrcli_parse.go @@ -173,7 +173,11 @@ func parseCommandLinePassOne( argi += 1 flagSequences = append(flagSequences, args[oargi:argi]) - } else if cli.FLAG_TABLE.Parse(args, argc, &argi, options) { + } else if handled, flagErr := cli.FLAG_TABLE.Parse(args, argc, &argi, options); flagErr != nil { + parseErr = flagErr + return + + } else if handled { flagSequences = append(flagSequences, args[oargi:argi]) } else if args[argi] == "--" { @@ -357,7 +361,10 @@ func parseCommandLinePassTwo( lib.InternalCodingErrorIf(argc == 0) // Parse the main-flag into the options struct. - rc := cli.FLAG_TABLE.Parse(args, argc, &argi, options) + rc, flagErr := cli.FLAG_TABLE.Parse(args, argc, &argi, options) + if flagErr != nil { + return nil, nil, flagErr + } // Should have been parsed OK in pass one. lib.InternalCodingErrorIf(!rc) diff --git a/pkg/terminals/repl/entry.go b/pkg/terminals/repl/entry.go index 602bb4c02..2fd3edbf8 100644 --- a/pkg/terminals/repl/entry.go +++ b/pkg/terminals/repl/entry.go @@ -20,12 +20,14 @@ package repl import ( + "errors" "fmt" "os" "path" "strings" "github.com/johnkerl/miller/v6/pkg/cli" + "github.com/johnkerl/miller/v6/pkg/lib" ) func replUsage(verbName string, o *os.File, exitCode int) { @@ -140,7 +142,15 @@ func ReplMain(args []string) int { argi += 1 } - } else if cli.FLAG_TABLE.Parse(args, argc, &argi, options) { + } else if handled, flagErr := cli.FLAG_TABLE.Parse(args, argc, &argi, options); flagErr != nil { + var exitRequest *lib.ExitRequest + if errors.As(flagErr, &exitRequest) { + return exitRequest.Code + } + fmt.Fprintf(os.Stderr, "%v\n", flagErr) + return 1 + + } else if handled { } else { replUsage(replName, os.Stderr, 1) diff --git a/pkg/terminals/script/entry.go b/pkg/terminals/script/entry.go index b9d52a67d..d25176ca6 100644 --- a/pkg/terminals/script/entry.go +++ b/pkg/terminals/script/entry.go @@ -10,6 +10,7 @@ package script import ( + "errors" "fmt" "os" "path" @@ -112,7 +113,14 @@ func ScriptMain(args []string) int { if argi < argc && args[argi] == "--" { argi++ } - } else if cli.FLAG_TABLE.Parse(args, argc, &argi, options) { + } else if handled, flagErr := cli.FLAG_TABLE.Parse(args, argc, &argi, options); flagErr != nil { + var exitRequest *lib.ExitRequest + if errors.As(flagErr, &exitRequest) { + return exitRequest.Code + } + fmt.Fprintf(os.Stderr, "%v\n", flagErr) + return 1 + } else if handled { } else { scriptUsage(scriptName, os.Stderr, 1) } diff --git a/pkg/transformers/join.go b/pkg/transformers/join.go index 0fba89c3c..5c3540203 100644 --- a/pkg/transformers/join.go +++ b/pkg/transformers/join.go @@ -233,7 +233,11 @@ func transformerJoinParseCLI( // loop (so individual if-statements don't need to). However, // cli.Parse expects it unadvanced. largi := argi - 1 - if cli.FLAG_TABLE.Parse(args, argc, &largi, &opts.joinFlagOptions) { + handled, err := cli.FLAG_TABLE.Parse(args, argc, &largi, &opts.joinFlagOptions) + if err != nil { + return nil, err + } + if handled { // This lets mlr main and mlr join have different input formats. // Nothing else to handle here. argi = largi diff --git a/pkg/transformers/put_or_filter.go b/pkg/transformers/put_or_filter.go index 14f095ebb..e95993586 100644 --- a/pkg/transformers/put_or_filter.go +++ b/pkg/transformers/put_or_filter.go @@ -331,7 +331,11 @@ func transformerPutOrFilterParseCLI( // loop (so individual if-statements don't need to). However, // ParseWriterOptions expects it unadvanced. largi := argi - 1 - if cli.FLAG_TABLE.Parse(args, argc, &largi, options) { + handled, err := cli.FLAG_TABLE.Parse(args, argc, &largi, options) + if err != nil { + return nil, err + } + if handled { // This lets mlr main and mlr put have different output formats. // Nothing else to handle here. argi = largi diff --git a/pkg/transformers/split.go b/pkg/transformers/split.go index 00b257856..056885b6d 100644 --- a/pkg/transformers/split.go +++ b/pkg/transformers/split.go @@ -185,7 +185,11 @@ func transformerSplitParseCLI( // loop (so individual if-statements don't need to). However, // ParseWriterOptions expects it unadvanced. largi := argi - 1 - if cli.FLAG_TABLE.Parse(args, argc, &largi, localOptions) { + handled, err := cli.FLAG_TABLE.Parse(args, argc, &largi, localOptions) + if err != nil { + return nil, err + } + if handled { // This lets mlr main and mlr split have different output formats. // Nothing else to handle here. argi = largi diff --git a/pkg/transformers/tee.go b/pkg/transformers/tee.go index 0ebd9681f..d689d9254 100644 --- a/pkg/transformers/tee.go +++ b/pkg/transformers/tee.go @@ -90,7 +90,11 @@ func transformerTeeParseCLI( // loop (so individual if-statements don't need to). However, // ParseWriterOptions expects it unadvanced. largi := argi - 1 - if cli.FLAG_TABLE.Parse(args, argc, &largi, localOptions) { + handled, err := cli.FLAG_TABLE.Parse(args, argc, &largi, localOptions) + if err != nil { + return nil, err + } + if handled { // This lets mlr main and mlr tee have different output formats. // Nothing else to handle here. argi = largi