README.md
1clipp - command line interfaces for modern C++
2===========================================================
3
4[![Linux build status](https://travis-ci.org/muellan/clipp.svg?branch=master)](https://travis-ci.org/muellan/clipp) [![MSVC build status](https://ci.appveyor.com/api/projects/status/ci29ngpfks980i7g?svg=true)](https://ci.appveyor.com/project/muellan/clipp)
5
6Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a **single header file**.
7
8- options, options+value(s), positional values, positional commands, nested alternatives, decision trees, joinable flags, custom value filters, ...
9- documentation generation (usage lines, man pages); error handling
10- lots of examples; large set of tests
11
12- ### [Quick Reference Table](#quick-reference)
13- ### [Overview (short examples)](#overview)
14- ### [Detailed Examples](#examples)
15- #### [Why yet another library for parsing command line arguments?](#motivation) / [Design goals](#design-goals)
16- #### [Requirements / Compilers](#requirements)
17
18
19
20## Quick Intro
21
22### Simple Use Case — Simple Setup!
23Consider this command line interface:
24```man
25SYNOPSIS
26 convert <input file> [-r] [-o <output format>] [-utf16]
27
28OPTIONS
29 -r, --recursive convert files recursively
30 -utf16 use UTF-16 encoding
31```
32Here is the code that defines the positional value ```input file``` and the three options ```-r```, ```-o``` and ```-utf16```. If parsing fails, the above default man page-like snippet will be printed to stdout.
33```cpp
34#include <iostream>
35#include "clipp.h"
36using namespace clipp; using std::cout; using std::string;
37
38int main(int argc, char* argv[]) {
39 bool rec = false, utf16 = false;
40 string infile = "", fmt = "csv";
41
42 auto cli = (
43 value("input file", infile),
44 option("-r", "--recursive").set(rec).doc("convert files recursively"),
45 option("-o") & value("output format", fmt),
46 option("-utf16").set(utf16).doc("use UTF-16 encoding")
47 );
48
49 if(!parse(argc, argv, cli)) cout << make_man_page(cli, argv[0]);
50 // ...
51}
52```
53
54
55
56### A More Complex Example:
57```man
58SYNOPSIS
59 finder make <wordfile> -dict <dictionary> [--progress] [-v]
60 finder find <infile>... -dict <dictionary> [-o <outfile>] [-split|-nosplit] [-v]
61 finder help [-v]
62
63OPTIONS
64 --progress, -p show progress
65 -o, --output <outfile> write to file instead of stdout
66 -split, -nosplit (do not) split output
67 -v, --version show version
68```
69This CLI has three alternative commands (```make```, ```find```, ```help```), some positional value-arguments (```<wordfile>```, ```<infile>```) of which one is repeatable, a required flag with value-argument (```-dict <dictionary>```), an option with value-argument (```-o <outfile>```), one option with two alternatives (```-split```, ```-nosplit```) and two conventional options (```-v```, ```--progress```).
70
71Here is the code that defines the interface, generates the man page snippet above *and* handles the parsing result:
72```cpp
73using namespace clipp; using std::cout; using std::string;
74
75//variables storing the parsing result; initialized with their default values
76enum class mode {make, find, help};
77mode selected = mode::help;
78std::vector<string> input;
79string dict, out;
80bool split = false, progr = false;
81
82auto dictionary = required("-dict") & value("dictionary", dict);
83
84auto makeMode = (
85 command("make").set(selected,mode::make),
86 values("wordfile", input),
87 dictionary,
88 option("--progress", "-p").set(progr) % "show progress" );
89
90auto findMode = (
91 command("find").set(selected,mode::find),
92 values("infile", input),
93 dictionary,
94 (option("-o", "--output") & value("outfile", out)) % "write to file instead of stdout",
95 ( option("-split" ).set(split,true) |
96 option("-nosplit").set(split,false) ) % "(do not) split output" );
97
98auto cli = (
99 (makeMode | findMode | command("help").set(selected,mode::help) ),
100 option("-v", "--version").call([]{cout << "version 1.0\n\n";}).doc("show version") );
101
102if(parse(argc, argv, cli)) {
103 switch(selected) {
104 case mode::make: /* ... */ break;
105 case mode::find: /* ... */ break;
106 case mode::help: cout << make_man_page(cli, "finder"); break;
107 }
108} else {
109 cout << usage_lines(cli, "finder") << '\n';
110}
111```
112
113
114
115
116## Quick Reference
117
118Below are a few examples that should give you an idea for how clipp works.
119Consider this basic setup with a few variables that we want to set using
120command line arguments:
121```cpp
122int main(int argc, char* argv[]) {
123 using namespace clipp;
124
125 // define some variables
126 bool a = false, b = false;
127 int n = 0, k = 0;
128 double x = 0.0, y = 0.0;
129 std::vector<int> ids;
130
131 auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );
132
133 parse(argc, argv, cli); //excludes argv[0]
134
135 std::cout << usage_lines(cli, "exe") << '\n';
136}
137```
138
139| Interface (`usage_lines`) | Code (content of `cli` parentheses )
140| -------------------------- | ------------------------------------
141| ` exe [-a] ` | ` option("-a", "--all").set(a)`
142| ` exe [--all] ` | ` option("--all", "-a", "--ALL").set(a)`
143| ` exe [-a] [-b] ` | ` option("-a").set(a), option("-b").set(b)`
144| ` exe -a ` | ` required("-a").set(a)`
145| ` exe [-a] -b ` | ` option("-a").set(a), required("-b").set(b)`
146| ` exe [-n <times>] ` | ` option("-n", "--iter") & value("times", n) `
147| ` exe [-n [<times>]] ` | ` option("-n", "--iter") & opt_value("times", n) `
148| ` exe -n <times> ` | ` required("-n", "--iter") & value("times", n) `
149| ` exe -n [<times>] ` | ` required("-n", "--iter") & opt_value("times", n) `
150| ` exe [-c <x> <y>]` | ` option("-c") & value("x", x) & value("y", y)`
151| ` exe -c <x> <y> ` | ` required("-c") & value("x", x) & value("y", y)`
152| ` exe -c <x> [<y>] ` | ` required("-c") & value("x", x) & opt_value("y", y)`
153| ` exe [-l <lines>...] ` | ` option("-l") & values("lines", ids) `
154| ` exe [-l [<lines>...]] ` | ` option("-l") & opt_values("lines", ids) `
155| ` exe [-l <lines>]... ` | ` repeatable( option("-l") & value("lines", ids) ) `
156| ` exe -l <lines>... ` | ` required("-l") & values("lines", ids) `
157| ` exe -l [<lines>...] ` | ` required("-l") & opt_values("lines", ids) `
158| ` exe (-l <lines>)... ` | ` repeatable( required("-l") & value("lines", ids) ) `
159| ` exe fetch [-a] ` | ` command("fetch").set(k,1), option("-a").set(a) `
160| ` exe init \| fetch [-a] ` | ` command("init").set(k,0) \| (command("fetch").set(k,1), option("-a").set(a)) `
161| ` exe [-a\|-b] ` | ` option("-a").set(a) \| option("-b").set(b) `
162| ` exe [-m a\|b] ` | ` option("-m") & (required("a").set(b) \| required("b").set(b)) `
163
164
165
166
167## Overview
168
169See the [examples](#examples) section for detailed explanations of each topic.
170
171Namespace qualifiers are omitted from all examples for better readability. All entities are defined in ```namespace clipp```.
172
173
174#### Basic Setup
175```cpp
176int main(int argc, char* argv[]) {
177 using namespace clipp;
178
179 auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );
180 parse(argc, argv, cli); //excludes argv[0]
181
182 //if you want to include argv[0]
183 //parse(argv, argv+argc, cli);
184}
185```
186
187There are two kinds of building blocks for command line interfaces: parameters and groups. Convieniently named factory functions produce parameters or groups with the desired settings applied.
188#### Parameters ([flag strings](#flag-strings), [commands](#commands), [positional values](#required-positional-values), [required flags](#required-flags), [repeatable parameters](#repeatable-parameters))
189```cpp
190bool a = false, f = false;
191string s; vector<string> vs;
192auto cli = ( // matches required positional repeatable
193 command("push"), // exactly yes yes no
194 required("-f", "--file").set(f), // exactly yes no no
195 required("-a", "--all", "-A").set(a), // exactly no no no
196
197 value("file", s), // any arg yes yes no
198 values("file", vs), // any arg yes yes yes
199 opt_value("file", s), // any arg no yes no
200 opt_values("file", vs), // any arg no yes yes
201
202 //"catch all" parameter - useful for error handling
203 any_other(vs), // any arg no no yes
204 //catches arguments that fulfill a predicate and aren't matched by other parameters
205 any(predicate, vs) // predicate no no yes
206);
207```
208The functions above are convenience factories:
209```cpp
210bool f = true; string s;
211auto v1 = values("file", s);
212// is equivalent to:
213auto v2 = parameter{match::nonempty}.label("file").blocking(true).repeatable(true).set(s);
214
215auto r1 = required("-f", "--file").set(f);
216// is equivalent to:
217auto r2 = parameter{"-f", "--file"}.required(true).set(f);
218```
219 - a required parameter has to match at least one command line argument
220 - a repeatable parameter can match any number of arguments
221 - non-positional (=non-blocking) parameters can match arguments in any order
222 - a positional (blocking) parameter defines a "stop point", i.e., until it matches all parameters following it are not allowed to match; once it matched, all parameters preceding it (wihtin the current group) will become unreachable
223
224##### [Flags + Values](#options-with-values)
225If you want parameters to be matched in sequence, you can tie them together using either ```operator &``` or the grouping function ```in_sequence```:
226
227```cpp
228int n = 1; string s; vector<int> ls;
229auto cli = (
230 //option with required value
231 option("-n", "--repeat") & value("times", n),
232
233 //required flag with optional value
234 required("--file") & opt_value("name", s),
235
236 //option with exactly two values
237 option("-p", "--pos") & value("x") & value("y"),
238
239 //same as before v v
240 in_sequence( option("-p", "--pos") , value("x") , value("y") ),
241
242 //option with at least one value (and optionally more)
243 option("-l") & values("lines", ls)
244);
245```
246
247##### [Filtering Value Parameters](#value-filters)
248Value parameters use a filter function to test if they are allowed to match an argument string. The default filter ```match::nonempty``` that is used by ```value```, ```values```, ```opt_value``` and ```opt_values``` will match any non-empty argument string.
249You can either supply other filter functions/function objects as first argument of ```value```, ```values```, etc. or use one of these built-in shorthand factory functions covering the most common cases:
250```cpp
251string name; double r = 0.0; int n = 0;
252auto cli = (
253 value("user", name), // matches any non-empty string
254 word("user", name), // matches any non-empty alphanumeric string
255 number("ratio", r), // matches string representations of numbers
256 integer("times", n) // matches string representations of integers
257);
258```
259Analogous to ```value```, ```opt_value```, etc. there are also functions for ```words```, ```opt_word```, etc.
260
261##### Value Parameters With [Custom Filters](#custom-value-filters)
262```cpp
263auto is_char = [](const string& arg) { return arg.size() == 1 && std::isalpha(arg[0]); };
264
265char c = ' ';
266 // matches required positional repeatable
267value(is_char, "c", c); // one character yes yes no
268```
269
270
271#### Groups
272 - [group](#grouping) mutually compatible parameters with parentheses and commas:
273 ```cpp
274 auto cli = ( option("-a"), option("-b"), option("-c") );
275 ```
276
277 - group mutually exclusive parameters as [alternatives](#alternatives) using ```operator |``` or ```one_of```:
278 ```cpp
279 auto cli1 = ( value("input_file") | command("list") | command("flush") );
280
281 auto cli2 = one_of( value("input_file") , command("list") , command("flush") );
282 ```
283
284 - group parameters so that they must be matched in sequence using ```operator &``` or ```in_sequence```:
285 ```cpp
286 double x = 0, y = 0, z = 0;
287 auto cli1 = ( option("-pos") & value("X",x) & value("Y",y) & value("Z",z) );
288
289 auto cli2 = in_sequence( option("-pos") , value("X",x) , value("Y",y) , value("Z",z) );
290 ```
291 Note that surrounding groups are not affected by this, so that ```-a``` and ```-b``` can be matched in any order while ```-b``` and the value ```X``` must match in sequence:
292 ```cpp
293 bool a = false, b = false; int x = 0;
294 auto cli = ( option("-a").set(a), option("-b").set(b) & value("X",x) );
295 ```
296
297 - groups can be nested and combined to form arbitrarily complex interfaces (see [here](#nested-alternatives) and [here](#complex-nestings)):
298 ```cpp
299 auto cli = ( command("push") | ( command("pull"), option("-f", "--force") ) );
300 ```
301
302 - groups can be repeatable as well:
303 ```cpp
304 auto cli1 = repeatable( command("flip") | command("flop") );
305 ```
306
307 - force common prefixes on a group of flags:
308 ```cpp
309 int x = 0;
310 auto cli1 = with_prefix("-", option("a"), option("b") & value("x",x), ... );
311 // => -a -b ^unaffected^
312
313 auto cli2 = with_prefix_short_long("-", "--", option("a", "all"), option("b"), ... );
314 // => -a --all -b
315 ```
316
317 - force common suffixes on a group of flags:
318 ```cpp
319 int x = 0;
320 auto cli1 = with_suffix("=", option("a") & value("x",x), ... );
321 // => a= ^unaffected^
322
323 auto cli2 = with_suffix_short_long(":", ":=", option("a", "all"), option("b"), ... );
324 // => a: all:= b:
325 ```
326
327 - make a group of flags [joinable](#joinable-flags):
328 ```cpp
329 auto cli1 = joinable( option("-a"), option("-b")); //will match "-a", "-b", "-ab", "-ba"
330
331 //works also with arbitrary common prefixes:
332 auto cli2 = joinable( option("--xA0"), option("--xB1")); //will also match "--xA0B1" or "--xB1A0"
333 ```
334
335
336#### Interfacing With Your Code
337The easiest way to connect the command line interface to the rest of your code is to bind object values or function (object) calls to parameters (see also [here](#actions)):
338```cpp
339bool b = false; int i = 5; int m = 0; string x; ifstream fs;
340auto cli = (
341 option("-b").set(b), // "-b" detected -> set b to true
342 option("-m").set(m,2), // "-m" detected -> set m to 2
343 option("-x") & value("X", x), // set x's value from arg string
344 option("-i") & opt_value("i", i), // set i's value from arg string
345 option("-v").call( []{ cout << "v"; } ), // call function (object) / lambda
346 option("-v")( []{ cout << "v"; } ), // same as previous line
347 option("-f") & value("file").call([&](string f){ fs.open(f); })
348);
349```
350
351In production code one would probably use a settings class:
352```cpp
353struct settings { bool x = false; /* ... */ };
354
355settings cmdline_settings(int argc, char* argv[]) {
356 settings s;
357 auto cli = ( option("-x").set(s.x), /* ... */ );
358 parse(argc, argv, cli);
359 return s;
360}
361```
362Note that the target must either be:
363 - a fundamental type (```int, long int, float, double, ...```)
364 - a type that is convertible from ```const char*```
365 - a callable entity: function, function object / lambda
366 that either has an empty parameter list or exactly one parameter that is
367 convertible from ```const char*```
368
369
370#### Generating Documentation ([see also here](#documentation-generation))
371Docstrings for groups and for parameters can either be set with the member function ```doc``` or with ```operator %```:
372```cpp
373auto cli = (
374 ( option("x").set(x).doc("sets X"),
375 option("y").set(y) % "sets Y"
376 ),
377 "documented group 1:" % (
378 option("-g").set(g).doc("activates G"),
379 option("-h").set(h) % "activates H"
380 ),
381 ( option("-i").set(i) % "activates I",
382 option("-j").set(j) % "activates J"
383 ).doc("documented group 2:")
384);
385```
386
387Usage Lines:
388```cpp
389cout << usage_lines(cli, "progname") << '\n';
390
391//with formatting options
392auto fmt = doc_formatting{}
393 .first_column(3)
394 .last_column(79);
395cout << usage_lines(cli, "progname", fmt) << '\n';
396```
397
398Detailed Documentation:
399```cpp
400cout << documentation(cli) << '\n';
401
402//with formatting options
403auto fmt = doc_formatting{}
404 .first_column(7)
405 .doc_column(15)
406 .last_column(99);
407cout << documentation(cli, fmt) << '\n';
408```
409
410Man Pages:
411```cpp
412auto cli = ( /*CODE DEFINING COMMAND LINE INTERFACE GOES HERE*/ );
413cout << make_man_page(cli, "progname") << '\n';
414
415//with formatting options
416auto fmt = doc_formatting{}
417 .first_column(7)
418 .doc_column(15)
419 .last_column(99);
420cout << make_man_page(cli, "progname", fmt) << '\n';
421```
422
423
424#### (Error) Event Handlers ([see here](#error-handling), [and here](#per-parameter-parsing-report))
425Each parameter can have event handler functions attached to it. These are invoked once for each argument that is mapped to the parameter (or once per missing event):
426```cpp
427string file = "default.txt";
428auto param = required("-nof").set(file,"") |
429 required("-f") & value("file", file)
430 // on 2nd, 3rd, 4th,... match (would be an error in this case)
431 .if_repeated( [] { /* ... */ } )
432 // if required value-param was missing
433 .if_missing( [] { /* ... */ } )
434 // if unreachable, e.g. no flag "-f" before filename
435 .if_blocked( [] { /* ... */ } )
436 // if match is in conflict with other alternative "-nof"
437 .if_conflicted( [] { /* ... */ } );
438```
439The handler functions can also take an int, which is set to the argument index at which the event occurred first:
440```cpp
441string file = "default.txt";
442auto param = required("-nof").set(file,"") |
443 required("-f") & value("file", file)
444 .if_repeated ( [] (int argIdx) { /* ... */ } )
445 .if_missing ( [] (int argIdx) { /* ... */ } )
446 .if_blocked ( [] (int argIdx) { /* ... */ } )
447 .if_conflicted( [] (int argIdx) { /* ... */ } );
448```
449
450
451#### Special Cases
452If we give ```-f -b``` or ```-b -f -a``` as command line arguments for the following CLI, an error will be reported, since the value after ```-f``` is not optional:
453```cpp
454auto cli = ( option("-a"), option("-f") & value("filename"), option("-b") );
455```
456This behavior is fine for most use cases.
457But what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the value parameter [greedy](#greedy-parameters) with ```operator !```. This way, the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:
458```cpp
459auto cli = ( option("-a"), option("-f") & !value("filename"), option("-b") );
460 // ^~~~~~
461```
462Be **very careful** with greedy parameters!
463
464
465
466#### Parsing Result Analysis
467```cpp
468auto cli = ( /* your interface here */ );
469auto res = parse(argc, argv, cli);
470
471if(res.any_error()) { /* ... */ }
472
473//aggregated errors
474if(res.unmapped_args_count()) { /* ... */ }
475if(res.any_bad_repeat()) { /* ... */ }
476if(res.any_blocked()) { /* ... */ }
477if(res.any_conflict()) { /* ... */ }
478
479for(const auto& m : res.missing()) {
480 cout << "missing " << m.param() << " after index " << m.after_index() << '\n';
481}
482
483//per-argument mapping
484for(const auto& m : res) {
485 cout << m.index() << ": " << m.arg() << " -> " << m.param();
486 cout << " repeat #" << m.repeat();
487 if(m.blocked()) cout << " blocked";
488 if(m.conflict()) cout << " conflict";
489 cout << '\n';
490}
491```
492
493#### Writing Your Own Convenience Factories
494Sometimes it can make your CLI code more expressive and increase maintainability, if you create your own factory functions for making parameters:
495```cpp
496//value that can only connect to one object with automatic default value documentation
497template<class Target>
498clipp::parameter
499documented_value(const std::string& name, Target& tgt, const std::string& docstr) {
500 using std::to_string;
501 return clipp::value(name,tgt).doc(docstr + "(default: " + to_string(tgt) + ")");
502}
503```
504```cpp
505//value that only matches strings without prefix '-'
506template<class Target, class... Targets>
507clipp::parameter
508nodash_value(std::string label, Target&& tgt, Targets&&... tgts) {
509 return clipp::value(clipp::match::prefix_not{"-"}, std::move(label),
510 std::forward<Target>(tgt), std::forward<Targets>(tgts)...);
511}
512```
513
514
515
516
517## Examples
518
519Note that namespace qualifiers are omitted from all examples for better readability.
520The repository folder "examples" contains code for most of the following examples.
521
522- [options](#options)
523- [coding styles](#coding-styles)
524- [flag strings](#flag-strings)
525- [groups](#grouping)
526- [positional values](#required-positional-values)
527- [options with values](#options-with-values)
528- [options with multiple values](#options-with-multiple-values)
529- [required flags](#required-flags)
530- [repeatable parameters](#repeatable-parameters)
531- [actions](#actions)
532- [joinable flags](#joinable-flags)
533- [alternatives](#alternatives)
534- [commands](#commands)
535- [nested alternatives](#nested-alternatives)
536- [complex nestings](#complex-nestings)
537- [example from docopt](#an-example-from-docopt)
538- [value filters](#value-filters)
539- [greedy parameters](#greedy-parameters)
540- [generalized joinable parameters](#generalized-joinable-parameters)
541- [custom value filters](#custom-value-filters)
542- [sanity checks](#sanity-checks)
543- [basic error handling](#basic-error-handling)
544- [parsing](#parsing)
545- [documentation generation](#documentation-generation)
546- [documentation filtering](#documentation-filtering)
547
548
549
550### Options
551```man
552SYNOPSIS
553 switch [-a] [-b] [-c] [--hi]
554
555OPTIONS
556 -a activates a
557 -b activates b
558 -c, --noc deactivates c
559 --hi says hi
560```
561
562```cpp
563bool a = false, b = false, c = true; //target variables
564
565auto cli = (
566 option("-a").set(a) % "activates a",
567 option("-b").set(b) % "activates b",
568 option("-c", "--noc").set(c,false) % "deactivates c",
569 option("--hi")([]{cout << "hi!\n";}) % "says hi");
570
571if(parse(argc, argv, cli))
572 cout << "a=" << a << "\nb=" << b << "\nc=" << c << '\n';
573else
574 cout << make_man_page(cli, "switch");
575```
576This will set ```a``` to true, if ```-a``` is found, ```b``` to true, if ```-b``` is found, ```c``` to false, if ```-c``` or ```--noc``` are found and prints "hi" if ```--hi``` is found in ```argv```. In case of parsing errors a man page will be printed.
577
578
579
580### Coding Styles
581If you like it more verbose use ```set``` to set variables, ```call``` to call functions and ```doc``` for docstrings. The sequence of member function calls doesn't matter.
582```cpp
583auto cli = (
584 option("-b").set(b).doc("activates b"),
585 option("-c", "--noc").set(c,false).doc("deactivates c"),
586 option("--hi").call([]{cout << "hi!\n";}).doc("says hi") );
587```
588
589#### You can also use ```operator >>``` and ```operator <<``` to define actions
590```cpp
591auto cli = (
592 option("-b") % "activates b" >> b,
593 option("-c", "--noc") % "deactivates c" >> set(c,false),
594 option("--hi") % "says hi" >> []{cout << "hi!\n";} );
595```
596
597```cpp
598auto cli = (
599 option("-b") % "activates b" >> b,
600 option("-c", "--noc") % "deactivates c" >> set(c,false),
601 option("--hi") % "says hi" >> []{cout << "hi!\n";} );
602```
603```cpp
604auto cli = (
605 b << option("-b") % "activates b",
606 set(c,false) << option("-c", "--noc") % "deactivates c",
607 []{cout << "hi!\n";} << option("--hi") % "says hi" );
608
609```
610```cpp
611auto cli = (
612 "activates b" % option("-b") >> b,
613 "deactivates c" % option("-c", "--noc") >> set(c,false),
614 "says hi" % option("--hi") >> []{cout << "hi!\n";} );
615```
616Note that ```%``` has a higher precedence than ```<<``` and ```>>``` which means that you either have to keep the docstrings closer to the command line parameters than the actions or use parentheses.
617
618You should also have a look at [actions](#actions) for more details.
619
620
621#### Step-by-step configuration of parameters:
622```cpp
623int n = 1;
624
625auto optN = parameter{"-n", "-N", "--iterations", "--repeats"}.required(true);
626
627auto valN = parameter{match::any}
628 .label("times")
629 .set(n)
630 .call([](string s) { if(!str::represents_number(s)) throw runtime_error{"invalid value for 'times'"}; })
631 .if_missing([]{ cout << "value 'times' not found!\n"; })
632 .doc("number of iterations (default = " + std::to_string(n) + ")");
633
634auto cli = group{};
635cli.push_back(std::move(optN));
636cli.push_back(std::move(valN));
637
638// or:
639auto cli = group{std::move(optN), std::move(valN)};
640```
641
642
643
644### Flag Strings
645There are no limitations regarding formatting and you can have an arbitrary number of flags per command line parameter.
646```cpp
647bool onetwo = false;
648auto myopt = option("-1", "-2", "1", "2", ":1", ":2", "--no1", "--no2").set(onetwo);
649 // ^----- will match any one of these strings ------^
650```
651
652#### Same prefix for all flags
653```cpp
654bool a = false, b = false;
655
656auto cli = with_prefix("-",
657 option("a").set(a), // -a
658 option("b").set(b) // -b
659);
660```
661
662#### Same prefix for all flags: single vs. multiple character(s)
663Single-letter flags will get the first prefix, flags with more than one letter will get the second one.
664```cpp
665bool a = false, b = false;
666
667auto cli = with_prefixes_short_long("-", "--",
668 option("a", "all").set(a), // -a, --all
669 option("b", "bottom").set(b) // -b, --bottom
670);
671```
672
673#### Same suffix for all flags
674```cpp
675bool a = false, b = false;
676
677auto cli = with_suffix(":",
678 option("a").set(a), // a:
679 option("b").set(b) // b:
680);
681```
682
683#### Same suffix for all flags: single vs. multiple character(s)
684Single-letter flags will get the first suffix (empty in this example), flags with more than one letter will get the second one.
685```cpp
686int a = 0, b = 0;
687
688auto cli = with_suffixes_short_long("", "=",
689 option("a", "all") & value("A", a), // -a, --all=
690 option("b", "bottom") & value("B", b) // -b, --bottom=
691);
692```
693
694#### Make Sure No Flag Occurs As Prefix Of Another Flag
695```cpp
696auto cli = ( /* your command line interface here */ );
697assert(cli.flags_are_prefix_free());
698```
699Note that identical flags will not trigger an error.
700
701
702### Grouping
703Groups can be nested (see [here](#nested-alternatives)) and have their own documentation string.
704The statement ```auto cli = ( ... );``` creates a group, if there are more than two parameters/groups declared inside the parentheses.
705
706```man
707SYNOPSIS
708 myprogram [x] [y] [a] [b] [-c] [-d] [-e] [-f]
709
710OPTIONS
711 x sets X
712 y sets Y
713
714 documented group 1:
715 a activates A
716 b activates B
717
718 documented group 2:
719 -c activates C
720 -d activates D
721
722 -e, -f activates E or F
723```
724
725```cpp
726bool x = false, y = false, a = false, b = false;
727bool g = false, h = false, e = false, f = false;
728
729auto cli = (
730 ( option("x").set(x) % "sets X", //simple group
731 option("y").set(y) % "sets Y"
732 ),
733 ( option("a").set(a) % "activates A",
734 option("b").set(b) % "activates B"
735 ) % "documented group 1:" //docstring after group
736 ,
737 "documented group 2:" % ( //docstring before group
738 option("-g").set(g) % "activates G",
739 option("-h").set(h) % "activates H"
740 ),
741 "activates E or F" % (
742 option("-e").set(e), //no docstrings inside group
743 option("-f").set(f)
744 )
745);
746
747cout << make_man_page(cli, "myprogram");
748```
749
750The above example is in fact shorthand for this:
751```cpp
752group cli{
753 group{
754 parameter{"x"}.set(x).doc("sets X"),
755 parameter{"y"}.set(y).doc("sets Y")
756 },
757 group{
758 parameter{"a"}.set(a).doc("activates A"),
759 parameter{"b"}.set(b).doc("activates B")
760 }.doc("documented group 1:")
761 ,
762 group{
763 parameter{"-g"}.set(g).doc("activates G"),
764 parameter{"-h"}.set(h).doc("activates H")
765 }.doc("documented group 2:")
766 ,
767 group{
768 parameter{"-e"}.set(e),
769 parameter{"-f"}.set(f)
770 }.doc("activates E or F")
771};
772
773cout << make_man_page(cli, "myprogram");
774```
775
776You can of course also fill groups one-by-one:
777```cpp
778group cli;
779cli.push_back(option("x").sets(x).doc("sets X"));
780//...
781```
782
783
784
785### Required Positional Values
786```man
787SYNOPSIS
788 myprogram <infile> <outfile> [-s]
789
790OPTIONS
791 infile input filename
792 outfile output filename
793 -s, --split split files
794```
795
796```cpp
797string ifile, ofile;
798bool split = false;
799auto cli = (
800 value("infile", ifile) % "input filename",
801 value("outfile", ofile) % "output filename",
802 option("-s", "--split").set(split) % "split files" );
803```
804
805#### Alternative Value Mapping Style
806```cpp
807auto cli = (
808 value("infile") % "input filename" >> ifile,
809 value("outfile") % "output filename" >> ofile,
810 option("-s", "--split") % "split files" >> split );
811```
812See [here](#coding-styles) for more on possible mapping styles.
813
814
815
816### Options With Values
817Parameters can be sequenced using operator ```&``` or the function ```in_sequence```. Sequenced parameters can only be matched one after the other. This mechanism can be used to attach a value parameter to an option.
818
819```man
820SYNOPSIS
821 simplify [-n <count>] [-r <ratio>] [-m [<lines=5>]]
822
823OPTIONS
824 -n, --count <count> number of iterations
825 -r, --ratio <ratio> compression ratio
826 -m <lines=5> merge lines (default: 5)
827```
828
829```cpp
830int n = 0;
831bool domerge = false;
832long m = 5;
833auto print_ratio = [](const char* r) { cout << "using ratio of " << r << '\n'; };
834
835auto cli = (
836 (option("-n", "--count") & value("count", n)) % "number of iterations",
837 (option("-r", "--ratio") & value("ratio", print_ratio)) % "compression ratio",
838 (option("-m").set(domerge) & opt_value("lines=5", m)) % "merge lines (default: 5)"
839);
840```
841
842
843#### Alternative Value Mapping Styles
844```cpp
845auto cli = (
846 (option("-n", "--count") & value("count") >> n ) % "number of iterations",
847 (option("-r", "--ratio") & value("ratio") >> print_ratio ) % "compression ratio",
848 (option("-m" ) & opt_value("lines=5") >> m >> domerge) % "merge lines (default: 5)"
849);
850```
851```cpp
852auto cli = (
853 (option("-n", "--count") & value("count").set(n)) % "number of iterations",
854 (option("-r", "--ratio") & value("ratio")(print_ratio)) % "compression ratio",
855 (option("-m").set(domerge) & opt_value("lines=5").set(m)) % "merge lines (default: 5)"
856);
857```
858See [here](#coding-styles) for more on coding styles.
859
860
861
862### Options With Multiple Values
863Parameters can be sequenced using operator ```&``` or the function ```in_sequence```. Sequenced parameters can only be matched one after the other. This mechanism can be used to attach multiple values to an option.
864
865```man
866SYNOPSIS
867 transform <geometry file> [-translate <x> <y> <z>] [-rotate <azimuth> <polar>]
868```
869
870```cpp
871string infile;
872bool tr = false, rot = false;
873double x = 0, y = 0, z = 0;
874double phi = 0, theta = 0;
875
876auto cli = (
877 value("geometry file", infile),
878 option("-translate").set(tr) & value("x", x) & value("y", y) & value("z", z),
879 option("-rotate").set(rot) & value("azimuth", phi) & value("polar", theta)
880);
881```
882
883Note that the following interface definition is equivalent to the above. Since ```value``` is positional we can list it with ```,```, but we have to make sure that the groups of values will only be matched after the options, hence the ```&```.
884```cpp
885auto cli = (
886 value("geometry file", infile),
887 option("-translate").set(tr) & ( value("x", x), value("y", y), value("z", z) ),
888 option("-rotate").set(rot) & ( value("azimuth", phi) , value("polar", theta) )
889);
890```
891
892
893
894### Required Flags
895Required flags are usually used together with non-optional values. Note that ```-i``` and ```-o``` are not positional in the following example, i.e., the relative order in which command line arguments for ```-i```, ```-o``` and ```-r``` are provided is irrelevant.
896
897```man
898SYNOPSIS
899 myprogram [-r] -i <input dir> -o <output dir>
900
901OPTIONS
902 -r, --recursive
903 search in subdirectories
904 -i, --in <input dir>
905 path to input directory
906 -o, --out <output dir>
907 path to output directory
908```
909
910```cpp
911bool recurse = false;
912string inpath, outpath;
913
914auto cli = (
915 option("-r", "--recursive").set(recurse) % "search in subdirectories",
916 (required("-i", "--in" ) & value("input dir", inpath)) % "path to input directory",
917 (required("-o", "--out") & value("output dir", outpath)) % "path to output directory"
918);
919```
920
921
922
923### Repeatable Parameters
924```man
925SYNOPSIS
926 simplify <file>... [-c] [-i <line>...]
927
928OPTIONS
929 <file>... input files
930 -c, --compress compress results
931 -i, --ignore <line>... lines to be ignored
932```
933
934```cpp
935vector<string> files;
936vector<int> lines;
937bool zip = false;
938auto cli = (
939 values("file", files) % "input files",
940 option("-c", "--compress").set(zip) % "compress results",
941 (option("-i", "--ignore") & integers("line", lines)) % "lines to be ignored"
942);
943```
944
945The call ```values("v")``` is shorthand for ```value("v").repeatable(true)```.
946
947Note, that the value parameter ```line``` is repeatable, but the flag ```--ignore``` is not. So
948something like
949```
950 simplify file1 file2 --ignore 1 2 --ignore 3 4 -c
951```
952is taken to be an error.
953However, it is possible if you make the group of ```--ignore``` and ```line``` itself repeatable:
954
955#### Repeatable Groups of Options with Repeatable Values
956```man
957SYNOPSIS
958 simplify <file>... [-c] [-i <line>...]...
959
960OPTIONS
961 <file>... input files
962 -c, --compress compress results
963 -i, --ignore <line>... lines to be ignored
964```
965
966```cpp
967vector<string> files;
968vector<int> lines;
969bool zip = false;
970auto cli = (
971 values("file", files) % "input files",
972 option("-c", "--compress").set(zip) % "compress results",
973 repeatable( // <-----
974 option("-i", "--ignore") & integers("line", lines)
975 ) % "lines to be ignored"
976);
977```
978Now both the option ```--ignore``` *and* the value parameter ```value``` are repeatable. In all of the following examples ```lines``` will be set to ```{1,2,3,4}``` and ```c``` will be set to ```true```:
979```
980 simplify file1 file2 -c --ignore 1 2 3 4
981 simplify file1 file2 --ignore 1 2 3 4 -c
982 simplify file1 file2 --ignore 1 -c --ignore 2 3 4
983 simplify file1 file2 --ignore 1 2 --ignore 3 4 -c
984 simplify file1 file2 --ignore 1 --ignore 2 -c --ignore 3 --ignore 4
985 simplify file1 file2 -c --ignore1 --ignore2 --ignore3 --ignore4
986```
987
988
989
990### Actions
991Actions are executed if a parameter matched an argument string in the command line arguments list. Actions are defined using the following member functions or operators:
992
993- ```parameter::call(f)``` or ```parameter::operator () (f)```: call a callable entity ```f``` (function, lambda, custom function object) for each one of the matched argument strings. If ```f``` accepts exactly one parameter that is convertible from ```const char*```, the command line argument is passed to it. If the parameter list is empty, it is simply called without argument.
994
995- ```parameter::set(target, value)```: assign a fixed value to a target object; note that the assignment ```target = value;``` must be a valid statement
996
997- ```parameter::set(target)```:
998 - A ```bool``` target is set to true if the flag/value is present and **left unchanged otherwise**.
999 - A target object of fundamental type ```T``` (```int```, ```long```, ```float```, ```double```, ...) will be assigned the result of converting the argument string to type ```T```.
1000 - Targets of type ```std::vector<T>``` are appended with a value for each matched argument string. Note that ```T``` must either be (explicitly) convertible from ```const char*``` or a fundamental type.
1001
1002- ```operator <<``` or ```operator >>``` assign arg strings to lvalues or call callable entities. Which kind of action will be performed is automatically determined through overload resolution.
1003
1004
1005#### Predefined Functions
1006```cpp
1007int x = 0; // equivalent to:
1008option("-x")(set(x)) // option("-x").set(x)
1009option("-x")(set(x,2)) // option("-x").set(x,2)
1010option("-x")(increment(x)) // option("-x")([&]{++x;})
1011option("-x")(decrement(x)) // option("-x")([&]{--x;})
1012
1013bool b = false; // equivalent to:
1014option("-b")(flip(b)) // option("-x")([&]{b = !b;})
1015```
1016
1017
1018#### Some Examples
1019```cpp
1020bool a = false, b = false;
1021int i = 1, n = 0, m = 0;
1022float x = 0.0f;
1023
1024auto cli = ( //INFORMAL description
1025 option("-a").set(a), //if(found("-a")) a = true;
1026 option("-b") >> b, //if(found("-b")) b = true;
1027 option("--toggle").call(flip(b)), //if(found("--toggle")) flip(b);
1028
1029 value("n").set(n), //n = std::atoi(arg);
1030 option("-i") & value("#",i), //if(found("-i arg")) i = std::atoi(arg);
1031 option("-1").set(m,1), //if(found("-1")) m = 1;
1032 option("-2").set(m,2), //if(found("-2")) m = 2;
1033
1034 //if(found("-z")) call_lambda_with_arg("-z");
1035 option("-z").call([](const char* s) { cout << s; }),
1036
1037 //using 'operator()' instead of 'call'
1038 //if(found("bob")) call_lambda_with_arg("bob");
1039 option("bob")([](const std::string& s) { cout << s; }),
1040
1041 //for_each_occurence("-x arg", call_lambda_with_arg(arg));
1042 repeatable( option("-x") & value("X")([&](const char* s) { x = std::atof(s); }) ),
1043
1044 option("--all") >> []() { cout << "found --all\n"; }
1045 >> [](const char* s) { cout << "found flag " << s << '\n'; };
1046);
1047```
1048
1049
1050
1051### Joinable Flags
1052```man
1053SYNOPSIS
1054 edit <file> [-rbs] ([:vim] [:st3] [:atom] [:emacs])
1055
1056OPTIONS
1057 -r open read-only
1058 -b use backup file
1059 -s use swap file
1060
1061 :vim, :st3, :atom, :emacs
1062 editor(s) to use; multiple possible
1063```
1064
1065```cpp
1066std::string file;
1067bool readonly = false, usebackup = false, useswap = false;
1068enum class editor {vim, sublime3, atom, emacs};
1069std::vector<editor> editors;
1070auto add = [&](editor e){ return [&]{ editors.push_back(e); }; };
1071
1072auto cli = (
1073 value("file", file),
1074 joinable(
1075 option("-r").set(readonly) % "open read-only",
1076 option("-b").set(usebackup) % "use backup file",
1077 option("-s").set(useswap) % "use swap file"
1078 ),
1079 joinable(
1080 option(":vim") >> add(editor::vim),
1081 option(":st3") >> add(editor::sublime3),
1082 option(":atom") >> add(editor::atom),
1083 option(":emacs") >> add(editor::emacs)
1084 ) % "editor(s) to use; multiple possible"
1085);
1086```
1087- Flags can be joined regardless of their length (second group in the example).
1088- If the flags have a common prefix (```-``` or ```:``` in the example) it must be given at least
1089 once as leading prefix in the command line argument.
1090- Allowed args for the first group are:
1091 ```-r```, ```-b```, ```-s```, ```-rb```, ```-br```, ```-rs```, ```-sr```,
1092 ```-sb```, ```-bs```, ```-rbs```, ```-rsb```, ...
1093- Allowed args for the second group are:
1094 ```:vim```, ```:vim:atom```, ```:emacs:st3```, ```:vimatom```, ...
1095
1096#### More Examples
1097
1098| joinable flags | valid args |
1099| ------------------------ | --------------------- |
1100| ```a```, ```b``` | ```ab```, ```ba```, ```a```, ```b``` |
1101| ```-a```, ```-b``` | ```-ab```, ```-ba```, ```-a```, ```-b```, ```-a-b```, ```-b-a``` |
1102| ```--a```, ```--b``` | ```--ab```, ```--ba```, ```--a```, ```--b```, ```--a--b```, ```--b--a``` |
1103| ```,a```, ```,b``` | ```,ab```, ```,ba```, ```,a```, ```,b```, ```,a,b```, ```,b,a``` |
1104| ```Xab```, ```Xcd``` | ```Xabcd```, ```Xcdab```, ```XabXcd```, ```XcdXab```, ```Xab```, ```Xcd``` |
1105| ```x:ab```, ```x:cd``` | ```x:abcd```, ```x:cdab```, ```x:abx:cd```, ```x:cdx:ab```, ```x:ab```, ```x:cd``` |
1106
1107
1108
1109### Alternatives
1110```man
1111SYNOPSIS
1112 find <file>... -s <expr> [any|all]
1113
1114OPTIONS
1115 <file>... input filenames
1116 -s <expr> string to look for
1117 any report as soon as any matches
1118 all report only if all match
1119```
1120
1121```cpp
1122vector<string> files;
1123string expr;
1124bool ifany = false, ifall = false;
1125
1126auto cli = (
1127 values("file", files) % "input filenames",
1128 (required("-s") & value("expr", expr)) % "string to look for",
1129 option("any").set(ifany) % "report as soon as any matches" |
1130 option("all").set(ifall) % "report only if all match"
1131);
1132```
1133
1134If you like it more verbose you can use the function ```one_of``` instead of ```operator |```:
1135```cpp
1136auto cli = (
1137 values("file", files) % "input filenames",
1138 (required("-s") & value("expr", expr)) % "string to look for",
1139 one_of( option("any").set(ifany) % "report as soon as any matches",
1140 option("all").set(ifall) % "report only if all match" )
1141);
1142```
1143
1144
1145#### gcc-style switches
1146```man
1147SYNOPSIS
1148 format [-o <output file>] [-falign|-fnoalign)]
1149
1150OPTIONS
1151 -o, --out <file>
1152 output filename
1153
1154 -falign, -fnoalign
1155 control alignment
1156```
1157
1158```cpp
1159string outfile = "a.out";
1160bool align = false;
1161
1162auto cli = (
1163 (option("-o", "--out") & value("output file", outfile)) % "output filename",
1164 ( option("-falign" ).set(align,true) |
1165 option("-fnoalign").set(align,false) ) % "control alignment"
1166);
1167```
1168
1169Note, that the documentation string is attached to the group of parameters for better readability.
1170
1171
1172#### non-redundant prefix specification
1173```cpp
1174//has the same meaning as the code above
1175string outfile = "a.out";
1176bool align = false;
1177
1178auto cli = (
1179 (option("-o", "--out") & value("output file", outfile)) % "output filename",
1180 with_prefix("-f", option("align" ).set(align,true) |
1181 option("noalign").set(align,false) ) % "control alignment"
1182);
1183```
1184
1185
1186#### merge alternatives with common prefixes in documentation
1187```man
1188Usage: format [-o <output file>] [-f(align|noalign)]
1189```
1190```cpp
1191auto fmt = doc_formatting{}.merge_alternative_flags_with_common_prefix(true);
1192cout << usage_lines(cli, "format", fmt) << '\n';
1193```
1194
1195
1196
1197### Commands
1198**= positional, required flags**
1199```man
1200SYNOPSIS
1201 make_doc new <filename> [-e <enc>]
1202
1203OPTIONS
1204 -e, --encoding 'utf8' or 'cp1252', default is UTF-8
1205
1206```
1207
1208```cpp
1209std::string fname;
1210std::string enc = "utf8";
1211
1212auto cli = (
1213 command("new"),
1214 value("filename", fname),
1215 option("-e", "--encoding") & value("enc", enc).doc("'utf8' or 'cp1252', default is " + enc)
1216);
1217```
1218
1219
1220
1221### Nested Alternatives
1222```man
1223SYNOPSIS
1224 image-find help
1225 image-find build (new|add) <file>... [-v] [-b [<size=1024>]] [--init|--no-init]
1226 image-find query <infile> -o <outfile> [-f <format>]
1227
1228OPTIONS
1229 -v, --verbose
1230 print detailed report
1231
1232 -b, --buffer [<size=1024>]
1233 sets buffer size in KiByte
1234
1235 --init, --no-init
1236 do or don't initialize
1237
1238 -f, --out-format <format>
1239 determine output format
1240```
1241
1242Value handling actions are omitted; see examples/nested_alternatives.cpp for a fully functional demo.
1243```cpp
1244auto cli = (
1245 command("help")
1246 | ( command("build"),
1247 ( command("new") | command("add")),
1248 values("file"),
1249 option("-v", "--verbose") % "print detailed report",
1250 (option("-b", "--buffer") & opt_value("size=1024")) % "sets buffer size in KiByte",
1251 ( option("--init") | option("--no-init") ) % "do or don't initialize"
1252 )
1253 | ( command("query"),
1254 value("infile"),
1255 required("-o", "--out") & value("outfile"),
1256 (option("-f", "--out-format") & value("format")) % "determine output format"
1257 )
1258);
1259```
1260
1261Note:
1262```
1263doc_formatting::split_alternatives(bool) //default: true
1264doc_formatting::alternatives_min_split_size(int) //default: 3
1265```
1266control if the usage is split up into several lines if any group inside an alternative exceeds a given minimum size.
1267
1268
1269
1270### Complex Nestings
1271The combination of blocking parameters, alternatives and grouping makes it possible to define interfaces with decision trees/DAGs of arbitrary complexity.
1272```man
1273SYNOPSIS
1274 complex_nesting [-v] [-i] (copy|move) [--all] [--replace] [-f] <files>... [-r] [-h]
1275 complex_nesting [-v] [-i] compare (date|content) [-b] [-q] <files>... [-r] [-h]
1276 complex_nesting [-v] [-i] merge (diff|patch) -o <outdir> [--show-conflicts] <files>... [-r] [-h]
1277 complex_nesting [-v] [-i] merge content [--git-style] [-m <marker>] -o <outdir> [--show-conflicts] <files>... [-r] [-h]
1278 complex_nesting [-v] [-i] list <files>... [-r] [-h]
1279
1280OPTIONS
1281 user interface options:
1282 -v, --verbose show detailed output
1283 -i, --interactive use interactive mode
1284
1285 copy mode:
1286 --all copy all
1287 --replace replace existing files
1288 -f, --force don't ask for confirmation
1289
1290 compare mode:
1291 -b, --binary compare files byte by byte
1292 -q, --quick use heuristics for faster comparison
1293
1294 merge mode:
1295 diff merge using diff
1296 patch merge using patch
1297 content merge based on content
1298
1299 content based merge options:
1300 --git-style emulate git's merge behavior
1301 <marker> merge marker symbol
1302
1303 <outdir> target directory for merge result
1304 --show-conflicts show merge conflicts during run
1305
1306 mode-independent options:
1307 <files>... input files
1308 -r, --recursive descend into subdirectories
1309 -h, --help show help
1310```
1311
1312Actions and target variables are omitted in the code.
1313```cpp
1314auto copyMode = "copy mode:" % (
1315 command("copy") | command("move"),
1316 option("--all") % "copy all",
1317 option("--replace") % "replace existing files",
1318 option("-f", "--force") % "don't ask for confirmation"
1319);
1320
1321auto compareMode = "compare mode:" % (
1322 command("compare"),
1323 (command("date") | command("content")),
1324 option("-b", "--binary") % "compare files byte by byte",
1325 option("-q", "--quick") % "use heuristics for faster comparison"
1326);
1327
1328auto mergeAlgo = (
1329 command("diff") % "merge using diff" |
1330 command("patch") % "merge using patch" |
1331 ( command("content") % "merge based on content",
1332 "content based merge options:" % (
1333 option("--git-style") % "emulate git's merge behavior",
1334 option("-m", "--marker") & value("marker") % "merge marker symbol"
1335 )
1336 )
1337);
1338
1339auto mergeMode = "merge mode:" % (
1340 command("merge"),
1341 mergeAlgo,
1342 required("-o") & value("outdir") % "target directory for merge result",
1343 option("--show-conflicts") % "show merge conflicts during run"
1344);
1345
1346auto firstOpt = "user interface options:" % (
1347 option("-v", "--verbose") % "show detailed output",
1348 option("-i", "--interactive") % "use interactive mode"
1349);
1350auto lastOpt = "mode-independent options:" % (
1351 values("files") % "input files",
1352 option("-r", "--recursive") % "descend into subdirectories",
1353 option("-h", "--help") % "show help"
1354);
1355
1356auto cli = (
1357 firstOpt,
1358 copyMode | compareMode | mergeMode | command("list"),
1359 lastOpt
1360);
1361
1362if(parse(argc, argv, cli)) {
1363 // program logic...
1364} else {
1365 auto fmt = doc_formatting{}.doc_column(31);
1366 cout << make_man_page(cli, argv[0], fmt) << '\n';
1367}
1368```
1369
1370You could of course write down everything as one big expression (docstrings are omitted)...:
1371```cpp
1372auto cli = (
1373 option("-v", "--verbose"),
1374 option("-i", "--interactive"),
1375 (
1376 ( (command("copy") | command("move")),
1377 option("--all"), option("--replace"),
1378 option("-f", "--force")
1379 )
1380 | ( command("compare"),
1381 (command("date") | command("content")),
1382 option("-b", "--binary"), option("-q", "--quick")
1383 )
1384 | ( command("merge"),
1385 (
1386 ( command("content"),
1387 option("--git-style"),
1388 option("-m", "--marker") & value("marker")
1389 )
1390 | command("diff")
1391 | command("patch")
1392 ),
1393 required("-o") & value("outdir"),
1394 option("--show-conflicts")
1395 )
1396 | command("list")
1397 ),
1398 values("files"),
1399 option("-r", "--recursive"),
1400 option("-h", "--help")
1401);
1402 ```
1403...but it is probably more readable and maintainable if you break up the CLI definition into logical parts.
1404
1405Note:
1406```
1407doc_formatting::split_alternatives(bool) //default: true
1408doc_formatting::alternatives_min_split_size(int) //default: 3
1409```
1410control whether the usage is split up into several lines if any group inside an alternative exceeds a given minimum size.
1411
1412
1413
1414### An Example From [docopt]
1415```man
1416Naval Fate.
1417
1418Usage:
1419 naval_fate ship new <name>...
1420 naval_fate ship <name> move <x> <y> [--speed= <kn>]
1421 naval_fate ship shoot <x> <y>
1422 naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
1423 naval_fate -h | --help
1424 naval_fate --version
1425
1426Options:
1427 --speed= <kn> Speed in knots [default: 10].
1428 --moored Moored (anchored) mine.
1429 --drifting Drifting mine.
1430 -h, --help Show this screen.
1431 --version Show version.
1432```
1433
1434This code defines the command line interface, handles the parsing result and
1435generates the above man page snippet.
1436```cpp
1437int x = 0, y = 0;
1438float speed = 0.0f;
1439bool drift = true;
1440vector<string> names;
1441enum class mode { none, help, shipnew, shipmove, shipshoot, mineset, minerem};
1442mode selected = mode::none;
1443
1444//define command line interface
1445auto coordinates = ( value("x", x), value("y", y) );
1446
1447auto shipnew = ( command("new").set(selected,mode::shipnew),
1448 values("name", names) );
1449
1450auto shipmove = (
1451 value("name", names),
1452 command("move").set(selected,mode::shipmove), coordinates,
1453 option("--speed=") & value("kn",speed) % "Speed in knots [default: 10]");
1454
1455auto shipshoot = ( command("shoot").set(selected,mode::shipshoot),
1456 coordinates );
1457
1458auto mines = (
1459 command("mine"),
1460 (command("set" ).set(selected,mode::mineset) |
1461 command("remove").set(selected,mode::minerem) ),
1462 coordinates,
1463 (option("--moored" ).set(drift,false) % "Moored (anchored) mine." |
1464 option("--drifting").set(drift,true) % "Drifting mine." )
1465);
1466
1467auto navalcli = (
1468 ( command("ship"), ( shipnew | shipmove | shipshoot ) )
1469 | mines,
1470 | command("-h", "--help").set(selected,mode::help) % "Show this screen."
1471 | command("--version")([]{ cout << "version 1.0\n"; }) % "Show version."
1472);
1473
1474parse(argc, argv, navalcli);
1475
1476//handle results
1477switch(m) {
1478 case mode::none:
1479 break;
1480 case mode::help: {
1481 auto fmt = doc_formatting{}
1482 .first_column(2).doc_column(16)
1483 .max_flags_per_param_in_usage(4);
1484
1485 cout << "Naval Fate.\n\nUsage:\n"
1486 << usage_lines(navalcli, "naval_fate", fmt)
1487 << "\n\nOptions:\n"
1488 << documentation(navalcli, fmt) << '\n';
1489 }
1490 break;
1491 }
1492 //...
1493}
1494```
1495
1496
1497
1498
1499### Value Filters
1500If a parameter doesn't have flags, i.e. it is a value-parameter, a filter function will be used to test if it matches an argument string. The default filter is ```clipp::match::nonempty``` which will match any non-empty argument string.
1501If you want more control over what is matched, you can use some other predefined filters or you can write your own ones (see [here](#custom-value-filters)).
1502
1503```man
1504Usage: exec [-n <times>] [-l <line>...] [-b <ratio>] [-f <term>]
1505```
1506
1507```cpp
1508int n = 1;
1509std::vector<int> lines;
1510double r = 1.0;
1511string term, name;
1512auto cli = (
1513 option("-n", "--repeat") & integer("times", n),
1514 option("-l", "--line") & integers("#", lines),
1515 option("-r", "--ratio) & number("ratio", r),
1516 option("-f", "--find") & word("term", term)
1517);
1518```
1519
1520#### Predefined Filtering Value-Parameters
1521```cpp
1522auto cli = (
1523 value("x"), //non-empty string
1524 word("x"), //alphanumeric string
1525 number("x"), //string representing integer or floating point number
1526 integer("x") //string representing integral number
1527);
1528```
1529Note that there are additional functions for
1530 - optional parameters: ```opt_value```, ```opt_word```, ...
1531 - repeatable parameters: ```values```, ```words```, ...
1532 - repeatable, optional parameters: ```opt_values```, ```opt_words```, ...
1533
1534
1535#### Using Filters Explicitly
1536Two kinds of filters are supported right now that can be passed as first argument of ```value```, ```values```, ```opt_value``` or ```opt_values``` as well as argument of the constructor ```parameter::parameter(Filter&&)```
1537 - Predicates ```(const string&) -> bool```
1538 which should return true if and only if an argument is an exact match.
1539
1540 - Substring matchers ```(const string&) -> subrange```
1541 which in case of a match also indicate the position and length of the matched substring within a command line argument.
1542
1543```cpp
1544string s;
1545value( match::length{1,5}, "str", s);
1546
1547//or using the parameter class directly
1548auto p = parameter{ match::length{1,5} }
1549 .positional(true).required(true)
1550 .label("str").set(s);
1551```
1552There are a couple of predefined filters in ```namespace clipp::match```, but you can of course write your own ones (see [here](#custom-value-filters)).
1553
1554Here is another example that makes sure we don't catch any value starting with "-" as a filename:
1555```cpp
1556auto cli = (
1557 option("-a")
1558 option("-f") & value(match::prefix_not("-"), "filename"),
1559 option("-b")
1560);
1561```
1562
1563```cpp
1564namespace clipp {
1565namespace match {
1566
1567 //simple predicates
1568 bool none (const string&);
1569 bool any (const string&);
1570 bool nonempty (const string&);
1571 bool alphabetic (const string&);
1572 bool alphanumeric (const string&);
1573
1574 //filters with settings and substring matching
1575 class numbers {
1576 explicit numbers(char decimalPoint = '.', char digitSeparator = ',', char exponentSeparator = 'e');
1577 subrange operator () (const string& arg);
1578 };
1579
1580 class integers {
1581 explicit integers(char digitSeparator = ',');
1582 subrange operator () (const string& arg);
1583 };
1584
1585 class substring {
1586 explicit substring(const string& str);
1587 subrange operator () (const string& arg);
1588 };
1589
1590 class prefix {
1591 explicit prefix(const string& prefix);
1592 subrange operator () (const string& arg);
1593 };
1594
1595 class prefix_not {
1596 explicit prefix_not(const string& prefix);
1597 subrange operator () (const string& arg);
1598 };
1599
1600 class length {
1601 explicit length(size_t exact);
1602 explicit length(size_t min, size_t max);
1603 subrange operator () (const string& arg);
1604 };
1605
1606} }
1607```
1608
1609
1610
1611### Greedy Parameters
1612
1613By default, the parser tries to identify a command line argument (in that order) as
1614 - a single flag
1615 - a concatenation of multiple, _joinable_ flags (in any order)
1616 - a concatenation of a _joinable_ flag sequence in the order defined in the CLI code
1617 - a single value parameter
1618 - a concatenation of a _joinable_ flag/value sequence in the order defined in the CLI code
1619 - a concatenation of _joinable_ flags & values in no particular order
1620
1621If no match was found, the parser tries the same list again without any restrictions imposed by blocking (positional) parameters, conflicting alternatives, etc. If this leads to any match, an error will be reported. This way, _potential_, but illegal matches can be found and, e.g., conflicting alternatives can be reported.
1622
1623Consider this CLI:
1624```cpp
1625auto cli = ( option("-a"), option("-f") & value("filename"), option("-b") );
1626```
1627If we give ```-f -b``` or ```-b -f -a``` as command line arguments, an error will be reported, since the value after ```-f``` is not optional.
1628
1629This behavior is fine for most use cases.
1630But what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the ```filename``` value parameter greedy, so that the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:
1631```cpp
1632auto cli = ( option("-a"), option("-f") & greedy(value("filename")), option("-b") );
1633```
1634or using ```operator !```:
1635```cpp
1636auto cli = ( option("-a"), option("-f") & !value("filename"), option("-b") );
1637```
1638
1639Now, every string coming after an ```-f``` will be used as filename.
1640
1641If we don't want just *any* kind of match accepted, but still retain a higher priority for a value parameter, we could use a [value filter](#value-filters):
1642```cpp
1643auto cli = (
1644 ( command("A"),
1645 option("-f") & !value(match::prefix_not("-"), "filename"),
1646 option("-b")
1647 ) |
1648 ( command("B"),
1649 option("-x")
1650 )
1651);
1652```
1653This way, the command line arguments ```A -f B``` will set the filename to "B" and produce no conflict error between the alternative commands ```A``` and ```B``` but ```A -f -b``` will still give an error.
1654
1655Note, that there is an inherent decision problem: either we want the ```filename``` value to match no matter what, or we won't get proper error handling if someone forgets to specify a filename and gives ```A -f -b``` Also, there might be interfaces where we really want to catch something like ```A -f B``` as a command conflict.
1656
1657
1658
1659
1660### Generalized Joinable Parameters
1661
1662Not only flags, but arbitrary combinations of flags and values can be made joinable. This feature is especially powerful if combined with repeatable groups.
1663Important: in order for an argument to be matched by such expressions, no parameter requirements must be violated during the matching. Also, no partial argument matches are allowed.
1664
1665#### Example 1: Counting Letters
1666```man
1667Usage: counter [a|b]...
1668```
1669
1670```cpp
1671int as = 0, bs = 0;
1672
1673auto cli = joinable( repeatable(
1674 option("a").call([&]{++as;}) |
1675 option("b").call([&]{++bs;})
1676 ) );
1677
1678if(parse(argc, argv, cli))
1679 cout << "as: " << as << "\nbs: " << bs << '\n';
1680else
1681 cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n';
1682```
1683
1684Valid input includes:
1685```
1686$ ./counter a
1687$ ./counter b
1688$ ./counter ab
1689$ ./counter abba
1690$ ./counter a b baba
1691$ ./counter a babba abab abbbbba b a ba a
1692 ...
1693```
1694
1695#### Example 2: Listing Numbers
1696```man
1697Usage: numbers ([,] [<number>])...
1698```
1699
1700```cpp
1701std::vector<double> nums;
1702
1703auto cli = joinable(repeatable( option(",") , opt_number("number", nums) ));
1704
1705if(parse(argc, argv, cli)) {
1706 cout << "numbers:\n";
1707 for(auto n : nums) cout << n << '\n';
1708} else {
1709 cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n';
1710}
1711```
1712
1713Valid input includes:
1714```
1715$ ./numbers 1
1716$ ./numbers 1 2 3
1717$ ./numbers 1 , 2
1718$ ./numbers 1 , 2 , 3
1719$ ./numbers 1, 2, 3
1720$ ./numbers 1 ,2 ,3
1721$ ./numbers 1,2
1722$ ./numbers 1,2,3
1723$ ./numbers 1.1 , 2
1724$ ./numbers 1,2.3,4.5
1725$ ./numbers 1,2,3 4.2 5,6 2 7.1,8.23,9
1726```
1727
1728**Warning:** Be careful with joinable and repeatable parameters! The resulting command line interface might be a lot less intuitive to use than you think. It can also be hard to get the "grammar" of complex parsing expressions right.
1729The following definition for example, contains a subtle pitfall:
1730```cpp
1731auto cli = joinable(repeatable( option(",") , number("number", nums) ));
1732// ^^^ non-optional
1733```
1734This will not match arguments like ```"1,"```. This is, because, if the repeat group is 'hit' by any of its child parameters, all non-optional parameters must also match within the current 'repeat cycle'. So, if the parser hits the ```","``` it expects to find a number arg as well, because it is blocking (positional) and required. Only after seeing this number can it enter the next repeat cycle. Thus, the argument will not be matched, since joined matches are only valid if no error occured. Making the number optional solves the problem.
1735
1736
1737### Custom Value Filters
1738Two kinds of filters are supported right now that can be passed as first argument of ```value```, ```values```, ```opt_value``` or ```opt_values``` as well as argument of the constructor ```parameter::parameter(Filter&&)```:
1739
1740 - Predicates ```(const string&) -> bool```
1741 which should return true if and only if an argument is an exact match.
1742
1743 - Substring matchers ```(const string&) -> subrange```
1744 which in case of a match also indicate the position and length of the matched substring within a command line argument.
1745
1746
1747#### Simple Predicate Example
1748 ```man
1749Usage: annotate auto | (label <character>)
1750```
1751
1752```cpp
1753auto is_char = [](const string& arg) { return arg.size() == 1 && std::isalpha(arg[0]); };
1754
1755char lbl = ' ';
1756auto cli = ( command("auto") | ( command("label"), value(is_char, "character", lbl) ) );
1757```
1758
1759
1760#### Substring Matcher Example
1761
1762Let's write a program that takes strings and lists all tag names (```<tag>```) contained in them:
1763```man
1764Usage: tagnames <string>...
1765```
1766
1767```cpp
1768//custom filter
1769auto tag_name = [] (const string& arg) {
1770 if(arg.size() < 3) return subrange{}; //too short
1771 auto i = arg.find("<");
1772 if(i == string::npos) return subrange{}; //no tag start found
1773 auto j = arg.find(">", i+1);
1774 if(j == string::npos) return subrange{}; //didn't find end of tag
1775 return subrange{i,j-i+1}; //partial match {start, length}
1776};
1777
1778std::set<string> tags;
1779auto cli = joinable(
1780 values(tag_name, "string",
1781 [&](const string& arg){ if(arg[1] != '/') tags.insert(arg);})
1782);
1783
1784if(parse(argc, argv, cli)) {
1785 cout << "tag names:\n";
1786 for(const auto& t : tags) cout << t << '\n';
1787} else {
1788 cout << "Usage:\n" << usage_lines(cli, "tagnames") << '\n';
1789}
1790```
1791
1792```
1793$ ./tagnames "<cee><d><e></e></d></cee>" "<a><bo></bo></a>"
1794tag names:
1795<a>
1796<bo>
1797<cee>
1798<d>
1799<e>
1800```
1801
1802
1803
1804### Sanity Checks
1805
1806Check, if no flag occurs as prefix of any other flag (identical flags will be ignored):
1807```cpp
1808auto cli = ( /* command line interface definition */);
1809
1810assert( cli.flags_are_prefix_free() );
1811```
1812
1813Check common prefix of all flags, like for example "-" (or "/" on Windows):
1814```cpp
1815auto cli = ( /* command line interface definition */);
1816
1817assert( cli.common_flag_prefix() == "-" );
1818```
1819
1820
1821
1822### Basic Error Handling
1823
1824Each parameter can have error handler functions/lambdas/function objects for different fail cases attached to it:
1825 - ```if_repeated``` is raised each time an argument is mapped to a parameter regardless of that parameter's repeatability setting
1826 - ```if_missing``` is raised if a required parameter has no argument associated with it
1827 - ```if_conflicted``` is raised if two or more arguments are mapped to more than one parameter of a group of alternatives
1828 - ```if_blocked``` is raised if an argument can only be mapped to a parameter that was not reachable at the time (e.g. because a positional value was expected before that parameter or the parameter was in a non-active alternative branch)
1829
1830#### Example:
1831```man
1832Usage: send <file> -t <target>... [--http|--ftp]
1833```
1834
1835```cpp
1836string filename;
1837vector<string> targets;
1838vector<string> wrong;
1839bool http = true;
1840
1841auto istarget = match::prefix_not("-");
1842
1843auto cli = (
1844 value("file", filename)
1845 .if_missing([]{ cout << "You need to provide a source filename!\n"; } )
1846 .if_repeated([](int idx){ cout << "Only one source file allowed! (index " << idx << ")\n"; } )
1847 ,
1848 required("-t") & values(istarget, "target", targets)
1849 .if_missing([]{ cout << "You need to provide at least one target filename!\n"; } )
1850 .if_blocked([]{ cout << "Target names must not be given before the source file name!\n"; })
1851 ,
1852 option("--http").set(http,true) |
1853 option("--ftp").set(http,false) % "protocol, default is http"
1854 .if_conflicted([]{ cout << "You can only use one protocol at a time!\n"; } )
1855 ,
1856 any_other(wrong)
1857);
1858
1859if(parse(argc, argv, cli) && wrong.empty()) {
1860 cout << "OK\n";
1861 /* ... */
1862} else {
1863 for(const auto& arg : wrong) cout << "'" << arg << "' is not a valid argument\n";
1864 cout << "Usage:" << usage_lines(cli,argv[0]) << '\n';
1865}
1866```
1867An error handler can either have an empty parameter list or take an ```int``` which is set to the command line argument index where the error occured first.
1868
1869The catch-all parameter made by ```any_other``` is used to catch command line arguments that are not supported.
1870
1871The value parameter ```target``` will only match command line arguments that do not begin with ```"-"```, so that wrongly spelled options cannot be parsed as ```target``` value.
1872
1873
1874### Parsing
1875```cpp
1876auto cli = (
1877 command("make"),
1878 value("file") % "name of file to make",
1879 option("-f", "--force") % "overwrite existing file"
1880);
1881
1882//excludes argv[0]
1883parse(argc, argv, cli);
1884
1885//if you want to include argv[0]
1886parse(argv, argv+argc, cli);
1887
1888parse({"make", "out.txt"}, cli);
1889
1890auto args = std::vector<std::string> {"make", "out.txt", "-f"};
1891parse(args, cli);
1892```
1893
1894The parse functions return an object of ```parsing_result``` which can be used for detailed analysis and will (explicitly) convert to false if any error occured during parsing.
1895```cpp
1896auto result = parse(argc, argv, cli);
1897
1898auto doc_label = [](const parameter& p) {
1899 if(!p.flags().empty()) return p.flags().front();
1900 if(!p.label().empty()) return p.label();
1901 return doc_string{"<?>"};
1902};
1903
1904cout << "args -> parameter mapping:\n";
1905for(const auto& m : result) {
1906 os << "#" << m.index() << " " << m.arg() << " -> ";
1907 auto p = m.param();
1908 if(p) {
1909 os << doc_label(*p) << " \t";
1910 if(m.repeat() > 0) {
1911 os << (m.bad_repeat() ? "[bad repeat " : "[repeat ")
1912 << m.repeat() << "]";
1913 }
1914 if(m.blocked()) os << " [blocked]";
1915 if(m.conflict()) os << " [conflict]";
1916 os << '\n';
1917 }
1918 else {
1919 os << " [unmapped]\n";
1920 }
1921}
1922
1923cout << "missing parameters:\n";
1924for(const auto& m : result.missing()) {
1925 auto p = m.param();
1926 if(p) {
1927 os << doc_label(*p) << " \t";
1928 os << " [missing after " << m.after_index() << "]\n";
1929 }
1930}
1931
1932```
1933
1934
1935
1936### Documentation Generation
1937Generate usage lines and documentation from parameters:
1938```cpp
1939auto cli = ( /* command line interface definition */ );
1940
1941//used default formatting
1942cout << "Usage:\n" << usage_lines(cli, "progname")
1943 << "\nOptions:\n" << documentation(cli) << '\n';
1944```
1945... or generate an entire man page in one go:
1946```cpp
1947auto cli = ( /* command line interface definition */ );
1948
1949cout << make_man_page(cli, "progname")
1950 .prepend_section("DESCRIPTION", " The best thing since sliced bread.")
1951 .append_section("LICENSE", " GPL3");
1952```
1953
1954#### Example
1955```man
1956DESCRIPTION
1957 Builds a database of words from text files.
1958
1959SYNOPSIS
1960 worddb help
1961 worddb build (new|add) <file>
1962 worddb query -i <infile> [-p]
1963 worddb info space
1964 worddb info statistics (words|chars)
1965 worddb remove (any|all) <regex>
1966 worddb modify [-c] [-u] [-m <size>]
1967
1968OPTIONS
1969 build commands
1970 new make new database
1971 add append to existing database
1972
1973 query settings
1974 <infile> input file
1975 -p, --pretty-print human friendly output
1976
1977 database info modes
1978 space detailed memory occupation analysis
1979
1980 statistics analysis
1981 words word frequency table
1982 chars character frequency table
1983
1984 remove mode
1985 <regex> regular expression filter
1986
1987 modification operations
1988 -c, --compress compress database in-memory
1989 -u, --unique keep only unique entries
1990 -m, --memlimit max. size in RAM
1991
1992LICENSE
1993 GPL3
1994 ```
1995
1996The full code:
1997```cpp
1998auto cli = (
1999 command("help") |
2000 ( command("build"),
2001 "build commands" %
2002 ( command("new") % "make new database"
2003 | command("add") % "append to existing database"
2004 ),
2005 value("file")
2006 ) |
2007 ( command("query"),
2008 "query settings" %
2009 ( required("-i", "--input") & value("infile") % "input file",
2010 option("-p", "--pretty-print") % "human friendly output")
2011 ) |
2012 ( command("info"),
2013 "database info modes" % (
2014 command("space") % "detailed memory occupation analysis" |
2015 (
2016 command("statistics"),
2017 "statistics analysis" % (
2018 command("words") % "word frequency table" |
2019 command("chars") % "character frequency table"
2020 )
2021 )
2022 )
2023 ) |
2024 "remove mode" % (
2025 command("remove"),
2026 "modify" % ( command("any") | command("all") ),
2027 value("regex") % "regular expression filter"
2028 ) |
2029 ( command("modify"),
2030 "modification operations" % (
2031 option("-c", "--compress") % "compress database in-memory",
2032 option("-u", "--unique") % "keep only unique entries",
2033 option("-m", "--memlimit") % "max. size in RAM" & value("size")
2034 )
2035 )
2036);
2037
2038auto fmt = doc_formatting{} .first_column(4) .doc_column(28) .last_column(80);
2039
2040cout << make_man_page(cli, "worddb", fmt)
2041 .prepend_section("DESCRIPTION", " Builds a database of words from text files.")
2042 .append_section("LICENSE", " GPL3") << '\n';
2043```
2044
2045
2046#### Formatting Options
2047```cpp
2048//all formatting options (with their default values)
2049auto fmt = doc_formatting{}
2050 .first_column(8) //left border column for text body
2051 .doc_column(20) //column where parameter docstring starts
2052 .last_column(100) //right border column for text body
2053 .indent_size(4) //indent of documentation lines for children of a documented group
2054 .line_spacing(0) //number of empty lines after single documentation lines
2055 .paragraph_spacing(1) //number of empty lines before and after paragraphs
2056 .flag_separator(", ") //between flags of the same parameter
2057 .param_separator(" ") //between parameters
2058 .group_separator(" ") //between groups (in usage)
2059 .alternative_param_separator("|") //between alternative flags
2060 .alternative_group_separator(" | ") //between alternative groups
2061 .surround_group("(", ")") //surround groups with these
2062 .surround_alternatives("(", ")") //surround group of alternatives with these
2063 .surround_alternative_flags("", "") //surround alternative flags with these
2064 .surround_joinable("(", ")") //surround group of joinable flags with these
2065 .surround_optional("[", "]") //surround optional parameters with these
2066 .surround_repeat("", "...") //surround repeatable parameters with these
2067 .surround_value("<", ">") //surround values with these
2068 .empty_label("") //used if parameter has no flags and no label
2069 .max_flags_per_param_in_usage(1) //max. # of flags per parameter in usage
2070 .max_flags_per_param_in_doc(32) //max. # of flags per parameter in detailed documentation
2071 .split_alternatives(true) //split usage into several lines for large alternatives
2072 .alternatives_min_split_size(3) //min. # of parameters for separate usage line
2073 .merge_alternative_flags_with_common_prefix(false) //-ab(cdxy|xy) instead of -abcdxy|-abxy
2074 .merge_joinable_flags_with_common_prefix(true) //-abc instead of -a -b -c
2075 .ignore_newline_chars(false) //ignore '\n' in docstrings
2076 ;
2077
2078cout << "Usage:\n" << usage_lines(cli, "progname", fmt)
2079 << "\nOptions:\n" << documentation(cli, fmt) << '\n';
2080
2081//or generate entire man page in one go
2082cout << make_man_page(cli, "progname", fmt)
2083 .prepend_section("DESCRIPTION", "This program lets you format text.")
2084 .append_section("LICENSE", "GPLv3");
2085```
2086
2087
2088
2089### Documentation Filtering
2090
2091The documentation generator class ```documentation``` can also take an additional third constructor argument that allows to filter parameters according to their properties.
2092
2093```cpp
2094int main(int argc, char* argv[]) {
2095 auto cli = (
2096 value("input file"),
2097 option("-r", "--recursive").set(rec).doc("convert files recursively"),
2098 option("-o") & value("output format", fmt),
2099 option("-utf16").set(utf16).doc("use UTF-16 encoding")
2100 );
2101
2102 auto fmt = doc_formatting{}.doc_column(28);
2103
2104 auto filter = param_filter{}.prefix("--");
2105
2106 cout << "Usage:\n" << usage_lines(cli, argv[0]) << "\n\n"
2107 << "Parameters:\n" << documentation(cli, fmt, filter) << '\n';}
2108```
2109
2110Which results in:
2111```man
2112Usage:
2113 convert <input file> [-r] [-o <output format>] [-utf16]
2114
2115Parameters:
2116 -r, --recursive convert files recursively
2117```
2118
2119#### Parameter Filters
2120
2121Any function/lambda that maps a parameter to a bool can be used as filter
2122predicate. CLIPP also comes with a default parameter filter class:
2123```cpp
2124//all param_filter options (with their default values)
2125auto filter = param_filter{}
2126 .prefix("") //only parameters with given prefix
2127 .required(tri::either) //required parameters
2128 .blocking(tri::either) //blocking/positional parameters
2129 .repeatable(tri::either) //repeatable parameters
2130 .has_doc(tri::yes) //parameters with/without docstrings
2131 ;
2132```
2133which uses a dedicated tristate type:
2134```cpp
2135namespace clipp {
2136 enum class tri { no, yes, either };
2137}
2138```
2139
2140
2141## Motivation
2142Well, I didn't find a library that makes building simple command line interfaces simple, yet can also be used to build complex CLIs. I really don't want to write 20 lines of boilerplate just to have 3 simple command line options. I also don't want to drag along monstrosities like boost or Qt for that. Over time, *clipp* evolved into a domain specific language (in pure C++) that I hope can at least somewhat approach the readability of [docopt] but can leverage the benefits (toolability, etc.) of C++'s type system.
2143
2144
2145#### Other libraries (Boost, POCO, Qt, adishavit/Argh, Taywee/args ... or 'getopt')
2146 - often involve a lot of boilerplate (also for very simple use cases)
2147 - Some libs might be okay in terms of usability, but don't let you build complex interfaces
2148 with nested alternatives, mixed commands & options, positional values, more than 2 flags per option, etc.
2149 - I really like ad-hoc parsers like [Argh](https://github.com/adishavit/argh) for their simplicity, but they don't generate usage / man pages and don't allow complex interfaces with error checking.
2150 - Most libs make it really hard to figure out the resulting command line interface by looking at the code (OK, you be the judge if I did a better job at this...).
2151 - Some libs come with a ton of dependencies (Qt, Boost). I want a single header file!
2152 - Some libs require the separation of code related to one command/option. I find this harder to maintain than having everything related to one option in one place.
2153 - Sometimes flag strings of commands/options have to be repeated several times over.
2154 - Many libs come with restrictions regarding flag names, formatting, joinability, etc.
2155
2156
2157#### What about [docopt]?
2158I like the basic idea, but I don't like redundancy in code, especially if it involves repeating string literals. Docopt generates a command line argument parser from a "man page docstring". After parsing, you have to query a dictionary to get values or check for option presence. That means you either have to mention the same flag names twice (in the docstring *and* in the query) or you have to use string variables which makes the docstring hard to read and kind of defeats the purpose of docopt. Furthermore, the code tends to be littered with string-to-whatever conversions.
2159
2160I also wanted the ability to keep *everything* related to one option/command/value together in the code which I found very useful for programs with lots of command line options. Docopt doesn't let you do that since the interface definition and the code performing any actions is always separated (unless you give up on the "beautiful doc page" idea at the heart of docopt and build your input string to the parser generator piece-by-piece).
2161
2162
2163
2164
2165## Design Goals
2166 - minimize boilerplate
2167 - simple code for simple use cases
2168 - good code readability (as far as C++ allows for it)
2169 - avoid ambiguities
2170 - eliminate repetitions
2171 - ability to keep code related to one option/command/value together
2172 - support many different command line interface conventions
2173 - support different coding styles, conventions & tastes
2174 - value semantics wherever possible
2175 - do not break clipp's general interface and conventions in the future
2176
2177
2178
2179
2180## Requirements
2181 - requires a mostly C++11 conforming compiler
2182
2183### Compilers, clipp compiles with
2184 - g++ 5.3.0, g++ 5.4.1, g++ 6, g++ 7
2185 - clang++ 3.8, clang++ 3.9, clang++ 4.0, clang++ 5.0
2186 - MSVC 14.11.25503 (compiler 19.11.25547)
2187
2188
2189
2190
2191## Feedback
2192I would be delighted to hear from anyone who uses *clipp* in their project(s). If you find bugs or design flaws or want to suggest improvements please open an issue or submit a pull request.
2193
2194
2195
2196
2197## Development
2198*clipp* is still very young, so I probably won't add new features any time soon and rather:
2199 - fix bugs
2200 - improve test cases and coverage
2201 - add more code documentation
2202 - clean up the code / make it more understandable
2203 - add the ability to use other string classes
2204
2205
2206[docopt]: http://docopt.org
2207
2208