* [Building, Installing, and Testing](#building-installing-and-testing)
* [Supported Toolchains](#supported-toolchains)
* [Contributing](#contributing)
* [License](#license)
## Quick Start
Simply include argparse.hpp and you're good to go.
```cpp
#include <argparse/argparse.hpp>
```
To start parsing command-line arguments, create an ```ArgumentParser```.
```cpp
argparse::ArgumentParser program("program_name");
```
**NOTE:** There is an optional second argument to the `ArgumentParser` which is the program version. Example: `argparse::ArgumentParser program("libfoo", "1.9.0");`
**NOTE:** There are optional third and fourth arguments to the `ArgumentParser` which control default arguments. Example: `argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);` See [Default Arguments](#default-arguments), below.
To add a new argument, simply call ```.add_argument(...)```. You can provide a variadic list of argument names that you want to group together, e.g., ```-v``` and ```--verbose```
Argparse supports a variety of argument types including positional, optional, and compound arguments. Below you can see how to configure each of these types:
* The ```add_argument()``` method is used to specify which command-line options the program is willing to accept. In this case, I’ve named it square so that it’s in line with its function.
* Command-line arguments are strings. To square the argument and print the result, we need to convert this argument to a number. In order to do this, we use the ```.scan``` method to convert user input into an integer.
* We can get the value stored by the parser for a given argument using ```parser.get<T>(key)``` method.
### Optional Arguments
Now, let's look at ***optional arguments***. Optional arguments start with ```-``` or ```--```, e.g., ```--verbose``` or ```-a```. Optional arguments can be placed anywhere in the input sequence.
```cpp
argparse::ArgumentParser program("test");
program.add_argument("--verbose")
.help("increase output verbosity")
.default_value(false)
.implicit_value(true);
try {
program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
std::cerr <<err.what()<<std::endl;
std::cerr <<program;
std::exit(1);
}
if (program["--verbose"] == true) {
std::cout << "Verbosity enabled" <<std::endl;
}
```
```console
foo@bar:/home/dev/$ ./main --verbose
Verbosity enabled
```
Here's what's happening:
* The program is written so as to display something when --verbose is specified and display nothing when not.
* Since the argument is actually optional, no error is thrown when running the program without ```--verbose```. Note that by using ```.default_value(false)```, if the optional argument isn’t used, it's value is automatically set to false.
* By using ```.implicit_value(true)```, the user specifies that this option is more of a flag than something that requires a value. When the user provides the --verbose option, it's value is set to true.
#### Requiring optional arguments
There are scenarios where you would like to make an optional argument ***required***. As discussed above, optional arguments either begin with `-` or `--`. You can make these types of arguments required like so:
```cpp
program.add_argument("-o", "--output")
.required()
.help("specify the output file.");
```
If the user does not provide a value for this parameter, an exception is thrown.
Alternatively, you could provide a default value like so:
```cpp
program.add_argument("-o", "--output")
.default_value(std::string("-"))
.required()
.help("specify the output file.");
```
#### Accessing optional arguments without default values
If you require an optional argument to be present but have no good default value for it, you can combine testing and accessing the argument as following:
```cpp
if (auto fn = program.present("-o")) {
do_something_with(*fn);
}
```
Similar to `get`, the `present` method also accepts a template argument. But rather than returning `T`, `parser.present<T>(key)` returns `std::optional<T>`, so that when the user does not provide a value to this parameter, the return value compares equal to `std::nullopt`.
#### Deciding if the value was given by the user
If you want to know whether the user supplied a value for an argument that has a ```.default_value```, check whether the argument ```.is_used()```.
```cpp
program.add_argument("--color")
.default_value(std::string{"orange"}) // might otherwise be type const char* leading to an error when trying program.get<std::string>
As you can see here, ```argparse``` supports negative integers, negative floats and scientific notation.
### Combining Positional and Optional Arguments
```cpp
argparse::ArgumentParser program("main");
program.add_argument("square")
.help("display the square of a given number")
.scan<'i', int>();
program.add_argument("--verbose")
.default_value(false)
.implicit_value(true);
try {
program.parse_args(argc, argv);
}
catch (const std::runtime_error& err) {
std::cerr <<err.what()<<std::endl;
std::cerr <<program;
std::exit(1);
}
int input = program.get<int>("square");
if (program["--verbose"] == true) {
std::cout << "The square of " <<input<<"is"<<(input*input)<<std::endl;
}
else {
std::cout << (input * input) <<std::endl;
}
```
```console
foo@bar:/home/dev/$ ./main 4
16
foo@bar:/home/dev/$ ./main 4 --verbose
The square of 4 is 16
foo@bar:/home/dev/$ ./main --verbose 4
The square of 4 is 16
```
### Printing Help
`std::cout << program` prints a help message, including the program usage and information about the arguments registered with the `ArgumentParser`. For the previous example, here's the default help message:
```
foo@bar:/home/dev/$ ./main --help
Usage: main [-h] [--verbose] square
Positional arguments:
square display the square of a given number
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--verbose
```
You may also get the help message in string via `program.help().str()`.
#### Adding a description and an epilog to help
`ArgumentParser::add_description` will add text before the detailed argument
information. `ArgumentParser::add_epilog` will add text after all other help output.
```cpp
#include <argparse/argparse.hpp>
int main(int argc, char *argv[]) {
argparse::ArgumentParser program("main");
program.add_argument("thing").help("Thing to use.").metavar("THING");
program.add_argument("--member").help("The alias for the member to pass to.").metavar("ALIAS");
program.add_description("Forward a thing to the next member.");
program.add_epilog("Possible things include betingalw, chiz, and res.");
program.parse_args(argc, argv);
std::cout <<program<<std::endl;
}
```
```console
Usage: main [-h] [--member ALIAS] [--verbose] THING
Forward a thing to the next member.
Positional arguments:
THING Thing to use.
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--member ALIAS The alias for the member to pass to.
--verbose
Possible things include betingalw, chiz, and res.
```
### List of Arguments
ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ```.nargs``` associates a different number of command-line arguments with a single action. When using ```nargs(N)```, N arguments from the command line will be gathered together into a list.
auto files = program.get<std::vector<std::string>>("--input_files"); // {"config.yml", "System.xml"}
```
```ArgumentParser.get<T>()``` has specializations for ```std::vector``` and ```std::list```. So, the following variant, ```.get<std::list>```, will also work.
```cpp
auto files = program.get<std::list<std::string>>("--input_files"); // {"config.yml", "System.xml"}
```
Using ```.scan```, one can quickly build a list of desired value types from command line arguments. Here's an example:
auto c = program.get<std::vector<float>>("-c"); // {1.95, 2.47}
/// Some code that prints parsed arguments
```
```console
foo@bar:/home/dev/$ ./main -ac 3.14 2.718
a = true
b = false
c = {3.14, 2.718}
foo@bar:/home/dev/$ ./main -cb
a = false
b = true
c = {0.0, 0.0}
```
Here's what's happening:
* We have three optional arguments ```-a```, ```-b``` and ```-c```.
* ```-a``` and ```-b``` are toggle arguments.
* ```-c``` requires 2 floating point numbers from the command-line.
* argparse can handle compound arguments, e.g., ```-abc``` or ```-bac``` or ```-cab```. This only works with short single-character argument names.
- ```-a``` and ```-b``` become true.
- argv is further parsed to identify the inputs mapped to ```-c```.
- If argparse cannot find any arguments to map to c, then c defaults to {0.0, 0.0} as defined by ```.default_value```
### Converting to Numeric Types
For inputs, users can express a primitive type for the value.
The ```.scan<Shape,T>``` method attempts to convert the incoming `std::string` to `T` following the `Shape` conversion specifier. An `std::invalid_argument` or `std::range_error` exception is thrown for errors.
```cpp
program.add_argument("-x")
.scan<'d', int>();
program.add_argument("scale")
.scan<'g', double>();
```
`Shape` specifies what the input "looks like", and the type template argument specifies the return value of the predefined action. Acceptable types are floating point (i.e float, double, long double) and integral (i.e. signed char, short, int, long, long long).
The grammar follows `std::from_chars`, but does not exactly duplicate it. For example, hexadecimal numbers may begin with `0x` or `0X` and numbers with a leading zero may be handled as octal values.
`argparse` provides predefined arguments and actions for `-h`/`--help` and `-v`/`--version`. By default, these actions will **exit** the program after displaying a help or version message, respectively. This exit does not call destructors, skipping clean-up of taken resources.
These default arguments can be disabled during `ArgumentParser` creation so that you can handle these arguments in your own way. (Note that a program name and version must be included when choosing default arguments.)
The above code snippet outputs a help message and continues to run. It does not support a `--version` argument.
The default is `default_arguments::all` for included arguments. No default arguments will be added with `default_arguments::none`. `default_arguments::help` and `default_arguments::version` will individually add `--help` and `--version`.
The default arguments can be used while disabling the default exit with these arguments. This forth argument to `ArgumentParser` (`exit_on_default_arguments`) is a bool flag with a default **true** value. The following call will retain `--help` and `--version`, but will not exit when those arguments are used.
foo@bar:/home/dev/$ ./compiler -o main foo.cpp bar.cpp baz.cpp
Output filename: main
3 files provided
foo.cpp
bar.cpp
baz.cpp
```
***NOTE***: Remember to place all optional arguments BEFORE the remaining argument. If the optional argument is placed after the remaining arguments, it too will be deemed remaining:
```console
foo@bar:/home/dev/$ ./compiler foo.cpp bar.cpp baz.cpp -o main
A parser may use arguments that could be used by other parsers.
These shared arguments can be added to a parser which is then used as a "parent" for parsers which also need those arguments. One or more parent parsers may be added to a parser with `.add_parents`. The positional and optional arguments in each parent is added to the child parser.
Changes made to parents after they are added to a parser are not reflected in any child parsers. Completely initialize parent parsers before adding them to a parser.
Each parser will have the standard set of default arguments. Disable the default arguments in parent parsers to avoid duplicate help output.
Many programs split up their functionality into a number of sub-commands, for example, the `git` program can invoke sub-commands like `git checkout`, `git add`, and `git commit`. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which require different kinds of command-line arguments. `ArgumentParser` supports the creation of such sub-commands with the `add_subparser()` member function.
```cpp
#include <argparse/argparse.hpp>
int main(int argc, char *argv[]) {
argparse::ArgumentParser program("git");
// git add subparser
argparse::ArgumentParser add_command("add");
add_command.add_description("Add file contents to the index");
add_command.add_argument("files")
.help("Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.")
-v, --version prints version information and exits
Subcommands:
add Add file contents to the index
cat-file Provide content or type and size information for repository objects
commit Record changes to the repository
submodule Initialize, update or inspect submodules
foo@bar:/home/dev/$ ./git add --help
Usage: add [-h] files
Add file contents to the index
Positional arguments:
files Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
foo@bar:/home/dev/$ ./git commit --help
Usage: commit [-h] [--all] [--message VAR]
Record changes to the repository
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
-a, --all Tell the command to automatically stage files that have been modified and deleted.
-m, --message Use the given <msg> as the commit message.
foo@bar:/home/dev/$ ./git submodule --help
Usage: submodule [-h] {update}
Initialize, update or inspect submodules
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
Subcommands:
update Update the registered submodules to match what the superproject expects
```
When a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages.
Additionally, every parser has the `.is_subcommand_used("<command_name>")` and `.is_subcommand_used(subparser)` member functions to check if a subcommand was used.
```Argument``` and ```ArgumentParser``` instances added to an ```ArgumentParser``` can be retrieved with ```.at<T>()```. The default return type is ```Argument```.
Sometimes a program may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the `parse_known_args()` function can be useful. It works much like `parse_args()` except that it does not produce an error when extra arguments are present. Instead, it returns a list of remaining argument strings.
Most command-line options will use `-` as the prefix, e.g. `-f/--foo`. Parsers that need to support different or additional prefix characters, e.g. for options like `+f` or `/foo`, may specify them using the `set_prefix_chars()`.