1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
libargparse
===========
This is (yet another) simple command-line parser for C++ applications, inspired by Python's agparse module.
It requires only a C++11 compiler, and has no external dependancies.
One of the advantages of libargparse is that all conversions from command-line strings to program types (bool, int etc.) are performed when the command line is parsed (and not when the options are accessed).
This avoids command-line related errors from showing up deep in the program execution, which can be problematic for long-running programs.
Basic Usage
===========
```cpp
#include "argparse.hpp"
struct Args {
argparse::ArgValue<bool> do_foo;
argparse::ArgValue<bool> enable_bar;
argparse::ArgValue<std::string> filename;
argparse::ArgValue<size_t> verbosity;
};
int main(int argc, const char** argv) {
Args args;
auto parser = argparse::ArgumentParser(argv[0], "My application description");
parser.add_argument(args.filename, "filename")
.help("File to process");
parser.add_argument(args.do_foo, "--foo")
.help("Causes foo")
.default_value("false")
.action(argparse::Action::STORE_TRUE);
parser.add_argument(args.enable_bar, "--bar")
.help("Control bar")
.default_value("false");
parser.add_argument(args.verbosity, "--verbosity", "-v")
.help("Sets the verbosity")
.default_value("1")
.choices({"0", "1", "2"});
parser.parse_args(argc, argv);
//Show the arguments
std::cout << "args.filename: " << args.filename << "\n";
std::cout << "args.do_foo: " << args.do_foo << "\n";
std::cout << "args.verbosity: " << args.verbosity << "\n";
std::cout << "\n";
//Do work
if (args.do_foo) {
if (args.verbosity > 0) {
std::cout << "Doing foo with " << args.filename << "\n";
}
if (args.verbosity > 1) {
std::cout << "Doing foo step 1" << "\n";
std::cout << "Doing foo step 2" << "\n";
std::cout << "Doing foo step 3" << "\n";
}
}
if (args.enable_bar) {
if (args.verbosity > 0) {
std::cout << "Bar is enabled" << "\n";
}
} else {
if (args.verbosity > 0) {
std::cout << "Bar is disabled" << "\n";
}
}
return 0;
}
```
and the resulting help:
```
$ ./argparse_example -h
usage: argparse_example filename [--foo] [--bar {true, false}]
[-v {0, 1, 2}] [-h]
My application description
arguments:
filename File to process
--foo Causes foo (Default: false)
--bar {true, false}
Control whether bar is enabled (Default: false)
-v {0, 1, 2}, --verbosity {0, 1, 2}
Sets the verbosity (Default: 1)
-h, --help Shows this help message
```
By default the usage and help messages are line-wrapped to 80 characters.
Custom Conversions
==================
By default libargparse performs string to program type conversions using ``<sstream>``, meaning any type supporting ``operator<<()`` and ``operator>>()`` should be automatically supported.
However this does not always provide sufficient flexibility.
As a result libargparse also supports custom conversions, allowing user-defined mappings between command-line strings to program types.
If we wanted to modify the above example so the '--bar' argument accepted the strings 'on' and 'off' (instead of the default 'true' and 'false') we would define a custom class as follows:
```cpp
struct OnOff {
ConvertedValue<bool> from_str(std::string str) {
ConvertedValue<bool> converted_value;
if (str == "on") converted_value.set_value(true);
else if (str == "off") converted_value.set_value(false);
else converted_value.set_error("Invalid argument value");
return converted_value;
}
ConvertedValue<std::string> to_str(bool val) {
ConvertedValue<std::string> converted_value;
if (val) converted_value.set_value("on");
else converted_value.set_value("off");
return converted_value;
}
std::vector<std::string> default_choices() {
return {"on", "off"};
}
};
```
Where the `from_str()` and `to_str()` define the conversions to and from a string, and `default_choices()` returns the set of valid choices. Note that default_choices() can return an empty vector to indicate there is no specified default set of choices.
We then modify the ``add_argument()`` call to use our conversion object:
```cpp
parser.add_argument<bool,OnOff>(args.enable_bar, "--bar")
.help("Control whether bar is enabled")
.default_value("off");
```
with the resulting help:
```
usage: argparse_example filename [--foo] [--bar {on, off}] [-v {0, 1, 2}]
[-h]
My application description
arguments:
filename File to process
--foo Causes foo (Default: false)
--bar {on, off} Control whether bar is enabled (Default: off)
-v {0, 1, 2}, --verbosity {0, 1, 2}
Sets the verbosity (Default: 1)
-h, --help Shows this help message
```
Advanced Usage
==============
For more advanced usage such as argument groups see [argparse_test.cpp](argparse_test.cpp) and [argparse.hpp](src/argparse.hpp).
Future Work
===========
libargparse is missing a variety of more advanced features found in Python's argparse, including (but not limited to):
* action: append, count
* subcommands
* mutually exclusive options
* parsing only known args
* concatenated short options (e.g. `-xvf`, for options `-x`, `-v`, `-f`)
* equal concatenated option values (e.g. `--foo=VALUE`)
Acknowledgements
================
Python's [argparse module](https://docs.python.org/2.7/library/argparse.html)
|