Clipp
easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation
Install / Use
/learn @muellan/ClippREADME
clipp - command line interfaces for modern C++
Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a single header file.
-
options, options+value(s), positional values, positional commands, nested alternatives, decision trees, joinable flags, custom value filters, ...
-
documentation generation (usage lines, man pages); error handling
-
lots of examples; large set of tests
-
Quick Reference Table
-
Overview (short examples)
-
Detailed Examples
-
Why yet another library for parsing command line arguments? / Design goals
-
Requirements / Compilers
Quick Intro
Simple Use Case — Simple Setup!
Consider this command line interface:
SYNOPSIS
convert <input file> [-r] [-o <output format>] [-utf16]
OPTIONS
-r, --recursive convert files recursively
-utf16 use UTF-16 encoding
Here 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.
#include <iostream>
#include "clipp.h"
using namespace clipp; using std::cout; using std::string;
int main(int argc, char* argv[]) {
bool rec = false, utf16 = false;
string infile = "", fmt = "csv";
auto cli = (
value("input file", infile),
option("-r", "--recursive").set(rec).doc("convert files recursively"),
option("-o") & value("output format", fmt),
option("-utf16").set(utf16).doc("use UTF-16 encoding")
);
if(!parse(argc, argv, cli)) cout << make_man_page(cli, argv[0]);
// ...
}
A More Complex Example:
SYNOPSIS
finder make <wordfile> -dict <dictionary> [--progress] [-v]
finder find <infile>... -dict <dictionary> [-o <outfile>] [-split|-nosplit] [-v]
finder help [-v]
OPTIONS
--progress, -p show progress
-o, --output <outfile> write to file instead of stdout
-split, -nosplit (do not) split output
-v, --version show version
This 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).
Here is the code that defines the interface, generates the man page snippet above and handles the parsing result:
using namespace clipp; using std::cout; using std::string;
//variables storing the parsing result; initialized with their default values
enum class mode {make, find, help};
mode selected = mode::help;
std::vector<string> input;
string dict, out;
bool split = false, progr = false;
auto dictionary = required("-dict") & value("dictionary", dict);
auto makeMode = (
command("make").set(selected,mode::make),
values("wordfile", input),
dictionary,
option("--progress", "-p").set(progr) % "show progress" );
auto findMode = (
command("find").set(selected,mode::find),
values("infile", input),
dictionary,
(option("-o", "--output") & value("outfile", out)) % "write to file instead of stdout",
( option("-split" ).set(split,true) |
option("-nosplit").set(split,false) ) % "(do not) split output" );
auto cli = (
(makeMode | findMode | command("help").set(selected,mode::help) ),
option("-v", "--version").call([]{cout << "version 1.0\n\n";}).doc("show version") );
if(parse(argc, argv, cli)) {
switch(selected) {
case mode::make: /* ... */ break;
case mode::find: /* ... */ break;
case mode::help: cout << make_man_page(cli, "finder"); break;
}
} else {
cout << usage_lines(cli, "finder") << '\n';
}
Quick Reference
Below are a few examples that should give you an idea for how clipp works. Consider this basic setup with a few variables that we want to set using command line arguments:
int main(int argc, char* argv[]) {
using namespace clipp;
// define some variables
bool a = false, b = false;
int n = 0, k = 0;
double x = 0.0, y = 0.0;
std::vector<int> ids;
auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );
parse(argc, argv, cli); //excludes argv[0]
std::cout << usage_lines(cli, "exe") << '\n';
}
| Interface (usage_lines) | Code (content of cli parentheses )
| -------------------------- | ------------------------------------
| exe [-a] | option("-a", "--all").set(a)
| exe [--all] | option("--all", "-a", "--ALL").set(a)
| exe [-a] [-b] | option("-a").set(a), option("-b").set(b)
| exe -a | required("-a").set(a)
| exe [-a] -b | option("-a").set(a), required("-b").set(b)
| exe [-n <times>] | option("-n", "--iter") & value("times", n)
| exe [-n [<times>]] | option("-n", "--iter") & opt_value("times", n)
| exe -n <times> | required("-n", "--iter") & value("times", n)
| exe -n [<times>] | required("-n", "--iter") & opt_value("times", n)
| exe [-c <x> <y>] | option("-c") & value("x", x) & value("y", y)
| exe -c <x> <y> | required("-c") & value("x", x) & value("y", y)
| exe -c <x> [<y>] | required("-c") & value("x", x) & opt_value("y", y)
| exe [-l <lines>...] | option("-l") & values("lines", ids)
| exe [-l [<lines>...]] | option("-l") & opt_values("lines", ids)
| exe [-l <lines>]... | repeatable( option("-l") & value("lines", ids) )
| exe -l <lines>... | required("-l") & values("lines", ids)
| exe -l [<lines>...] | required("-l") & opt_values("lines", ids)
| exe (-l <lines>)... | repeatable( required("-l") & value("lines", ids) )
| exe fetch [-a] | command("fetch").set(k,1), option("-a").set(a)
| exe init \| fetch [-a] | command("init").set(k,0) \| (command("fetch").set(k,1), option("-a").set(a))
| exe [-a\|-b] | option("-a").set(a) \| option("-b").set(b)
| exe [-m a\|b] | option("-m") & (required("a").set(a) \| required("b").set(b))
Overview
See the examples section for detailed explanations of each topic.
Namespace qualifiers are omitted from all examples for better readability. All entities are defined in namespace clipp.
Basic Setup
int main(int argc, char* argv[]) {
using namespace clipp;
auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );
parse(argc, argv, cli); //excludes argv[0]
//if you want to include argv[0]
//parse(argv, argv+argc, cli);
}
There 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.
Parameters (flag strings, commands, positional values, required flags, repeatable parameters)
bool a = false, f = false;
string s; vector<string> vs;
auto cli = ( // matches required positional repeatable
command("push"), // exactly yes yes no
required("-f", "--file").set(f), // exactly yes no no
required("-a", "--all", "-A").set(a), // exactly no no no
value("file", s), // any arg yes yes no
values("file", vs), // any arg yes yes yes
opt_value("file", s), // any arg no yes no
opt_values("file", vs), // any arg no yes yes
//"catch all" parameter - useful for error handling
any_other(vs), // any arg no no yes
//catches arguments that fulfill a predicate and aren't matched by other parameters
any(predicate, vs) // predicate no no yes
);
The functions above are convenience factories:
bool f = true; string s;
auto v1 = values("file", s);
// is equivalent to:
auto v2 = parameter{match::nonempty}.label("file").blocking(true).repeatable(true).set(s);
auto r1 = required("-f", "--file").set(f);
// is equivalent to:
auto r2 = parameter{"-f", "--file"}.required(true).set(f);
- a required parameter has to match at least one command line argument
- a repeatable parameter can match any number of arguments
- non-positional (=non-blocking) parameters can match arguments in any order
- 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
Flags + Values
If you want parameters to be matched in sequence, you can tie them together using either operator & or the grouping function in_sequence:
int n = 1; string s; vector<int> ls;
auto cli = (
//option with required value
option("-n", "--repeat") & value("times", n),
//required flag w
