mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-01 13:13:53 +00:00
Adds @ComixHe as a contributor for code. This was requested by phlptp [in this comment](https://github.com/CLIUtils/CLI11/pull/1132#issuecomment-2702742598) [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
1891 lines
120 KiB
Markdown
1891 lines
120 KiB
Markdown
# CLI11: Command line parser for C++11
|
|
|
|

|
|
|
|
[![Build Status Azure][azure-badge]][azure]
|
|
[![Actions Status][actions-badge]][actions-link]
|
|
[![Code Coverage][codecov-badge]][codecov]
|
|
[![Codacy Badge][codacy-badge]][codacy-link]
|
|
[![License: BSD][license-badge]](./LICENSE) [![DOI][doi-badge]][doi-link]
|
|
|
|
[![Gitter chat][gitter-badge]][gitter]
|
|
[![Latest GHA release][releases-badge]][github releases]
|
|
[![Latest release][repology-badge]][repology]
|
|
[![Conan.io][conan-badge]][conan-link]
|
|
[![Conda Version][conda-badge]][conda-link]
|
|
[![Try CLI11 2.4 online][wandbox-badge]][wandbox-link]
|
|
|
|
[What's new](./CHANGELOG.md) • [Documentation][gitbook] • [API
|
|
Reference][api-docs]
|
|
|
|
CLI11 is a command line parser for C++11 and beyond that provides a rich feature
|
|
set with a simple and intuitive interface.
|
|
|
|
## Table of Contents
|
|
|
|
- [CLI11: Command line parser for C++11](#cli11-command-line-parser-for-c11)
|
|
- [Table of Contents](#table-of-contents)
|
|
- [Background](#background)
|
|
- [Introduction](#introduction)
|
|
- [Why write another CLI parser?](#why-write-another-cli-parser)
|
|
- [Other parsers](#other-parsers)
|
|
- [Features not supported by this library](#features-not-supported-by-this-library)
|
|
- [Install](#install)
|
|
- [Usage](#usage)
|
|
- [Adding options](#adding-options)
|
|
- [Option types](#option-types)
|
|
- [Example](#example)
|
|
- [Option options](#option-options)
|
|
- [Validators](#validators)
|
|
- [Transforming Validators](#transforming-validators)
|
|
- [Validator operations](#validator-operations)
|
|
- [Custom Validators](#custom-validators)
|
|
- [Querying Validators](#querying-validators)
|
|
- [Getting results](#getting-results)
|
|
- [Subcommands](#subcommands)
|
|
- [Subcommand options](#subcommand-options)
|
|
- [Callbacks](#callbacks)
|
|
- [Option groups](#option-groups)
|
|
- [Configuration file](#configuration-file)
|
|
- [Inheriting defaults](#inheriting-defaults)
|
|
- [Formatting](#formatting)
|
|
- [Subclassing](#subclassing)
|
|
- [How it works](#how-it-works)
|
|
- [Unicode support](#unicode-support)
|
|
- [Note on using Unicode paths](#note-on-using-unicode-paths)
|
|
- [Utilities](#utilities)
|
|
- [Other libraries](#other-libraries)
|
|
- [API](#api)
|
|
- [Examples](#examples)
|
|
- [Contribute](#contribute)
|
|
- [License](#license)
|
|
|
|
Features that were added in the last released minor version are marked with
|
|
"🆕". Features only available in main are marked with "🚧".
|
|
|
|
## Background
|
|
|
|
### Introduction
|
|
|
|
CLI11 provides all the features you expect in a powerful command line parser,
|
|
with a beautiful, minimal syntax and no dependencies beyond C++11. It is header
|
|
only, and comes in a single file form for easy inclusion in projects. It is easy
|
|
to use for small projects, but powerful enough for complex command line
|
|
projects, and can be customized for frameworks. It is tested on [Azure][] and
|
|
[GitHub Actions][actions-link], and was originally used by the [GooFit GPU
|
|
fitting framework][goofit]. It was inspired by [`plumbum.cli`][plumbum] for
|
|
Python. CLI11 has a user friendly introduction in this README, a more in-depth
|
|
tutorial [GitBook][], as well as [API documentation][api-docs] generated by
|
|
Travis. See the [changelog](./CHANGELOG.md) or [GitHub Releases][] for details
|
|
for current and past releases. Also see the [Version 1.0 post][], [Version 1.3
|
|
post][], [Version 1.6 post][], or [Version 2.0 post][] for more information.
|
|
|
|
You can be notified when new releases are made by subscribing to
|
|
<https://github.com/CLIUtils/CLI11/releases.atom> on an RSS reader, like Feedly,
|
|
or use the releases mode of the GitHub watching tool.
|
|
|
|
### Why write another CLI parser?
|
|
|
|
An acceptable CLI parser library should be all of the following:
|
|
|
|
- Easy to include (i.e., header only, one file if possible, **no external
|
|
requirements**).
|
|
- Short, simple syntax: This is one of the main reasons to use a CLI parser, it
|
|
should make variables from the command line nearly as easy to define as any
|
|
other variables. If most of your program is hidden in CLI parsing, this is a
|
|
problem for readability.
|
|
- C++11 or better: Should work with GCC 4.8+ (default on CentOS/RHEL 7), Clang
|
|
3.4+, AppleClang 7+, NVCC 7.0+, or MSVC 2015+.
|
|
- Work on Linux, macOS, and Windows.
|
|
- Well tested on all common platforms and compilers. "Well" is defined as having
|
|
good coverage measured by [CodeCov][].
|
|
- Clear help printing.
|
|
- Nice error messages.
|
|
- Standard shell idioms supported naturally, like grouping flags, a positional
|
|
separator, etc.
|
|
- Easy to execute, with help, parse errors, etc. providing correct exit and
|
|
details.
|
|
- Easy to extend as part of a framework that provides "applications" to users.
|
|
- Usable subcommand syntax, with support for multiple subcommands, nested
|
|
subcommands, option groups, and optional fallthrough (explained later).
|
|
- Ability to add a configuration file (`TOML`, `INI`, or custom format), and
|
|
produce it as well.
|
|
- Produce real values that can be used directly in code, not something you have
|
|
pay compute time to look up, for HPC applications.
|
|
- Work with common types, simple custom types, and extensible to exotic types.
|
|
- Permissively licensed.
|
|
|
|
### Other parsers
|
|
|
|
<details><summary>The major CLI parsers for C++ include, with my biased opinions: (click to expand)</summary><p>
|
|
|
|
| Library | My biased opinion |
|
|
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| [Boost Program Options][] | A great library if you already depend on Boost, but its pre-C++11 syntax is really odd and setting up the correct call in the main function is poorly documented (and is nearly a page of code). A simple wrapper for the Boost library was originally developed, but was discarded as CLI11 became more powerful. The idea of capturing a value and setting it originated with Boost PO. [See this comparison.][cli11-po-compare] |
|
|
| [The Lean Mean C++ Option Parser][] | One header file is great, but the syntax is atrocious, in my opinion. It was quite impractical to wrap the syntax or to use in a complex project. It seems to handle standard parsing quite well. |
|
|
| [TCLAP][] | The not-quite-standard command line parsing causes common shortcuts to fail. It also seems to be poorly supported, with only minimal bugfixes accepted. Header only, but in quite a few files. Has not managed to get enough support to move to GitHub yet. No subcommands. Produces wrapped values. |
|
|
| [Cxxopts][] | C++11, single file, and nice CMake support, but requires regex, therefore GCC 4.8 (CentOS 7 default) does not work. Syntax closely based on Boost PO, so not ideal but familiar. |
|
|
| [DocOpt][] | Completely different approach to program options in C++11, you write the docs and the interface is generated. Too fragile and specialized. |
|
|
|
|
After I wrote this, I also found the following libraries:
|
|
|
|
| Library | My biased opinion |
|
|
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| [GFlags][] | The Google Commandline Flags library. Uses macros heavily, and is limited in scope, missing things like subcommands. It provides a simple syntax and supports config files/env vars. |
|
|
| [GetOpt][] | Very limited C solution with long, convoluted syntax. Does not support much of anything, like help generation. Always available on UNIX, though (but in different flavors). |
|
|
| [ProgramOptions.hxx][] | Interesting library, less powerful and no subcommands. Nice callback system. |
|
|
| [Args][] | Also interesting, and supports subcommands. I like the optional-like design, but CLI11 is cleaner and provides direct value access, and is less verbose. |
|
|
| [Argument Aggregator][] | I'm a big fan of the [fmt][] library, and the try-catch statement looks familiar. :thumbsup: Doesn't seem to support subcommands. |
|
|
| [Clara][] | Simple library built for the excellent [Catch][] testing framework. Unique syntax, limited scope. |
|
|
| [Argh!][] | Very minimalistic C++11 parser, single header. Don't have many features. No help generation?!?! At least it's exception-free. |
|
|
| [CLI][] | Custom language and parser. Huge build-system overkill for very little benefit. Last release in 2009, but still occasionally active. |
|
|
| [argparse][] | C++17 single file argument parser. Design seems similar to CLI11 in some ways. The author has several other interesting projects. |
|
|
| [lyra][] | a simple header only parser with composable options. Might work well for simple standardized parsing |
|
|
|
|
See [Awesome C++][] for a less-biased list of parsers. You can also find other
|
|
single file libraries at [Single file libs][].
|
|
|
|
</p></details>
|
|
<br/>
|
|
|
|
None of these libraries fulfill all the above requirements, or really even come
|
|
close. As you probably have already guessed, CLI11 does. So, this library was
|
|
designed to provide a great syntax, good compiler compatibility, and minimal
|
|
installation fuss.
|
|
|
|
### Features not supported by this library
|
|
|
|
There are some other possible "features" that are intentionally not supported by
|
|
this library:
|
|
|
|
- Completion of partial options, such as Python's `argparse` supplies for
|
|
incomplete arguments. It's better not to guess. Most third party command line
|
|
parsers for python actually reimplement command line parsing rather than using
|
|
argparse because of this perceived design flaw (recent versions do have an
|
|
option to disable it).
|
|
- Autocomplete: This might eventually be added to both Plumbum and CLI11, but it
|
|
is not supported yet.
|
|
- While not recommended, CLI11 does now support non standard option names such
|
|
as `-option`. 🆕. This is enabled through `allow_non_standard_option_names()`
|
|
modifier on an app.
|
|
|
|
## Install
|
|
|
|
To use, the most common methods are described here additional methods and
|
|
details are available at [installation][]:
|
|
|
|
- All-in-one local header: Copy `CLI11.hpp` from the [most recent
|
|
release][github releases] into your include directory, and you are set. This
|
|
is combined from the source files for every release. This includes the entire
|
|
command parser library, but does not include separate utilities (like `Timer`,
|
|
`AutoTimer`). The utilities are completely self contained and can be copied
|
|
separately.
|
|
- All-in-one global header: Like above, but copying the file to a shared folder
|
|
location like `/opt/CLI11`. Then, the C++ include path has to be extended to
|
|
point at this folder. With CMake 3.10+, use `include_directories(/opt/CLI11)`
|
|
- For other methods including using CMake, conan or vcpkg and some specific
|
|
instructions for GCC 8 or WASI see [installation][].
|
|
|
|
## Usage
|
|
|
|
### Adding options
|
|
|
|
To set up, add options, and run, your main function will look something like
|
|
this:
|
|
|
|
```cpp
|
|
int main(int argc, char** argv) {
|
|
CLI::App app{"App description"};
|
|
argv = app.ensure_utf8(argv);
|
|
|
|
std::string filename = "default";
|
|
app.add_option("-f,--file", filename, "A help string");
|
|
|
|
CLI11_PARSE(app, argc, argv);
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
For more information about `ensure_utf8` the section on
|
|
[Unicode support](#unicode-support) below.
|
|
|
|
<details><summary>Note: If you don't like macros, this is what that macro expands to: (click to expand)</summary><p>
|
|
|
|
```cpp
|
|
try {
|
|
app.parse(argc, argv);
|
|
} catch (const CLI::ParseError &e) {
|
|
return app.exit(e);
|
|
}
|
|
```
|
|
|
|
The try/catch block ensures that `-h,--help` or a parse error will exit with the
|
|
correct return code (selected from `CLI::ExitCodes`). (The return here should be
|
|
inside `main`). You should not assume that the option values have been set
|
|
inside the catch block; for example, help flags intentionally short-circuit all
|
|
other processing for speed and to ensure required options and the like do not
|
|
interfere.
|
|
|
|
</p></details>
|
|
</br>
|
|
|
|
The initialization is just one line, adding options is just two each. The parse
|
|
macro is just one line (or 5 for the contents of the macro). After the app runs,
|
|
the filename will be set to the correct value if it was passed, otherwise it
|
|
will be set to the default. You can check to see if this was passed on the
|
|
command line with `app.count("--file")`.
|
|
|
|
#### Option types
|
|
|
|
While all options internally are the same type, there are several ways to add an
|
|
option depending on what you need. The supported values are:
|
|
|
|
```cpp
|
|
// Add options
|
|
app.add_option(option_name, help_str="")
|
|
|
|
app.add_option(option_name,
|
|
variable_to_bind_to, // bool, char(see note), int, float, vector, enum, std::atomic, or string-like, or anything with a defined conversion from a string or that takes an int, double, or string in a constructor. Also allowed are tuples, std::array or std::pair. Also supported are complex numbers, wrapper types, and containers besides vectors of any other supported type.
|
|
help_string="")
|
|
|
|
app.add_option_function<type>(option_name,
|
|
function <void(const type &value)>, // type can be any type supported by add_option
|
|
help_string="")
|
|
|
|
// char as an option type is supported before 2.0 but in 2.0 it defaulted to allowing single non numerical characters in addition to the numeric values.
|
|
|
|
// There is a template overload which takes two template parameters the first is the type of object to assign the value to, the second is the conversion type. The conversion type should have a known way to convert from a string, such as any of the types that work in the non-template version. If XC is a std::pair and T is some non pair type. Then a two argument constructor for T is called to assign the value. For tuples or other multi element types, XC must be a single type or a tuple like object of the same size as the assignment type
|
|
app.add_option<typename T, typename XC>(option_name,
|
|
T &output, // output must be assignable or constructible from a value of type XC
|
|
help_string="")
|
|
|
|
// Add flags
|
|
app.add_flag(option_name,
|
|
help_string="")
|
|
|
|
app.add_flag(option_name,
|
|
variable_to_bind_to, // bool, int, float, complex, containers, enum, std::atomic, or string-like, or any singular object with a defined conversion from a string like add_option
|
|
help_string="")
|
|
|
|
app.add_flag_function(option_name,
|
|
function <void(std::int64_t count)>,
|
|
help_string="")
|
|
|
|
app.add_flag_callback(option_name,function<void(void)>,help_string="")
|
|
|
|
// Add subcommands
|
|
App* subcom = app.add_subcommand(name, description);
|
|
|
|
Option_group *app.add_option_group(name,description);
|
|
```
|
|
|
|
An option name may start with any character except ('-', ' ', '\n', and '!').
|
|
For long options, after the first character all characters are allowed except
|
|
('=',':','{',' ', '\n'). For the `add_flag*` functions '{' and '!' have special
|
|
meaning which is why they are not allowed. Names are given as a comma separated
|
|
string, with the dash or dashes. An option or flag can have as many names as you
|
|
want, and afterward, using `count`, you can use any of the names, with dashes as
|
|
needed, to count the options. One of the names is allowed to be given without
|
|
proceeding dash(es); if present the option is a positional option, and that name
|
|
will be used on the help line for its positional form. The string `++` is also
|
|
not allowed as option name due to its use as an array separator and marker on
|
|
config files.
|
|
|
|
The `add_option_function<type>(...` function will typically require the template
|
|
parameter be given unless a `std::function` object with an exact match is
|
|
passed. The type can be any type supported by the `add_option` function. The
|
|
function should throw an error (`CLI::ConversionError` or `CLI::ValidationError`
|
|
possibly) if the value is not valid.
|
|
|
|
The two parameter template overload can be used in cases where you want to
|
|
restrict the input such as
|
|
|
|
```cpp
|
|
double val
|
|
app.add_option<double,unsigned int>("-v",val);
|
|
```
|
|
|
|
which would first verify the input is convertible to an `unsigned int` before
|
|
assigning it. Or using some variant type
|
|
|
|
```cpp
|
|
using vtype=std::variant<int, double, std::string>;
|
|
vtype v1;
|
|
app.add_option<vtype,std:string>("--vs",v1);
|
|
app.add_option<vtype,int>("--vi",v1);
|
|
app.add_option<vtype,double>("--vf",v1);
|
|
```
|
|
|
|
otherwise the output would default to a string. The `add_option` can be used
|
|
with any integral or floating point types, enumerations, or strings. Or any type
|
|
that takes an int, double, or std\::string in an assignment operator or
|
|
constructor. If an object can take multiple varieties of those, std::string
|
|
takes precedence, then double then int. To better control which one is used or
|
|
to use another type for the underlying conversions use the two parameter
|
|
template to directly specify the conversion type.
|
|
|
|
Types such as (std or boost) `optional<int>`, `optional<double>`, and
|
|
`optional<string>` and any other wrapper types are supported directly. For
|
|
purposes of CLI11 wrapper types are those which `value_type` definition. See
|
|
[CLI11 Advanced Topics/Custom Converters][] for information on how you can add
|
|
your own converters for additional types.
|
|
|
|
Vector types can also be used in the two parameter template overload
|
|
|
|
```cpp
|
|
std::vector<double> v1;
|
|
app.add_option<std::vector<double>,int>("--vs",v1);
|
|
```
|
|
|
|
would load a vector of doubles but ensure all values can be represented as
|
|
integers.
|
|
|
|
Automatic direct capture of the default string is disabled when using the two
|
|
parameter template. Use `set_default_str(...)` or
|
|
`->default_function(std::string())` to set the default string or capture
|
|
function directly for these cases.
|
|
|
|
Flag options specified through the `add_flag*` functions allow a syntax for the
|
|
option names to default particular options to a false value or any other value
|
|
if some flags are passed. For example:
|
|
|
|
```cpp
|
|
app.add_flag("--flag,!--no-flag",result,"help for flag");
|
|
```
|
|
|
|
specifies that if `--flag` is passed on the command line result will be true or
|
|
contain a value of 1. If `--no-flag` is passed `result` will contain false or -1
|
|
if `result` is a signed integer type, or 0 if it is an unsigned type. An
|
|
alternative form of the syntax is more explicit: `"--flag,--no-flag{false}"`;
|
|
this is equivalent to the previous example. This also works for short form
|
|
options `"-f,!-n"` or `"-f,-n{false}"`. If `variable_to_bind_to` is anything but
|
|
an integer value the default behavior is to take the last value given, while if
|
|
`variable_to_bind_to` is an integer type the behavior will be to sum all the
|
|
given arguments and return the result. This can be modified if needed by
|
|
changing the `multi_option_policy` on each flag (this is not inherited). The
|
|
default value can be any value. For example if you wished to define a numerical
|
|
flag:
|
|
|
|
```cpp
|
|
app.add_flag("-1{1},-2{2},-3{3}",result,"numerical flag")
|
|
```
|
|
|
|
Using any of those flags on the command line will result in the specified number
|
|
in the output. Similar things can be done for string values, and enumerations,
|
|
as long as the default value can be converted to the given type.
|
|
|
|
On a `C++14` compiler, you can pass a callback function directly to `.add_flag`,
|
|
while in C++11 mode you'll need to use `.add_flag_function` if you want a
|
|
callback function. The function will be given the number of times the flag was
|
|
passed. You can throw a relevant `CLI::ParseError` to signal a failure.
|
|
|
|
#### Example
|
|
|
|
- `"one,-o,--one"`: Valid as long as not a flag, would create an option that can
|
|
be specified positionally, or with `-o` or `--one`
|
|
- `"this"` Can only be passed positionally
|
|
- `"-a,-b,-c"` No limit to the number of non-positional option names
|
|
|
|
The add commands return a pointer to an internally stored `Option`. This option
|
|
can be used directly to check for the count (`->count()`) after parsing to avoid
|
|
a string based lookup.
|
|
|
|
#### Option options
|
|
|
|
Before parsing, you can set the following options:
|
|
|
|
- `->required()`: The program will quit if this option is not present. This is
|
|
`mandatory` in Plumbum, but required options seems to be a more standard term.
|
|
For compatibility, `->mandatory()` also works.
|
|
- `->expected(N)`: Take `N` values instead of as many as possible, only for
|
|
vector args. If negative, require at least `-N`; end with `--` or another
|
|
recognized option or subcommand.
|
|
- `->expected(MIN,MAX)`: Set a range of expected values to accompany an option.
|
|
`expected(0,1)` is the equivalent of making a flag.
|
|
- `->type_name(typename)`: Set the name of an Option's type (`type_name_fn`
|
|
allows a function instead)
|
|
- `->type_size(N)`: Set the intrinsic size of an option value. The parser will
|
|
require multiples of this number if negative. Most of the time this is
|
|
detected automatically though can be modified for specific use cases.
|
|
- `->type_size(MIN,MAX)`: Set the intrinsic size of an option to a range.
|
|
- `->needs(opt)`: This option requires another option to also be present, opt is
|
|
an `Option` pointer. Options can be removed from the `needs` with
|
|
`remove_needs(opt)`. The option can also be specified with a string containing
|
|
the name of the option
|
|
- `->excludes(opt)`: This option cannot be given with `opt` present, opt is an
|
|
`Option` pointer. Can also be given as a string containing the name of the
|
|
option. Options can be removed from the excludes list with
|
|
`->remove_excludes(opt)`
|
|
- `->envname(name)`: Gets the value from the environment if present and not
|
|
passed on the command line. The value must also pass any validators to be
|
|
used.
|
|
- `->group(name)`: The help group to put the option in. No effect for positional
|
|
options. Defaults to `"Options"`. Options given an empty string will not show
|
|
up in the help print (hidden).
|
|
- `->ignore_case()`: Ignore the case on the command line (also works on
|
|
subcommands, does not affect arguments).
|
|
- `->ignore_underscore()`: Ignore any underscores in the options names (also
|
|
works on subcommands, does not affect arguments). For example "option_one"
|
|
will match with "optionone". This does not apply to short form options since
|
|
they only have one character
|
|
- `->disable_flag_override()`: From the command line long form flag options can
|
|
be assigned a value on the command line using the `=` notation `--flag=value`.
|
|
If this behavior is not desired, the `disable_flag_override()` disables it and
|
|
will generate an exception if it is done on the command line. The `=` does not
|
|
work with short form flag options.
|
|
- `->allow_extra_args(true/false)`: If set to true the option will take an
|
|
unlimited number of arguments like a vector, if false it will limit the number
|
|
of arguments to the size of the type used in the option. Default value depends
|
|
on the nature of the type use, containers default to true, others default to
|
|
false.
|
|
- `->delimiter(char)`: Allows specification of a custom delimiter for separating
|
|
single arguments into vector arguments, for example specifying
|
|
`->delimiter(',')` on an option would result in `--opt=1,2,3` producing 3
|
|
elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a
|
|
vector value.
|
|
- `->description(str)`: Set/change the description.
|
|
- `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option
|
|
policy. Shortcuts available: `->take_last()`, `->take_first()`,`->take_all()`,
|
|
and `->join()`. This will only affect options expecting 1 argument or bool
|
|
flags (which do not inherit their default but always start with a specific
|
|
policy). `->join(delim)` can also be used to join with a specific delimiter.
|
|
This equivalent to calling `->delimiter(delim)` and `->join()`. Valid values
|
|
are `CLI::MultiOptionPolicy::Throw`, `CLI::MultiOptionPolicy::Throw`,
|
|
`CLI::MultiOptionPolicy::TakeLast`, `CLI::MultiOptionPolicy::TakeFirst`,
|
|
`CLI::MultiOptionPolicy::Join`, `CLI::MultiOptionPolicy::TakeAll`,
|
|
`CLI::MultiOptionPolicy::Sum`, and `CLI::MultiOptionPolicy::Reverse`.
|
|
- `->check(std::string(const std::string &), validator_name="",validator_description="")`:
|
|
Define a check function. The function should return a non empty string with
|
|
the error message if the check fails
|
|
- `->check(Validator)`: Use a Validator object to do the check see
|
|
[Validators](#validators) for a description of available Validators and how to
|
|
create new ones.
|
|
- `->transform(std::string(std::string &), validator_name="",validator_description=")`:
|
|
Converts the input string into the output string, in-place in the parsed
|
|
options.
|
|
- `->transform(Validator)`: Uses a Validator object to do the transformation see
|
|
[Validators](#validators) for a description of available Validators and how to
|
|
create new ones.
|
|
- `->each(void(const std::string &)>`: Run this function on each value received,
|
|
as it is received. It should throw a `ValidationError` if an error is
|
|
encountered.
|
|
- `->configurable(false)`: Disable this option from being in a configuration
|
|
file.
|
|
- `->capture_default_str()`: Store the current value attached and display it in
|
|
the help string.
|
|
- `->default_function(std::string())`: Advanced: Change the function that
|
|
`capture_default_str()` uses.
|
|
- `->always_capture_default()`: Always run `capture_default_str()` when creating
|
|
new options. Only useful on an App's `option_defaults`.
|
|
- `->default_str(string)`: Set the default string directly (NO VALIDATION OR
|
|
CALLBACKS). This string will also be used as a default value if no arguments
|
|
are passed and the value is requested.
|
|
- `->default_val(value)`: Generate the default string from a value and validate
|
|
that the value is also valid. For options that assign directly to a value type
|
|
the value in that type is also updated. Value must be convertible to a
|
|
string(one of known types or have a stream operator). The callback may be
|
|
triggered if the `run_callback_for_default` is set.
|
|
- `->run_callback_for_default()`: This will force the option callback to be
|
|
executed or the variable set when the `default_val` is set.
|
|
- `->option_text(string)`: Sets the text between the option name and
|
|
description.
|
|
- `->force_callback()`: Causes the option callback or value set to be triggered
|
|
even if the option was not present in parsing.
|
|
- `->trigger_on_parse()`: If set, causes the callback and all associated
|
|
validation checks for the option to be executed when the option value is
|
|
parsed vs. at the end of all parsing. This could cause the callback to be
|
|
executed multiple times. Also works with positional options.
|
|
|
|
These options return the `Option` pointer, so you can chain them together, and
|
|
even skip storing the pointer entirely. The `each` function takes any function
|
|
that has the signature `void(const std::string&)`; it should throw a
|
|
`ValidationError` when validation fails. The help message will have the name of
|
|
the parent option prepended. Since `each`, `check` and `transform` use the same
|
|
underlying mechanism, you can chain as many as you want, and they will be
|
|
executed in order. Operations added through `transform` are executed first in
|
|
reverse order of addition, and `check` and `each` are run following the
|
|
transform functions in order of addition. If you just want to see the
|
|
unconverted values, use `.results()` to get the `std::vector<std::string>` of
|
|
results.
|
|
|
|
On the command line, options can be given as:
|
|
|
|
- `-a` (flag)
|
|
- `-abc` (flags can be combined)
|
|
- `-f filename` (option)
|
|
- `-ffilename` (no space required)
|
|
- `-abcf filename` (flags and option can be combined)
|
|
- `--long` (long flag)
|
|
- `--long_flag=true` (long flag with equals -- to override default value)
|
|
- `--file filename` (space)
|
|
- `--file=filename` (equals)
|
|
|
|
If `allow_windows_style_options()` is specified in the application or subcommand
|
|
options can also be given as:
|
|
|
|
- `/a` (flag)
|
|
- `/f filename` (option)
|
|
- `/long` (long flag)
|
|
- `/file filename` (space)
|
|
- `/file:filename` (colon)
|
|
- `/long_flag:false` (long flag with : to override the default value)
|
|
- Windows style options do not allow combining short options or values not
|
|
separated from the short option like with `-` options
|
|
|
|
Long flag options may be given with an `=<value>` to allow specifying a false
|
|
value, or some other value to the flag. See [config files](#configuration-file)
|
|
for details on the values supported. NOTE: only the `=` or `:` for windows-style
|
|
options may be used for this, using a space will result in the argument being
|
|
interpreted as a positional argument. This syntax can override the default
|
|
values, and can be disabled by using `disable_flag_override()`.
|
|
|
|
Extra positional arguments will cause the program to exit, so at least one
|
|
positional option with a vector is recommended if you want to allow extraneous
|
|
arguments. If you set `.allow_extras()` on the main `App`, you will not get an
|
|
error. You can access the missing options using `remaining` (if you have
|
|
subcommands, `app.remaining(true)` will get all remaining options, subcommands
|
|
included). If the remaining arguments are to processed by another `App` then the
|
|
function `remaining_for_passthrough()` can be used to get the remaining
|
|
arguments in reverse order such that `app.parse(vector)` works directly and
|
|
could even be used inside a subcommand callback.
|
|
|
|
You can access a vector of pointers to the parsed options in the original order
|
|
using `parse_order()`. If `--` is present in the command line that does not end
|
|
an unlimited option, then everything after that is positional only.
|
|
|
|
#### Validators
|
|
|
|
Validators are structures to check or modify inputs, they can be used to verify
|
|
that an input meets certain criteria or transform it into another value. They
|
|
are added through the `check` or `transform` functions. The differences between
|
|
the two function are that checks do not modify the input whereas transforms can
|
|
and are executed before any Validators added through `check`.
|
|
|
|
CLI11 has several Validators built-in that perform some common checks
|
|
|
|
- `CLI::IsMember(...)`: Require an option be a member of a given set. See
|
|
[Transforming Validators](#transforming-validators) for more details.
|
|
- `CLI::Transformer(...)`: Modify the input using a map. See
|
|
[Transforming Validators](#transforming-validators) for more details.
|
|
- `CLI::CheckedTransformer(...)`: Modify the input using a map, and require that
|
|
the input is either in the set or already one of the outputs of the set. See
|
|
[Transforming Validators](#transforming-validators) for more details.
|
|
- `CLI::AsNumberWithUnit(...)`: Modify the `<NUMBER> <UNIT>` pair by matching
|
|
the unit and multiplying the number by the corresponding factor. It can be
|
|
used as a base for transformers, that accept things like size values (`1 KB`)
|
|
or durations (`0.33 ms`).
|
|
- `CLI::AsSizeValue(...)`: Convert inputs like `100b`, `42 KB`, `101 Mb`,
|
|
`11 Mib` to absolute values. `KB` can be configured to be interpreted as 10^3
|
|
or 2^10.
|
|
- `CLI::ExistingFile`: Requires that the file exists if given.
|
|
- `CLI::ExistingDirectory`: Requires that the directory exists.
|
|
- `CLI::ExistingPath`: Requires that the path (file or directory) exists.
|
|
- `CLI::NonexistentPath`: Requires that the path does not exist.
|
|
- `CLI::FileOnDefaultPath`: Best used as a transform, Will check that a file
|
|
exists either directly or in a default path and update the path appropriately.
|
|
See [Transforming Validators](#transforming-validators) for more details
|
|
- `CLI::Range(min,max)`: Requires that the option be between min and max (make
|
|
sure to use floating point if needed). Min defaults to 0.
|
|
- `CLI::Bounded(min,max)`: Modify the input such that it is always between min
|
|
and max (make sure to use floating point if needed). Min defaults to 0. Will
|
|
produce an error if conversion is not possible.
|
|
- `CLI::PositiveNumber`: Requires the number be greater than 0
|
|
- `CLI::NonNegativeNumber`: Requires the number be greater or equal to 0
|
|
- `CLI::Number`: Requires the input be a number.
|
|
- `CLI::ValidIPV4`: Requires that the option be a valid IPv4 string e.g.
|
|
`'255.255.255.255'`, `'10.1.1.7'`.
|
|
- `CLI::TypeValidator<TYPE>`:Requires that the option be convertible to the
|
|
specified type e.g. `CLI::TypeValidator<unsigned int>()` would require that
|
|
the input be convertible to an `unsigned int` regardless of the end
|
|
conversion.
|
|
|
|
These Validators can be used by simply passing the name into the `check` or
|
|
`transform` methods on an option
|
|
|
|
```cpp
|
|
->check(CLI::ExistingFile);
|
|
->check(CLI::Range(0,10));
|
|
```
|
|
|
|
Validators can be merged using `&` and `|` and inverted using `!`. For example:
|
|
|
|
```cpp
|
|
->check(CLI::Range(0,10)|CLI::Range(20,30));
|
|
```
|
|
|
|
will produce a check to ensure a value is between 0 and 10 or 20 and 30.
|
|
|
|
```cpp
|
|
->check(!CLI::PositiveNumber);
|
|
```
|
|
|
|
will produce a check for a number less than or equal to 0.
|
|
|
|
##### Transforming Validators
|
|
|
|
There are a few built in Validators that let you transform values if used with
|
|
the `transform` function. If they also do some checks then they can be used
|
|
`check` but some may do nothing in that case.
|
|
|
|
- `CLI::Bounded(min,max)` will bound values between min and max and values
|
|
outside of that range are limited to min or max, it will fail if the value
|
|
cannot be converted and produce a `ValidationError`
|
|
- The `IsMember` Validator lets you specify a set of predefined options. You can
|
|
pass any container or copyable pointer (including `std::shared_ptr`) to a
|
|
container to this Validator; the container just needs to be iterable and have
|
|
a `::value_type`. The key type should be convertible from a string, You can
|
|
use an initializer list directly if you like. If you need to modify the set
|
|
later, the pointer form lets you do that; the type message and check will
|
|
correctly refer to the current version of the set. The container passed in can
|
|
be a set, vector, or a map like structure. If used in the `transform` method
|
|
the output value will be the matching key as it could be modified by filters.
|
|
|
|
After specifying a set of options, you can also specify "filter" functions of
|
|
the form `T(T)`, where `T` is the type of the values. The most common choices
|
|
probably will be `CLI::ignore_case` an `CLI::ignore_underscore`, and
|
|
`CLI::ignore_space`. These all work on strings but it is possible to define
|
|
functions that work on other types. Here are some examples of `IsMember`:
|
|
|
|
- `CLI::IsMember({"choice1", "choice2"})`: Select from exact match to choices.
|
|
- `CLI::IsMember({"choice1", "choice2"}, CLI::ignore_case, CLI::ignore_underscore)`:
|
|
Match things like `Choice_1`, too.
|
|
- `CLI::IsMember(std::set<int>({2,3,4}))`: Most containers and types work; you
|
|
just need `std::begin`, `std::end`, and `::value_type`.
|
|
- `CLI::IsMember(std::map<std::string, TYPE>({{"one", 1}, {"two", 2}}))`: You
|
|
can use maps; in `->transform()` these replace the matched value with the
|
|
matched key. The value member of the map is not used in `IsMember`, so it can
|
|
be any type.
|
|
- `auto p = std::make_shared<std::vector<std::string>>(std::initializer_list<std::string>("one", "two")); CLI::IsMember(p)`:
|
|
You can modify `p` later.
|
|
- The `Transformer` and `CheckedTransformer` Validators transform one value into
|
|
another. Any container or copyable pointer (including `std::shared_ptr`) to a
|
|
container that generates pairs of values can be passed to these `Validator's`;
|
|
the container just needs to be iterable and have a `::value_type` that
|
|
consists of pairs. The key type should be convertible from a string, and the
|
|
value type should be convertible to a string You can use an initializer list
|
|
directly if you like. If you need to modify the map later, the pointer form
|
|
lets you do that; the description message will correctly refer to the current
|
|
version of the map. `Transformer` does not do any checking so values not in
|
|
the map are ignored. `CheckedTransformer` takes an extra step of verifying
|
|
that the value is either one of the map key values, in which case it is
|
|
transformed, or one of the expected output values, and if not will generate a
|
|
`ValidationError`. A Transformer placed using `check` will not do anything.
|
|
|
|
After specifying a map of options, you can also specify "filter" just like in
|
|
`CLI::IsMember`. Here are some examples (`Transformer` and `CheckedTransformer`
|
|
are interchangeable in the examples) of `Transformer`:
|
|
|
|
- `CLI::Transformer({{"key1", "map1"},{"key2","map2"}})`: Select from key values
|
|
and produce map values.
|
|
- `CLI::Transformer(std::map<std::string,int>({"two",2},{"three",3},{"four",4}}))`:
|
|
most maplike containers work, the `::value_type` needs to produce a pair of
|
|
some kind.
|
|
- `CLI::CheckedTransformer(std::map<std::string, int>({{"one", 1}, {"two", 2}}))`:
|
|
You can use maps; in `->transform()` these replace the matched key with the
|
|
value. `CheckedTransformer` also requires that the value either match one of
|
|
the keys or match one of known outputs.
|
|
- `auto p = std::make_shared<CLI::TransformPairs<std::string>>(std::initializer_list<std::pair<std::string,std::string>>({"key1", "map1"},{"key2","map2"})); CLI::Transformer(p)`:
|
|
You can modify `p` later. `TransformPairs<T>` is an alias for
|
|
`std::vector<std::pair<<std::string,T>>`
|
|
|
|
NOTES: If the container used in `IsMember`, `Transformer`, or
|
|
`CheckedTransformer` has a `find` function like `std::unordered_map` or
|
|
`std::map` then that function is used to do the searching. If it does not have a
|
|
`find` function a linear search is performed. If there are filters present, the
|
|
fast search is performed first, and if that fails a linear search with the
|
|
filters on the key values is performed.
|
|
|
|
- `CLI::FileOnDefaultPath(default_path)`: can be used to check for files in a
|
|
default path. If used as a transform it will first check that a file exists,
|
|
if it does nothing further is done, if it does not it tries to add a default
|
|
Path to the file and search there again. If the file does not exist an error
|
|
is returned normally but this can be disabled using
|
|
`CLI::FileOnDefaultPath(default_path, false)`. This allows multiple paths to
|
|
be chained using multiple transform calls.
|
|
|
|
- `CLI::EscapedString`: can be used to process an escaped string. The processing
|
|
is equivalent to that used for TOML config files, see
|
|
[TOML strings](https://toml.io/en/v1.0.0#string). With 2 notable exceptions.
|
|
\` can also be used as a literal string notation, and it also allows binary
|
|
string notation see
|
|
[binary strings](https://cliutils.github.io/CLI11/book/chapters/config.html).
|
|
The escaped string processing will remove outer quotes if present, `"` will
|
|
indicate a string with potential escape sequences, `'` and \` will indicate a
|
|
literal string and the quotes removed but no escape sequences will be
|
|
processed. This is the same escape processing as used in config files.
|
|
|
|
##### Validator operations
|
|
|
|
Validators are copyable and have a few operations that can be performed on them
|
|
to alter settings. Most of the built in Validators have a default description
|
|
that is displayed in the help. This can be altered via
|
|
`.description(validator_description)`. The name of a Validator, which is useful
|
|
for later reference from the `get_validator(name)` method of an `Option` can be
|
|
set via `.name(validator_name)` The operation function of a Validator can be set
|
|
via `.operation(std::function<std::string(std::string &>)`. The `.active()`
|
|
function can activate or deactivate a Validator from the operation. A validator
|
|
can be set to apply only to a specific element of the output. For example in a
|
|
pair option `std::pair<int, std::string>` the first element may need to be a
|
|
positive integer while the second may need to be a valid file. The
|
|
`.application_index(int)` function can specify this. It is zero based and
|
|
negative indices apply to all values.
|
|
|
|
```cpp
|
|
opt->check(CLI::Validator(CLI::PositiveNumber).application_index(0));
|
|
opt->check(CLI::Validator(CLI::ExistingFile).application_index(1));
|
|
```
|
|
|
|
All the validator operation functions return a Validator reference allowing them
|
|
to be chained. For example
|
|
|
|
```cpp
|
|
opt->check(CLI::Range(10,20).description("range is limited to sensible values").active(false).name("range"));
|
|
```
|
|
|
|
will specify a check on an option with a name "range", but deactivate it for the
|
|
time being. The check can later be activated through
|
|
|
|
```cpp
|
|
opt->get_validator("range")->active();
|
|
```
|
|
|
|
##### Custom Validators
|
|
|
|
A validator object with a custom function can be created via
|
|
|
|
```cpp
|
|
CLI::Validator(std::function<std::string(std::string &)>,validator_description,validator_name="");
|
|
```
|
|
|
|
or if the operation function is set later they can be created with
|
|
|
|
```cpp
|
|
CLI::Validator(validator_description);
|
|
```
|
|
|
|
It is also possible to create a subclass of `CLI::Validator`, in which case it
|
|
can also set a custom description function, and operation function.
|
|
|
|
##### Querying Validators
|
|
|
|
Once loaded into an Option, a pointer to a named Validator can be retrieved via
|
|
|
|
```cpp
|
|
opt->get_validator(name);
|
|
```
|
|
|
|
This will retrieve a Validator with the given name or throw a
|
|
`CLI::OptionNotFound` error. If no name is given or name is empty the first
|
|
unnamed Validator will be returned or the first Validator if there is only one.
|
|
|
|
or
|
|
|
|
```cpp
|
|
opt->get_validator(index);
|
|
```
|
|
|
|
Which will return a validator in the index it is applied which isn't necessarily
|
|
the order in which was defined. The pointer can be `nullptr` if an invalid index
|
|
is given. Validators have a few functions to query the current values:
|
|
|
|
- `get_description()`: Will return a description string
|
|
- `get_name()`: Will return the Validator name
|
|
- `get_active()`: Will return the current active state, true if the Validator is
|
|
active.
|
|
- `get_application_index()`: Will return the current application index.
|
|
- `get_modifying()`: Will return true if the Validator is allowed to modify the
|
|
input, this can be controlled via the `non_modifying()` method, though it is
|
|
recommended to let `check` and `transform` option methods manipulate it if
|
|
needed.
|
|
|
|
#### Getting results
|
|
|
|
In most cases, the fastest and easiest way is to return the results through a
|
|
callback or variable specified in one of the `add_*` functions. But there are
|
|
situations where this is not possible or desired. For these cases the results
|
|
may be obtained through one of the following functions. Please note that these
|
|
functions will do any type conversions and processing during the call so should
|
|
not used in performance critical code:
|
|
|
|
- `->results()`: Retrieves a vector of strings with all the results in the order
|
|
they were given.
|
|
- `->results(variable_to_bind_to)`: Gets the results according to the
|
|
MultiOptionPolicy and converts them just like the `add_option_function` with a
|
|
variable.
|
|
- `Value=opt->as<type>()`: Returns the result or default value directly as the
|
|
specified type if possible, can be vector to return all results, and a
|
|
non-vector to get the result according to the MultiOptionPolicy in place.
|
|
|
|
### Subcommands
|
|
|
|
Subcommands are keywords that invoke a new set of options and features. For
|
|
example, the `git` command has a long series of subcommands, like `add` and
|
|
`commit`. Each can have its own options and implementations. Subcommands are
|
|
supported in CLI11, and can be nested infinitely. To add a subcommand, call the
|
|
`add_subcommand` method with a name and an optional description. This gives a
|
|
pointer to an `App` that behaves just like the main app, and can take options or
|
|
further subcommands. Add `->ignore_case()` to a subcommand to allow any
|
|
variation of caps to also be accepted. `->ignore_underscore()` is similar, but
|
|
for underscores. Children inherit the current setting from the parent. You
|
|
cannot add multiple matching subcommand names at the same level (including
|
|
`ignore_case` and `ignore_underscore`).
|
|
|
|
If you want to require that at least one subcommand is given, use
|
|
`.require_subcommand()` on the parent app. You can optionally give an exact
|
|
number of subcommands to require, as well. If you give two arguments, that sets
|
|
the min and max number allowed. 0 for the max number allowed will allow an
|
|
unlimited number of subcommands. As a handy shortcut, a single negative value N
|
|
will set "up to N" values. Limiting the maximum number allows you to keep
|
|
arguments that match a previous subcommand name from matching.
|
|
|
|
If an `App` (main or subcommand) has been parsed on the command line, `->parsed`
|
|
will be true (or convert directly to bool). All `App`s have a
|
|
`get_subcommands()` method, which returns a list of pointers to the subcommands
|
|
passed on the command line. A `got_subcommand(App_or_name)` method is also
|
|
provided that will check to see if an `App` pointer or a string name was
|
|
collected on the command line.
|
|
|
|
For many cases, however, using an app's callback capabilities may be easier.
|
|
Every app has a set of callbacks that can be executed at various stages of
|
|
parsing; a `C++` lambda function (with capture to get parsed values) can be used
|
|
as input to the callback definition function. If you throw `CLI::Success` or
|
|
`CLI::RuntimeError(return_value)`, you can even exit the program through the
|
|
callback.
|
|
|
|
Multiple subcommands are allowed, to allow [`Click`][click] like series of
|
|
commands (order is preserved). The same subcommand can be triggered multiple
|
|
times but all positional arguments will take precedence over the second and
|
|
future calls of the subcommand. `->count()` on the subcommand will return the
|
|
number of times the subcommand was called. The subcommand callback will only be
|
|
triggered once unless the `.immediate_callback()` flag is set or the callback is
|
|
specified through the `parse_complete_callback()` function. The
|
|
`final_callback()` is triggered only once. In which case the callback executes
|
|
on completion of the subcommand arguments but after the arguments for that
|
|
subcommand have been parsed, and can be triggered multiple times. Note that the
|
|
`parse_complete_callback()` is executed prior to processing any config files.
|
|
The `final_callback()` is executed after config file processing.
|
|
|
|
Subcommands may also have an empty name either by calling `add_subcommand` with
|
|
an empty string for the name or with no arguments. Nameless subcommands function
|
|
a similarly to groups in the main `App`. See [Option groups](#option-groups) to
|
|
see how this might work. If an option is not defined in the main App, all
|
|
nameless subcommands are checked as well. This allows for the options to be
|
|
defined in a composable group. The `add_subcommand` function has an overload for
|
|
adding a `shared_ptr<App>` so the subcommand(s) could be defined in different
|
|
components and merged into a main `App`, or possibly multiple `Apps`. Multiple
|
|
nameless subcommands are allowed. Callbacks for nameless subcommands are only
|
|
triggered if any options from the subcommand were parsed. Subcommand names given
|
|
through the `add_subcommand` method have the same restrictions as option names.
|
|
|
|
Options or flags in a subcommand may be directly specified using dot notation
|
|
|
|
- `--subcommand.long=val` (long subcommand option)
|
|
- `--subcommand.long val` (long subcommand option)
|
|
- `--subcommand.f=val` (short form subcommand option)
|
|
- `--subcommand.f val` (short form subcommand option)
|
|
- `--subcommand.f` (short form subcommand flag)
|
|
- `--subcommand1.subsub.f val` (short form nested subcommand option)
|
|
|
|
The use of dot notation in this form is equivalent `--subcommand.long <args>` =>
|
|
`subcommand --long <args> ++`. Nested subcommands also work `sub1.subsub` would
|
|
trigger the subsub subcommand in `sub1`. This is equivalent to "sub1 subsub".
|
|
Quotes around the subcommand names are permitted following the TOML standard for
|
|
such specification. This includes allowing escape sequences. For example
|
|
`"subcommand".'f'` or `"subcommand.with.dots".arg1 = value`.
|
|
|
|
#### Subcommand options
|
|
|
|
There are several options that are supported on the main app and subcommands and
|
|
option_groups. These are:
|
|
|
|
- `.ignore_case()`: Ignore the case of this subcommand. Inherited by added
|
|
subcommands, so is usually used on the main `App`.
|
|
- `.ignore_underscore()`: Ignore any underscores in the subcommand name.
|
|
Inherited by added subcommands, so is usually used on the main `App`.
|
|
- `.allow_windows_style_options()`: Allow command line options to be parsed in
|
|
the form of `/s /long /file:file_name.ext` This option does not change how
|
|
options are specified in the `add_option` calls or the ability to process
|
|
options in the form of `-s --long --file=file_name.ext`.
|
|
- `.allow_non_standard_option_names()`:🆕 Allow specification of single `-` long
|
|
form option names. This is not recommended but is available to enable
|
|
reworking of existing interfaces. If this modifier is enabled on an app or
|
|
subcommand, options or flags can be specified like normal but instead of
|
|
throwing an exception, long form single dash option names will be allowed. It
|
|
is not allowed to have a single character short option starting with the same
|
|
character as a single dash long form name; for example, `-s` and `-single` are
|
|
not allowed in the same application.
|
|
- `.fallthrough()`: Allow extra unmatched options and positionals to "fall
|
|
through" and be matched on a parent option. Subcommands by default are allowed
|
|
to "fall through" as in they will first attempt to match on the current
|
|
subcommand and if they fail will progressively check parents for matching
|
|
subcommands. This can be disabled through `subcommand_fallthrough(false)` 🆕.
|
|
- `.subcommand_fallthrough()`: 🆕 Allow subcommands to "fall through" and be
|
|
matched on a parent option. Disabling this prevents additional subcommands at
|
|
the same level from being matched. It can be useful in certain circumstances
|
|
where there might be ambiguity between subcommands and positionals. The
|
|
default is true.
|
|
- `.configurable()`: Allow the subcommand to be triggered from a configuration
|
|
file. By default subcommand options in a configuration file do not trigger a
|
|
subcommand but will just update default values.
|
|
- `.disable()`: Specify that the subcommand is disabled, if given with a bool
|
|
value it will enable or disable the subcommand or option group.
|
|
- `.disabled_by_default()`: Specify that at the start of parsing the
|
|
subcommand/option_group should be disabled. This is useful for allowing some
|
|
Subcommands to trigger others.
|
|
- `.enabled_by_default()`: Specify that at the start of each parse the
|
|
subcommand/option_group should be enabled. This is useful for allowing some
|
|
Subcommands to disable others.
|
|
- `.silent()`: Specify that the subcommand is silent meaning that if used it
|
|
won't show up in the subcommand list. This allows the use of subcommands as
|
|
modifiers
|
|
- `.validate_positionals()`: Specify that positionals should pass validation
|
|
before matching. Validation is specified through `transform`, `check`, and
|
|
`each` for an option. If an argument fails validation it is not an error and
|
|
matching proceeds to the next available positional or extra arguments.
|
|
- `.validate_optional_arguments()`: Specify that optional arguments should pass
|
|
validation before being assigned to an option. Validation is specified through
|
|
`transform`, `check`, and `each` for an option. If an argument fails
|
|
validation it is not an error and matching proceeds to the next available
|
|
positional subcommand or extra arguments.
|
|
- `.excludes(option_or_subcommand)`: If given an option pointer or pointer to
|
|
another subcommand, these subcommands cannot be given together. In the case of
|
|
options, if the option is passed the subcommand cannot be used and will
|
|
generate an error.
|
|
- `.needs(option_or_subcommand)`: If given an option pointer or pointer to
|
|
another subcommand, the subcommands will require the given option to have been
|
|
given before this subcommand is validated which occurs prior to execution of
|
|
any callback or after parsing is completed.
|
|
- `.require_option()`: Require 1 or more options or option groups be used.
|
|
- `.require_option(N)`: Require `N` options or option groups, if `N>0`, or up to
|
|
`N` if `N<0`. `N=0` resets to the default to 0 or more.
|
|
- `.require_option(min, max)`: Explicitly set min and max allowed options or
|
|
option groups. Setting `max` to 0 implies unlimited options.
|
|
- `.require_subcommand()`: Require 1 or more subcommands.
|
|
- `.require_subcommand(N)`: Require `N` subcommands if `N>0`, or up to `N` if
|
|
`N<0`. `N=0` resets to the default to 0 or more.
|
|
- `.require_subcommand(min, max)`: Explicitly set min and max allowed
|
|
subcommands. Setting `max` to 0 is unlimited.
|
|
- `.add_subcommand(name="", description="")`: Add a subcommand, returns a
|
|
pointer to the internally stored subcommand.
|
|
- `.add_subcommand(shared_ptr<App>)`: Add a subcommand by shared_ptr, returns a
|
|
pointer to the internally stored subcommand.
|
|
- `.remove_subcommand(App)`: Remove a subcommand from the app or subcommand.
|
|
- `.got_subcommand(App_or_name)`: Check to see if a subcommand was received on
|
|
the command line.
|
|
- `.get_subcommands(filter)`: The list of subcommands that match a particular
|
|
filter function.
|
|
- `.add_option_group(name="", description="")`: Add an
|
|
[option group](#option-groups) to an App, an option group is specialized
|
|
subcommand intended for containing groups of options or other groups for
|
|
controlling how options interact.
|
|
- `.get_parent()`: Get the parent App or `nullptr` if called on main App.
|
|
- `.get_option(name)`: Get an option pointer by option name will throw if the
|
|
specified option is not available, nameless subcommands are also searched
|
|
- `.get_option_no_throw(name)`: Get an option pointer by option name. This
|
|
function will return a `nullptr` instead of throwing if the option is not
|
|
available.
|
|
- `.get_options(filter)`: Get the list of all defined option pointers (useful
|
|
for processing the app for custom output formats).
|
|
- `.parse_order()`: Get the list of option pointers in the order they were
|
|
parsed (including duplicates).
|
|
- `.formatter(fmt)`: Set a formatter, with signature
|
|
`std::string(const App*, std::string, AppFormatMode)`. See Formatting for more
|
|
details.
|
|
- `.description(str)`: Set/change the description.
|
|
- `.get_description()`: Access the description.
|
|
- `.alias(str)`: set an alias for the subcommand, this allows subcommands to be
|
|
called by more than one name.
|
|
- `.parsed()`: True if this subcommand was given on the command line.
|
|
- `.count()`: Returns the number of times the subcommand was called.
|
|
- `.count(option_name)`: Returns the number of times a particular option was
|
|
called.
|
|
- `.count_all()`: Returns the total number of arguments a particular subcommand
|
|
processed, on the main App it returns the total number of processed commands.
|
|
- `.name(name)`: Add or change the name.
|
|
- `.callback(void() function)`: Set the callback for an app. Either sets the
|
|
`pre_parse_callback` or the `final_callback` depending on the value of
|
|
`immediate_callback`. See [Subcommand callbacks](#callbacks) for some
|
|
additional details.
|
|
- `.parse_complete_callback(void() function)`: Set the callback that runs at the
|
|
completion of parsing. For subcommands this is executed at the completion of
|
|
the single subcommand and can be executed multiple times. See
|
|
[Subcommand callbacks](#callbacks) for some additional details.
|
|
- `.final_callback(void() function)`: Set the callback that runs at the end of
|
|
all processing. This is the last thing that is executed before returning. See
|
|
[Subcommand callbacks](#callbacks) for some additional details.
|
|
- `.immediate_callback()`: Specifies whether the callback for a subcommand
|
|
should be run as a `parse_complete_callback`(true) or `final_callback`(false).
|
|
When used on the main app it will execute the main app callback prior to the
|
|
callbacks for a subcommand if they do not also have the `immediate_callback`
|
|
flag set. It is preferable to use the `parse_complete_callback` or
|
|
`final_callback` directly instead of the `callback` and `immediate_callback`
|
|
if one wishes to control the ordering and timing of callback. Though
|
|
`immediate_callback` can be used to swap them if that is needed.
|
|
- `.pre_parse_callback(void(std::size_t) function)`: Set a callback that
|
|
executes after the first argument of an application is processed. See
|
|
[Subcommand callbacks](#callbacks) for some additional details.
|
|
- `.allow_extras()`: Do not throw an error if extra arguments are left over.
|
|
- `.positionals_at_end()`: Specify that positional arguments occur as the last
|
|
arguments and throw an error if an unexpected positional is encountered.
|
|
- `.prefix_command()`: Like `allow_extras`, but stop processing immediately on
|
|
the first unrecognized item. All subsequent arguments are placed in the
|
|
remaining_arg list. It is ideal for allowing your app or subcommand to be a
|
|
"prefix" to calling another app.
|
|
- `.usage(message)`: Replace text to appear at the start of the help string
|
|
after description.
|
|
- `.usage(std::string())`: Set a callback to generate a string that will appear
|
|
at the start of the help string after description.
|
|
- `.footer(message)`: Set text to appear at the bottom of the help string.
|
|
- `.footer(std::string())`: Set a callback to generate a string that will appear
|
|
at the end of the help string.
|
|
- `.set_help_flag(name, message)`: Set the help flag name and message, returns a
|
|
pointer to the created option.
|
|
- `.set_version_flag(name, versionString or callback, help_message)`: Set the
|
|
version flag name and version string or callback and optional help message,
|
|
returns a pointer to the created option.
|
|
- `.set_help_all_flag(name, message)`: Set the help all flag name and message,
|
|
returns a pointer to the created option. Expands subcommands.
|
|
- `.failure_message(func)`: Set the failure message function. Two provided:
|
|
`CLI::FailureMessage::help` and `CLI::FailureMessage::simple` (the default).
|
|
- `.group(name)`: Set a group name, defaults to `"Subcommands"`. Setting an
|
|
empty string for the name will be hide the subcommand.
|
|
- `[option_name]`: retrieve a const pointer to an option given by `option_name`
|
|
for Example `app["--flag1"]` will get a pointer to the option for the
|
|
"--flag1" value, `app["--flag1"]->as<bool>()` will get the results of the
|
|
command line for a flag. The operation will throw an exception if the option
|
|
name is not valid.
|
|
|
|
> [!NOTE]
|
|
>
|
|
> If you have a fixed number of required positional options, that will match
|
|
> before subcommand names. `{}` is an empty filter function, and any positional
|
|
> argument will match before repeated subcommand names.
|
|
|
|
#### Callbacks
|
|
|
|
A subcommand has three optional callbacks that are executed at different stages
|
|
of processing. The `preparse_callback` is executed once after the first argument
|
|
of a subcommand or application is processed and gives an argument for the number
|
|
of remaining arguments to process. For the main app the first argument is
|
|
considered the program name, for subcommands the first argument is the
|
|
subcommand name. For Option groups and nameless subcommands the first argument
|
|
is after the first argument or subcommand is processed from that group. The
|
|
second callback is executed after parsing. This is known as the
|
|
`parse_complete_callback`. For subcommands this is executed immediately after
|
|
parsing and can be executed multiple times if a subcommand is called multiple
|
|
times. On the main app this callback is executed after all the
|
|
`parse_complete_callback`s for the subcommands are executed but prior to any
|
|
`final_callback` calls in the subcommand or option groups. If the main app or
|
|
subcommand has a config file, no data from the config file will be reflected in
|
|
`parse_complete_callback` on named subcommands. For `option_group`s the
|
|
`parse_complete_callback` is executed prior to the `parse_complete_callback` on
|
|
the main app but after the `config_file` is loaded (if specified). The
|
|
`final_callback` is executed after all processing is complete. After the
|
|
`parse_complete_callback` is executed on the main app, the used subcommand
|
|
`final_callback` are executed followed by the "final callback" for option
|
|
groups. The last thing to execute is the `final_callback` for the `main_app`.
|
|
For example say an application was set up like
|
|
|
|
```cpp
|
|
app.parse_complete_callback(ac1);
|
|
app.final_callback(ac2);
|
|
auto sub1=app.add_subcommand("sub1")->parse_complete_callback(c1)->preparse_callback(pc1);
|
|
auto sub2=app.add_subcommand("sub2")->final_callback(c2)->preparse_callback(pc2);
|
|
app.preparse_callback( pa);
|
|
|
|
... A bunch of other options
|
|
```
|
|
|
|
Then the command line is given as
|
|
|
|
```bash
|
|
program --opt1 opt1_val sub1 --sub1opt --sub1optb val sub2 --sub2opt sub1 --sub1opt2 sub2 --sub2opt2 val
|
|
```
|
|
|
|
- `pa` will be called prior to parsing any values with an argument of 13.
|
|
- `pc1` will be called immediately after processing the `sub1` command with a
|
|
value of 10.
|
|
- `c1` will be called when the `sub2` command is encountered.
|
|
- `pc2` will be called with value of 6 after the `sub2` command is encountered.
|
|
- `c1` will be called again after the second `sub2` command is encountered.
|
|
- `ac1` will be called after processing of all arguments
|
|
- `c2` will be called once after processing all arguments.
|
|
- `ac2` will be called last after completing all lower level callbacks have been
|
|
executed.
|
|
|
|
A subcommand is considered terminated when one of the following conditions are
|
|
met.
|
|
|
|
1. There are no more arguments to process
|
|
2. Another subcommand is encountered that would not fit in an optional
|
|
positional slot of the subcommand
|
|
3. The `positional_mark` (`--`) is encountered and there are no available
|
|
positional slots in the subcommand.
|
|
4. The `subcommand_terminator` mark (`++`) is encountered
|
|
|
|
Prior to executed a `parse_complete_callback` all contained options are
|
|
processed before the callback is triggered. If a subcommand with a
|
|
`parse_complete_callback` is called again, then the contained options are reset,
|
|
and can be triggered again.
|
|
|
|
#### Option groups
|
|
|
|
The subcommand method
|
|
|
|
```cpp
|
|
.add_option_group(name,description)
|
|
```
|
|
|
|
Will create an option group, and return a pointer to it. The argument for
|
|
`description` is optional and can be omitted. An option group allows creation of
|
|
a collection of options, similar to the groups function on options, but with
|
|
additional controls and requirements. They allow specific sets of options to be
|
|
composed and controlled as a collective. For an example see
|
|
[range example](https://github.com/CLIUtils/CLI11/blob/main/examples/ranges.cpp).
|
|
Option groups are a specialization of an App so all
|
|
[functions](#subcommand-options) that work with an App or subcommand also work
|
|
on option groups. Options can be created as part of an option group using the
|
|
add functions just like a subcommand, or previously created options can be added
|
|
through. The name given in an option group must not contain newlines or null
|
|
characters.
|
|
|
|
```cpp
|
|
ogroup->add_option(option_pointer);
|
|
ogroup->add_options(option_pointer);
|
|
ogroup->add_options(option1,option2,option3,...);
|
|
```
|
|
|
|
The option pointers used in this function must be options defined in the parent
|
|
application of the option group otherwise an error will be generated.
|
|
Subcommands can also be added via
|
|
|
|
```cpp
|
|
ogroup->add_subcommand(subcom_pointer);
|
|
```
|
|
|
|
This results in the subcommand being moved from its parent into the option
|
|
group.
|
|
|
|
Options in an option group are searched for a command line match after any
|
|
options in the main app, so any positionals in the main app would be matched
|
|
first. So care must be taken to make sure of the order when using positional
|
|
arguments and option groups. Option groups work well with `excludes` and
|
|
`require_options` methods, as an application will treat an option group as a
|
|
single option for the purpose of counting and requirements, and an option group
|
|
will be considered used if any of the options or subcommands contained in it are
|
|
used. Option groups allow specifying requirements such as requiring 1 of 3
|
|
options in one group and 1 of 3 options in a different group. Option groups can
|
|
contain other groups as well. Disabling an option group will turn off all
|
|
options within the group.
|
|
|
|
The `CLI::TriggerOn` and `CLI::TriggerOff` methods are helper functions to allow
|
|
the use of options/subcommands from one group to trigger another group on or
|
|
off.
|
|
|
|
```cpp
|
|
CLI::TriggerOn(group1_pointer, triggered_group);
|
|
CLI::TriggerOff(group2_pointer, disabled_group);
|
|
```
|
|
|
|
These functions make use of `preparse_callback`, `enabled_by_default()` and
|
|
`disabled_by_default`. The triggered group may be a vector of group pointers.
|
|
These methods should only be used once per group and will override any previous
|
|
use of the underlying functions. More complex arrangements can be accomplished
|
|
using similar methodology with a custom `preparse_callback` function that does
|
|
more.
|
|
|
|
Additional helper functions `deprecate_option` and `retire_option` are available
|
|
to deprecate or retire options
|
|
|
|
```cpp
|
|
CLI::deprecate_option(option *, replacement_name="");
|
|
CLI::deprecate_option(App,option_name,replacement_name="");
|
|
```
|
|
|
|
will specify that the option is deprecated which will display a message in the
|
|
help and a warning on first usage. Deprecated options function normally but will
|
|
add a message in the help and display a warning on first use.
|
|
|
|
```cpp
|
|
CLI::retire_option(App,option *);
|
|
CLI::retire_option(App,option_name);
|
|
```
|
|
|
|
will create an option that does nothing by default and will display a warning on
|
|
first usage that the option is retired and has no effect. If the option exists
|
|
it is replaces with a dummy option that takes the same arguments.
|
|
|
|
If an empty string is passed the option group name the entire group will be
|
|
hidden in the help results. For example.
|
|
|
|
```cpp
|
|
auto hidden_group=app.add_option_group("");
|
|
```
|
|
|
|
will create a group such that no options in that group are displayed in the help
|
|
string. For the purposes of help display, if the option group name starts with a
|
|
'+' it is treated as if it were not in a group for help and get_options. For
|
|
example:
|
|
|
|
```cpp
|
|
auto added_group=app.add_option_group("+sub");
|
|
```
|
|
|
|
In this case the help output will not reference the option group and options
|
|
inside of it will be treated for most purposes as if they were part of the
|
|
parent.
|
|
|
|
### Configuration file
|
|
|
|
```cpp
|
|
app.set_config(option_name="",
|
|
default_file_name="",
|
|
help_string="Read an ini file",
|
|
required=false)
|
|
```
|
|
|
|
If this is called with no arguments, it will remove the configuration file
|
|
option (like `set_help_flag`). Setting a configuration option is special. If it
|
|
is present, it will be read along with the normal command line arguments. The
|
|
file will be read if it exists, and does not throw an error unless `required` is
|
|
`true`. Configuration files are in [TOML][] format by default, though the
|
|
default reader can also accept files in INI format as well. The config reader
|
|
can read most aspects of TOML files including strings both literal and with
|
|
potential escape sequences, digit separators, and multi-line strings, and run
|
|
them through the CLI11 parser. Other formats can be added by an adept user, some
|
|
variations are available through customization points in the default formatter.
|
|
An example of a TOML file:
|
|
|
|
```toml
|
|
# Comments are supported, using a #
|
|
# The default section is [default], case-insensitive
|
|
|
|
value = 1
|
|
value2 = 123_456 # a string with separators
|
|
str = "A string"
|
|
str2 = "A string\nwith new lines"
|
|
str3 = 'A literal "string"'
|
|
vector = [1,2,3]
|
|
str_vector = ["one","two","and three"]
|
|
|
|
# Sections map to subcommands
|
|
[subcommand]
|
|
in_subcommand = Wow
|
|
sub.subcommand = true
|
|
"sub"."subcommand2" = "string_value"
|
|
```
|
|
|
|
or equivalently in INI format
|
|
|
|
```ini
|
|
; Comments are supported, using a ;
|
|
; The default section is [default], case-insensitive
|
|
|
|
value = 1
|
|
str = "A string"
|
|
vector = 1 2 3
|
|
str_vector = "one" "two" "and three"
|
|
|
|
; Sections map to subcommands
|
|
[subcommand]
|
|
in_subcommand = Wow
|
|
sub.subcommand = true
|
|
```
|
|
|
|
Spaces before and after the name and argument are ignored. Multiple arguments
|
|
are separated by spaces. One set of quotes will be removed, preserving spaces
|
|
(the same way the command line works). Boolean options can be `true`, `on`, `1`,
|
|
`yes`, `enable`; or `false`, `off`, `0`, `no`, `disable` (case-insensitive).
|
|
Sections (and `.` separated names) are treated as subcommands (note: this does
|
|
not necessarily mean that subcommand was passed, it just sets the "defaults").
|
|
You cannot set positional-only arguments. Subcommands can be triggered from
|
|
configuration files if the `configurable` flag was set on the subcommand. Then
|
|
the use of `[subcommand]` notation will trigger a subcommand and cause it to act
|
|
as if it were on the command line.
|
|
|
|
To print a configuration file from the passed arguments, use
|
|
`.config_to_str(default_also=false, write_description=false)`, where
|
|
`default_also` will also show any defaulted arguments, and `write_description`
|
|
will include the app and option descriptions. See
|
|
[Config files](https://cliutils.github.io/CLI11/book/chapters/config.html) for
|
|
some additional details and customization points.
|
|
|
|
If it is desired that multiple configuration be allowed. Use
|
|
|
|
```cpp
|
|
app.set_config("--config")->expected(1, X);
|
|
```
|
|
|
|
Where X is some positive number and will allow up to `X` configuration files to
|
|
be specified by separate `--config` arguments. Value strings with quote
|
|
characters in it will be printed with a single quote. All other arguments will
|
|
use double quote. Empty strings will use a double quoted argument. Numerical or
|
|
boolean values are not quoted.
|
|
|
|
For options or flags which allow 0 arguments to be passed using an empty string
|
|
in the config file, `{}`, or `[]` will convert the result to the default value
|
|
specified via `default_str` or `default_val` on the option. If no user specified
|
|
default is given the result is an empty string or the converted value of an
|
|
empty string.
|
|
|
|
NOTE: Transforms and checks can be used with the option pointer returned from
|
|
set_config like any other option to validate the input if needed. It can also be
|
|
used with the built in transform `CLI::FileOnDefaultPath` to look in a default
|
|
path as well as the current one. For example
|
|
|
|
```cpp
|
|
app.set_config("--config")->transform(CLI::FileOnDefaultPath("/to/default/path/"));
|
|
```
|
|
|
|
See [Transforming Validators](#transforming-validators) for additional details
|
|
on this validator. Multiple transforms or validators can be used either by
|
|
multiple calls or using `|` operations with the transform.
|
|
|
|
### Inheriting defaults
|
|
|
|
Many of the defaults for subcommands and even options are inherited from their
|
|
creators. The inherited default values for subcommands are `allow_extras`,
|
|
`prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`,
|
|
`usage`, `footer`, `immediate_callback` and maximum number of required
|
|
subcommands. The help flag existence, name, and description are inherited, as
|
|
well.
|
|
|
|
Options have defaults for `group`, `required`, `multi_option_policy`,
|
|
`ignore_case`, `ignore_underscore`, `delimiter`, and `disable_flag_override`. To
|
|
set these defaults, you should set the `option_defaults()` object, for example:
|
|
|
|
```cpp
|
|
app.option_defaults()->required();
|
|
// All future options will be required
|
|
```
|
|
|
|
The default settings for options are inherited to subcommands, as well.
|
|
|
|
### Formatting
|
|
|
|
The job of formatting help printouts is delegated to a formatter callable object
|
|
on Apps and Options. You are free to replace either formatter by calling
|
|
`formatter(fmt)` on an `App`, where fmt is any copyable callable with the
|
|
correct signature. CLI11 comes with a default App formatter functional,
|
|
`Formatter`. It is customizable; you can set `label(key, value)` to replace the
|
|
default labels like `REQUIRED`, and `column_width(n)` to set the width of the
|
|
columns before you add the functional to the app or option. You can also
|
|
override almost any stage of the formatting process in a subclass of either
|
|
formatter. If you want to make a new formatter from scratch, you can do that
|
|
too; you just need to implement the correct signature. The first argument is a
|
|
const pointer to the in question. The formatter will get a `std::string` usage
|
|
name as the second option, and a `AppFormatMode` mode for the final option. It
|
|
should return a `std::string`.
|
|
|
|
The `AppFormatMode` can be `Normal`, `All`, or `Sub`, and it indicates the
|
|
situation the help was called in. `Sub` is optional, but the default formatter
|
|
uses it to make sure expanded subcommands are called with their own formatter
|
|
since you can't access anything but the call operator once a formatter has been
|
|
set.
|
|
|
|
### Subclassing
|
|
|
|
The App class was designed allow toolkits to subclass it, to provide preset
|
|
default options (see above) and setup/teardown code. Subcommands remain an
|
|
unsubclassed `App`, since those are not expected to need setup and teardown. The
|
|
default `App` only adds a help flag, `-h,--help`, than can removed/replaced
|
|
using `.set_help_flag(name, help_string)`. You can also set a help-all flag with
|
|
`.set_help_all_flag(name, help_string)`; this will expand the subcommands (one
|
|
level only). You can remove options if you have pointers to them using
|
|
`.remove_option(opt)`. You can add a `pre_callback` override to customize the
|
|
after parse but before run behavior, while still giving the user freedom to
|
|
`callback` on the main app.
|
|
|
|
The most important parse function is `parse(std::vector<std::string>)`, which
|
|
takes a reversed list of arguments (so that `pop_back` processes the args in the
|
|
correct order). `get_help_ptr` and `get_config_ptr` give you access to the
|
|
help/config option pointers. The standard `parse` manually sets the name from
|
|
the first argument, so it should not be in this vector. You can also use
|
|
`parse(string, bool)` to split up and parse a single string; the optional
|
|
boolean should be set to true if you are including the program name in the
|
|
string, and false otherwise. The program name can contain spaces if it is an
|
|
existing file, otherwise can be enclosed in quotes(single quote, double quote or
|
|
backtick). Embedded quote characters can be escaped with `\`.
|
|
|
|
Also, in a related note, the `App` you get a pointer to is stored in the parent
|
|
`App` in a `shared_ptr`s (similar to `Option`s) and are deleted when the main
|
|
`App` goes out of scope unless the object has another owner.
|
|
|
|
### How it works
|
|
|
|
Every `add_` option you have seen so far depends on one method that takes a
|
|
lambda function. Each of these methods is just making a different lambda
|
|
function with capture to populate the option. The function has full access to
|
|
the vector of strings, so it knows how many times an option was passed or how
|
|
many arguments it received. The lambda returns `true` if it could validate the
|
|
option strings, and `false` if it failed.
|
|
|
|
Other values can be added as long as they support `operator>>` (and defaults can
|
|
be printed if they support `operator<<`). To add a new type, for example,
|
|
provide a custom `operator>>` with an `istream` (inside the CLI namespace is
|
|
fine if you don't want to interfere with an existing `operator>>`).
|
|
|
|
If you wanted to extend this to support a completely new type, use a lambda or
|
|
add an overload of the `lexical_cast` function in the namespace of the type you
|
|
need to convert to. Some examples of some new parsers for `complex<double>` that
|
|
support all of the features of a standard `add_options` call are in
|
|
[one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
|
|
|
|
```cpp
|
|
app.add_option("--fancy-count", [](std::vector<std::string> val){
|
|
std::cout << "This option was given " << val.size() << " times." << std::endl;
|
|
return true;
|
|
});
|
|
```
|
|
|
|
### Unicode support
|
|
|
|
CLI11 supports Unicode and wide strings as defined in the
|
|
[UTF-8 Everywhere](http://utf8everywhere.org/) manifesto. In particular:
|
|
|
|
- The library can parse a wide version of command-line arguments on Windows,
|
|
which are converted internally to UTF-8 (more on this below);
|
|
- You can store option values in `std::wstring`, in which case they will be
|
|
converted to a correct wide string encoding on your system (UTF-16 on Windows
|
|
and UTF-32 on most other systems);
|
|
- Instead of storing wide strings, it is recommended to use provided `widen` and
|
|
`narrow` functions to convert to and from wide strings when actually necessary
|
|
(such as when calling into Windows APIs).
|
|
|
|
When using the command line on Windows with unicode arguments, your `main`
|
|
function may already receive broken Unicode. Parsing `argv` at that point will
|
|
not give you a correct string. To fix this, you have three options; the first is
|
|
recommended for cross-platform support:
|
|
|
|
1\. Replace `argv` with `app.ensure_utf8(argv)` before any arguments are parsed.
|
|
`ensure_utf8` will do nothing on systems where `argv` is already in UTF-8 (Such
|
|
as Linux or macOS) and return `argv` unmodified. On Windows, it will discard
|
|
`argv` and replace it with a correctly decoded array or arguments from win32
|
|
API.
|
|
|
|
```cpp
|
|
int main(int argc, char** argv) {
|
|
CLI::App app;
|
|
argv = app.ensure_utf8(argv); // new argv memory is held by app
|
|
// ...
|
|
CLI11_PARSE(app, argc, argv);
|
|
}
|
|
```
|
|
|
|
Be sure you do not modify `argv` before this function call, as the correct
|
|
values will be reconstructed using Windows APIs and produced by this call. It
|
|
has no effect on other platforms and just passes through `argv`.
|
|
|
|
<details><summary>Other options (click to expand)</summary><p>
|
|
|
|
2\. Use the Windows-only non-standard `wmain` function, which accepts
|
|
`wchar_t *argv[]` instead of `char* argv[]`. Parsing this will allow CLI to
|
|
convert wide strings to UTF-8 without losing information.
|
|
|
|
```cpp
|
|
int wmain(int argc, wchar_t *argv[]) {
|
|
CLI::App app;
|
|
// ...
|
|
CLI11_PARSE(app, argc, argv);
|
|
}
|
|
```
|
|
|
|
3\. Retrieve arguments yourself by using Windows APIs like
|
|
[`CommandLineToArgvW`](https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw)
|
|
and pass them to CLI. This is what the library is doing under the hood in
|
|
`ensure_utf8`.
|
|
|
|
</p></details>
|
|
</br>
|
|
|
|
The library provides functions to convert between UTF-8 and wide strings:
|
|
|
|
```cpp
|
|
namespace CLI {
|
|
std::string narrow(const std::wstring &str);
|
|
std::string narrow(const wchar_t *str);
|
|
std::string narrow(const wchar_t *str, std::size_t size);
|
|
std::string narrow(std::wstring_view str); // C++17
|
|
|
|
std::wstring widen(const std::string &str);
|
|
std::wstring widen(const char *str);
|
|
std::wstring widen(const char *str, std::size_t size);
|
|
std::wstring widen(std::string_view str); // C++17
|
|
}
|
|
```
|
|
|
|
#### Note on using Unicode paths
|
|
|
|
When creating a `filesystem::path` from a UTF-8 path on Windows, you need to
|
|
convert it to a wide string first. CLI11 provides a platform-independent
|
|
`to_path` function, which will convert a UTF-8 string to path, the right way:
|
|
|
|
```cpp
|
|
std::string utf8_name = "Hello Halló Привет 你好 👩🚀❤️.txt";
|
|
|
|
std::filesystem::path p = CLI::to_path(utf8_name);
|
|
std::ifstream stream(CLI::to_path(utf8_name));
|
|
// etc.
|
|
```
|
|
|
|
### Utilities
|
|
|
|
There are a few other utilities that are often useful in CLI programming. These
|
|
are in separate headers, and do not appear in `CLI11.hpp`, but are completely
|
|
independent and can be used as needed. The `Timer`/`AutoTimer` class allows you
|
|
to easily time a block of code, with custom print output.
|
|
|
|
```cpp
|
|
{
|
|
CLI::AutoTimer timer {"My Long Process", CLI::Timer::Big};
|
|
some_long_running_process();
|
|
}
|
|
```
|
|
|
|
This will create a timer with a title (default: `Timer`), and will customize the
|
|
output using the predefined `Big` output (default: `Simple`). Because it is an
|
|
`AutoTimer`, it will print out the time elapsed when the timer is destroyed at
|
|
the end of the block. If you use `Timer` instead, you can use `to_string` or
|
|
`std::cout << timer << std::endl;` to print the time. The print function can be
|
|
any function that takes two strings, the title and the time, and returns a
|
|
formatted string for printing.
|
|
|
|
### Other libraries
|
|
|
|
If you use the excellent [Rang][] library to add color to your terminal in a
|
|
safe, multi-platform way, you can combine it with CLI11 nicely:
|
|
|
|
```cpp
|
|
std::atexit([](){std::cout << rang::style::reset;});
|
|
try {
|
|
app.parse(argc, argv);
|
|
} catch (const CLI::ParseError &e) {
|
|
std::cout << (e.get_exit_code()==0 ? rang::fg::blue : rang::fg::red);
|
|
return app.exit(e);
|
|
}
|
|
```
|
|
|
|
This will print help in blue, errors in red, and will reset before returning the
|
|
terminal to the user.
|
|
|
|
If you are on a Unix-like system, and you'd like to handle control-c and color,
|
|
you can add:
|
|
|
|
```cpp
|
|
#include <csignal>
|
|
void signal_handler(int s) {
|
|
std::cout << std::endl << rang::style::reset << rang::fg::red << rang::fg::bold;
|
|
std::cout << "Control-C detected, exiting..." << rang::style::reset << std::endl;
|
|
std::exit(1); // will call the correct exit func, no unwinding of the stack though
|
|
}
|
|
```
|
|
|
|
And, in your main function:
|
|
|
|
```cpp
|
|
// Nice Control-C
|
|
struct sigaction sigIntHandler;
|
|
sigIntHandler.sa_handler = signal_handler;
|
|
sigemptyset(&sigIntHandler.sa_mask);
|
|
sigIntHandler.sa_flags = 0;
|
|
sigaction(SIGINT, &sigIntHandler, nullptr);
|
|
```
|
|
|
|
## API
|
|
|
|
The API is [documented here][api-docs]. Also see the [CLI11 tutorial
|
|
GitBook][gitbook].
|
|
|
|
## Examples
|
|
|
|
Several short examples of different features are included in the repository. A
|
|
brief description of each is included here
|
|
|
|
- [arg_capture](https://github.com/CLIUtils/CLI11/blob/main/examples/arg_capture.cpp):
|
|
Example of capturing all remaining arguments after a specific option, using
|
|
subcommand and prefix_command() with an alias.
|
|
- [callback_passthrough](https://github.com/CLIUtils/CLI11/blob/main/examples/callback_passthrough.cpp):
|
|
Example of directly passing remaining arguments through to a callback function
|
|
which generates a CLI11 application based on existing arguments.
|
|
- [custom_parse](https://github.com/CLIUtils/CLI11/blob/main/examples/custom_parse.cpp):
|
|
Based on [Issue #566](https://github.com/CLIUtils/CLI11/issues/566), example
|
|
of custom parser
|
|
- [digit_args](https://github.com/CLIUtils/CLI11/blob/main/examples/digit_args.cpp):
|
|
Based on [Issue #123](https://github.com/CLIUtils/CLI11/issues/123), uses
|
|
digit flags to pass a value
|
|
- [enum](https://github.com/CLIUtils/CLI11/blob/main/examples/enum.cpp): Using
|
|
enumerations in an option, and the use of
|
|
[CheckedTransformer](#transforming-validators)
|
|
- [enum_ostream](https://github.com/CLIUtils/CLI11/blob/main/examples/enum_ostream.cpp):
|
|
In addition to the contents of example enum.cpp, this example shows how a
|
|
custom ostream operator overrides CLI11's enum streaming.
|
|
- [formatter](https://github.com/CLIUtils/CLI11/blob/main/examples/formatter.cpp):
|
|
Illustrating usage of a custom formatter
|
|
- [groups](https://github.com/CLIUtils/CLI11/blob/main/examples/groups.cpp):
|
|
Example using groups of options for help grouping and a timer helper class
|
|
- [inter_argument_order](https://github.com/CLIUtils/CLI11/blob/main/examples/inter_argument_order.cpp):
|
|
An app to practice mixing unlimited arguments, but still recover the original
|
|
order.
|
|
- [json](https://github.com/CLIUtils/CLI11/blob/main/examples/json.cpp): Using
|
|
JSON as a config file parser
|
|
- [modhelp](https://github.com/CLIUtils/CLI11/blob/main/examples/modhelp.cpp):
|
|
How to modify the help flag to do something other than default
|
|
- [nested](https://github.com/CLIUtils/CLI11/blob/main/examples/nested.cpp):
|
|
Nested subcommands
|
|
- [option_groups](https://github.com/CLIUtils/CLI11/blob/main/examples/option_groups.cpp):
|
|
Illustrating the use of option groups and a required number of options. Based
|
|
on [Issue #88](https://github.com/CLIUtils/CLI11/issues/88) to set interacting
|
|
groups of options
|
|
- [positional_arity](https://github.com/CLIUtils/CLI11/blob/main/examples/positional_arity.cpp):
|
|
Illustrating use of `preparse_callback` to handle situations where the number
|
|
of arguments can determine which should get parsed, Based on
|
|
[Issue #166](https://github.com/CLIUtils/CLI11/issues/166)
|
|
- [positional_validation](https://github.com/CLIUtils/CLI11/blob/main/examples/positional_validation.cpp):
|
|
Example of how positional arguments are validated using the
|
|
`validate_positional` flag, also based on
|
|
[Issue #166](https://github.com/CLIUtils/CLI11/issues/166)
|
|
- [prefix_command](https://github.com/CLIUtils/CLI11/blob/main/examples/prefix_command.cpp):
|
|
Illustrating use of the `prefix_command` flag.
|
|
- [ranges](https://github.com/CLIUtils/CLI11/blob/main/examples/ranges.cpp): App
|
|
to demonstrate exclusionary option groups based on
|
|
[Issue #88](https://github.com/CLIUtils/CLI11/issues/88)
|
|
- [shapes](https://github.com/CLIUtils/CLI11/blob/main/examples/shapes.cpp):
|
|
Illustrating how to set up repeated subcommands Based on
|
|
[gitter discussion](https://gitter.im/CLI11gitter/Lobby?at=5c7af6b965ffa019ea788cd5)
|
|
- [simple](https://github.com/CLIUtils/CLI11/blob/main/examples/simple.cpp): A
|
|
simple example of how to set up a CLI11 Application with different flags and
|
|
options
|
|
- [subcom_help](https://github.com/CLIUtils/CLI11/blob/main/examples/subcom_help.cpp):
|
|
Configuring help for subcommands
|
|
- [subcom_partitioned](https://github.com/CLIUtils/CLI11/blob/main/examples/subcom_partitioned.cpp):
|
|
Example with a timer and subcommands generated separately and added to the
|
|
main app later.
|
|
- [subcommands](https://github.com/CLIUtils/CLI11/blob/main/examples/subcommands.cpp):
|
|
Short example of subcommands
|
|
- [validators](https://github.com/CLIUtils/CLI11/blob/main/examples/validators.cpp):
|
|
Example illustrating use of validators
|
|
|
|
## Contribute
|
|
|
|
To contribute, open an [issue][github issues] or [pull
|
|
request][github pull requests] on GitHub, or ask a question on [gitter][]. There
|
|
is also a [short note to contributors](./.github/CONTRIBUTING.md). This readme
|
|
roughly follows the [Standard Readme Style][] and includes a mention of almost
|
|
every feature of the library. More complex features are documented in more
|
|
detail in the [CLI11 tutorial GitBook][gitbook].
|
|
|
|
This project was created by [Henry Schreiner](https://github.com/henryiii) and
|
|
major features were added by [Philip Top](https://github.com/phlptp). Special
|
|
thanks to all the contributors
|
|
([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
|
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
<!-- prettier-ignore-start -->
|
|
<!-- markdownlint-disable -->
|
|
<table>
|
|
<tbody>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://profiles.sussex.ac.uk/p281168-alex-dewar/publications"><img src="https://avatars.githubusercontent.com/u/23149834?v=4?s=100" width="100px;" alt="Alex Dewar"/><br /><sub><b>Alex Dewar</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=alexdewar" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andrew-hardin"><img src="https://avatars0.githubusercontent.com/u/16496326?v=4?s=100" width="100px;" alt="Andrew Hardin"/><br /><sub><b>Andrew Hardin</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=andrew-hardin" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andreasxp"><img src="https://avatars.githubusercontent.com/u/28830446?v=4?s=100" width="100px;" alt="Andrey Zhukov"/><br /><sub><b>Andrey Zhukov</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=andreasxp" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SX91"><img src="https://avatars2.githubusercontent.com/u/754754?v=4?s=100" width="100px;" alt="Anton"/><br /><sub><b>Anton</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=SX91" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/trokhymchuk"><img src="https://avatars.githubusercontent.com/u/66204814?v=4?s=100" width="100px;" alt="Artem Trokhymchuk "/><br /><sub><b>Artem Trokhymchuk </b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=trokhymchuk" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BenjaminBeichler"><img src="https://avatars.githubusercontent.com/u/1441492?v=4?s=100" width="100px;" alt="Benjamin Beichler"/><br /><sub><b>Benjamin Beichler</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=BenjaminBeichler" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/calebzulawski"><img src="https://avatars.githubusercontent.com/u/563826?v=4?s=100" width="100px;" alt="Caleb Zulawski"/><br /><sub><b>Caleb Zulawski</b></sub></a><br /><a href="#platform-calebzulawski" title="Packaging/porting to new platform">📦</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/krico"><img src="https://avatars.githubusercontent.com/u/6952185?v=4?s=100" width="100px;" alt="Christian Asmussen"/><br /><sub><b>Christian Asmussen</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=krico" title="Documentation">📖</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=krico" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/cbachhuber/"><img src="https://avatars0.githubusercontent.com/u/27212661?v=4?s=100" width="100px;" alt="Christoph Bachhuber"/><br /><sub><b>Christoph Bachhuber</b></sub></a><br /><a href="#example-cbachhuber" title="Examples">💡</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=cbachhuber" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ComixHe"><img src="https://avatars.githubusercontent.com/u/54773474?v=4?s=100" width="100px;" alt="Comix"/><br /><sub><b>Comix</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ComixHe" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dfleury2"><img src="https://avatars1.githubusercontent.com/u/4805384?v=4?s=100" width="100px;" alt="D. Fleury"/><br /><sub><b>D. Fleury</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=dfleury2" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dbarowy"><img src="https://avatars3.githubusercontent.com/u/573142?v=4?s=100" width="100px;" alt="Dan Barowy"/><br /><sub><b>Dan Barowy</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=dbarowy" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mensinda"><img src="https://avatars3.githubusercontent.com/u/3407462?v=4?s=100" width="100px;" alt="Daniel Mensinger"/><br /><sub><b>Daniel Mensinger</b></sub></a><br /><a href="#platform-mensinda" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DarkWingMcQuack"><img src="https://avatars.githubusercontent.com/u/38857302?v=4?s=100" width="100px;" alt="DarkWingMcQuack"/><br /><sub><b>DarkWingMcQuack</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=DarkWingMcQuack" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZeeD26"><img src="https://avatars2.githubusercontent.com/u/2487468?v=4?s=100" width="100px;" alt="Dominik Steinberger"/><br /><sub><b>Dominik Steinberger</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ZeeD26" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dvj"><img src="https://avatars2.githubusercontent.com/u/77217?v=4?s=100" width="100px;" alt="Doug Johnston"/><br /><sub><b>Doug Johnston</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Advj" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=dvj" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://recursiveascent.blogspot.com/"><img src="https://avatars.githubusercontent.com/u/1779595?v=4?s=100" width="100px;" alt="Dylan Baker"/><br /><sub><b>Dylan Baker</b></sub></a><br /><a href="#platform-dcbaker" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/eli-schwartz"><img src="https://avatars.githubusercontent.com/u/6551424?v=4?s=100" width="100px;" alt="Eli Schwartz"/><br /><sub><b>Eli Schwartz</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=eli-schwartz" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sifferman"><img src="https://avatars.githubusercontent.com/u/43790149?v=4?s=100" width="100px;" alt="Ethan Sifferman"/><br /><sub><b>Ethan Sifferman</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=sifferman" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/helmesjo"><img src="https://avatars0.githubusercontent.com/u/2501070?v=4?s=100" width="100px;" alt="Fred Helmesjö"/><br /><sub><b>Fred Helmesjö</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Ahelmesjo" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=helmesjo" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gblanco92"><img src="https://avatars.githubusercontent.com/u/3957977?v=4?s=100" width="100px;" alt="Guillem Blanco"/><br /><sub><b>Guillem Blanco</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=gblanco92" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://iscinumpy.gitlab.io"><img src="https://avatars1.githubusercontent.com/u/4616906?v=4?s=100" width="100px;" alt="Henry Schreiner"/><br /><sub><b>Henry Schreiner</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Ahenryiii" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=henryiii" title="Documentation">📖</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=henryiii" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://izzys.casa"><img src="https://avatars0.githubusercontent.com/u/63051?v=4?s=100" width="100px;" alt="Isabella Muerte"/><br /><sub><b>Isabella Muerte</b></sub></a><br /><a href="#platform-slurps-mad-rips" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://izzys.casa/"><img src="https://avatars.githubusercontent.com/u/63051?v=4?s=100" width="100px;" alt="Izzy Muerte"/><br /><sub><b>Izzy Muerte</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=bruxisma" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jakoblover"><img src="https://avatars0.githubusercontent.com/u/14160441?v=4?s=100" width="100px;" alt="Jakob Lover"/><br /><sub><b>Jakob Lover</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=jakoblover" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jgerityneurala"><img src="https://avatars2.githubusercontent.com/u/57360646?v=4?s=100" width="100px;" alt="James Gerity"/><br /><sub><b>James Gerity</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=jgerityneurala" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jbriales"><img src="https://avatars1.githubusercontent.com/u/6850478?v=4?s=100" width="100px;" alt="Jesus Briales"/><br /><sub><b>Jesus Briales</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=jbriales" title="Code">💻</a> <a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Ajbriales" title="Bug reports">🐛</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SkyToGround"><img src="https://avatars1.githubusercontent.com/u/58835?v=4?s=100" width="100px;" alt="Jonas Nilsson"/><br /><sub><b>Jonas Nilsson</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3ASkyToGround" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=SkyToGround" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/j-rivero"><img src="https://avatars.githubusercontent.com/u/2098802?v=4?s=100" width="100px;" alt="Jose Luis Rivero"/><br /><sub><b>Jose Luis Rivero</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=j-rivero" title="Code">💻</a> <a href="#platform-j-rivero" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jsoref"><img src="https://avatars0.githubusercontent.com/u/2119212?v=4?s=100" width="100px;" alt="Josh Soref"/><br /><sub><b>Josh Soref</b></sub></a><br /><a href="#tool-jsoref" title="Tools">🔧</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=jsoref" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://www.effibem.com"><img src="https://avatars.githubusercontent.com/u/5479063?v=4?s=100" width="100px;" alt="Julien Marrec"/><br /><sub><b>Julien Marrec</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=jmarrec" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KOLANICH"><img src="https://avatars1.githubusercontent.com/u/240344?v=4?s=100" width="100px;" alt="KOLANICH"/><br /><sub><b>KOLANICH</b></sub></a><br /><a href="#platform-KOLANICH" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/skannan89"><img src="https://avatars0.githubusercontent.com/u/11918764?v=4?s=100" width="100px;" alt="Kannan"/><br /><sub><b>Kannan</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Askannan89" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=skannan89" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://himvis.com"><img src="https://avatars3.githubusercontent.com/u/465279?v=4?s=100" width="100px;" alt="Khem Raj"/><br /><sub><b>Khem Raj</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=kraj" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/looopTools"><img src="https://avatars.githubusercontent.com/u/1943536?v=4?s=100" width="100px;" alt="Lars Nielsen"/><br /><sub><b>Lars Nielsen</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=looopTools" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://lucas-czech.de"><img src="https://avatars0.githubusercontent.com/u/4741887?v=4?s=100" width="100px;" alt="Lucas Czech"/><br /><sub><b>Lucas Czech</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Alczech" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=lczech" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://www.mogigoma.com/"><img src="https://avatars2.githubusercontent.com/u/130862?v=4?s=100" width="100px;" alt="Mak Kolybabi"/><br /><sub><b>Mak Kolybabi</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=mogigoma" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LostInCompilation"><img src="https://avatars.githubusercontent.com/u/12819635?v=4?s=100" width="100px;" alt="Marc"/><br /><sub><b>Marc</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=LostInCompilation" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cetius"><img src="https://avatars.githubusercontent.com/u/6552472?v=4?s=100" width="100px;" alt="Marcin Ropa"/><br /><sub><b>Marcin Ropa</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=cetius" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://lambdafu.net/"><img src="https://avatars1.githubusercontent.com/u/1138455?v=4?s=100" width="100px;" alt="Marcus Brinkmann"/><br /><sub><b>Marcus Brinkmann</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Alambdafu" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=lambdafu" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://msoeken.github.io"><img src="https://avatars0.githubusercontent.com/u/1998245?v=4?s=100" width="100px;" alt="Mathias Soeken"/><br /><sub><b>Mathias Soeken</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=msoeken" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://www.mmmccormick.com/"><img src="https://avatars.githubusercontent.com/u/25432?v=4?s=100" width="100px;" alt="Matt McCormick"/><br /><sub><b>Matt McCormick</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=thewtex" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AnticliMaxtic"><img src="https://avatars.githubusercontent.com/u/43995389?v=4?s=100" width="100px;" alt="Max"/><br /><sub><b>Max</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=AnticliMaxtic" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://mbh.sh"><img src="https://avatars3.githubusercontent.com/u/20403931?v=4?s=100" width="100px;" alt="Michael Hall"/><br /><sub><b>Michael Hall</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=mbhall88" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nathanhourt"><img src="https://avatars2.githubusercontent.com/u/271977?v=4?s=100" width="100px;" alt="Nathan Hourt"/><br /><sub><b>Nathan Hourt</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Anathanhourt" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=nathanhourt" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nathanielhourt"><img src="https://avatars.githubusercontent.com/u/271977?v=4?s=100" width="100px;" alt="Nathaniel Hourt"/><br /><sub><b>Nathaniel Hourt</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=nathanielhourt" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/paddy-hack"><img src="https://avatars.githubusercontent.com/u/6804372?v=4?s=100" width="100px;" alt="Olaf Meeuwissen"/><br /><sub><b>Olaf Meeuwissen</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=paddy-hack" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://ondrejcertik.com/"><img src="https://avatars3.githubusercontent.com/u/20568?v=4?s=100" width="100px;" alt="Ondřej Čertík"/><br /><sub><b>Ondřej Čertík</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Acertik" title="Bug reports">🐛</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pleroux0"><img src="https://avatars2.githubusercontent.com/u/39619854?v=4?s=100" width="100px;" alt="Paul le Roux"/><br /><sub><b>Paul le Roux</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=pleroux0" title="Code">💻</a> <a href="#platform-pleroux0" title="Packaging/porting to new platform">📦</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chfast"><img src="https://avatars1.githubusercontent.com/u/573380?v=4?s=100" width="100px;" alt="Paweł Bylica"/><br /><sub><b>Paweł Bylica</b></sub></a><br /><a href="#platform-chfast" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PeteAudinate"><img src="https://avatars.githubusercontent.com/u/99274874?v=4?s=100" width="100px;" alt="PeteAudinate"/><br /><sub><b>PeteAudinate</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=PeteAudinate" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/peterazmanov"><img src="https://avatars0.githubusercontent.com/u/15322318?v=4?s=100" width="100px;" alt="Peter Azmanov"/><br /><sub><b>Peter Azmanov</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=peterazmanov" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/peterh"><img src="https://avatars.githubusercontent.com/u/79339?v=4?s=100" width="100px;" alt="Peter Harris"/><br /><sub><b>Peter Harris</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=peterh" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://ptheywood.uk/"><img src="https://avatars.githubusercontent.com/u/628937?v=4?s=100" width="100px;" alt="Peter Heywood"/><br /><sub><b>Peter Heywood</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ptheywood" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/phlptp"><img src="https://avatars0.githubusercontent.com/u/20667153?v=4?s=100" width="100px;" alt="Philip Top"/><br /><sub><b>Philip Top</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Aphlptp" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=phlptp" title="Documentation">📖</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=phlptp" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rafiw"><img src="https://avatars3.githubusercontent.com/u/3034707?v=4?s=100" width="100px;" alt="Rafi Wiener"/><br /><sub><b>Rafi Wiener</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Arafiw" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=rafiw" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RangeMachine"><img src="https://avatars.githubusercontent.com/u/11577601?v=4?s=100" width="100px;" alt="RangeMachine"/><br /><sub><b>RangeMachine</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=RangeMachine" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Krzmbrzl"><img src="https://avatars.githubusercontent.com/u/12751591?v=4?s=100" width="100px;" alt="Robert Adam"/><br /><sub><b>Robert Adam</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=Krzmbrzl" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://www.ratml.org/"><img src="https://avatars0.githubusercontent.com/u/1845039?v=4?s=100" width="100px;" alt="Ryan Curtin"/><br /><sub><b>Ryan Curtin</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=rcurtin" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SherlockInSpace"><img src="https://avatars.githubusercontent.com/u/5507786?v=4?s=100" width="100px;" alt="Ryan Sherlock"/><br /><sub><b>Ryan Sherlock</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=SherlockInSpace" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://sam.hocevar.net/"><img src="https://avatars2.githubusercontent.com/u/245089?v=4?s=100" width="100px;" alt="Sam Hocevar"/><br /><sub><b>Sam Hocevar</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=samhocevar" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://seanfisk.com/"><img src="https://avatars0.githubusercontent.com/u/410322?v=4?s=100" width="100px;" alt="Sean Fisk"/><br /><sub><b>Sean Fisk</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Aseanfisk" title="Bug reports">🐛</a> <a href="https://github.com/CLIUtils/CLI11/commits?author=seanfisk" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/delpinux"><img src="https://avatars0.githubusercontent.com/u/35096584?v=4?s=100" width="100px;" alt="Stéphane Del Pino"/><br /><sub><b>Stéphane Del Pino</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=delpinux" title="Code">💻</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/metopa"><img src="https://avatars2.githubusercontent.com/u/3974178?v=4?s=100" width="100px;" alt="Viacheslav Kroilov"/><br /><sub><b>Viacheslav Kroilov</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=metopa" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VolkerChristian"><img src="https://avatars.githubusercontent.com/u/18554540?v=4?s=100" width="100px;" alt="Volker Christian"/><br /><sub><b>Volker Christian</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=VolkerChristian" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/almikhayl"><img src="https://avatars2.githubusercontent.com/u/6747040?v=4?s=100" width="100px;" alt="almikhayl"/><br /><sub><b>almikhayl</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=almikhayl" title="Code">💻</a> <a href="#platform-almikhayl" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ayum"><img src="https://avatars.githubusercontent.com/u/6747040?v=4?s=100" width="100px;" alt="ayum"/><br /><sub><b>ayum</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ayum" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/captainurist"><img src="https://avatars.githubusercontent.com/u/73941350?v=4?s=100" width="100px;" alt="captainurist"/><br /><sub><b>captainurist</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=captainurist" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://cs.odu.edu/~ctsolakis"><img src="https://avatars0.githubusercontent.com/u/6725596?v=4?s=100" width="100px;" alt="christos"/><br /><sub><b>christos</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ChristosT" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/deining"><img src="https://avatars3.githubusercontent.com/u/18169566?v=4?s=100" width="100px;" alt="deining"/><br /><sub><b>deining</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=deining" title="Documentation">📖</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dherrera-fb"><img src="https://avatars.githubusercontent.com/u/89840711?v=4?s=100" width="100px;" alt="dherrera-fb"/><br /><sub><b>dherrera-fb</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=dherrera-fb" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/djerius"><img src="https://avatars.githubusercontent.com/u/196875?v=4?s=100" width="100px;" alt="djerius"/><br /><sub><b>djerius</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=djerius" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dryleev"><img src="https://avatars.githubusercontent.com/u/83670813?v=4?s=100" width="100px;" alt="dryleev"/><br /><sub><b>dryleev</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=dryleev" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elszon"><img src="https://avatars0.githubusercontent.com/u/2971495?v=4?s=100" width="100px;" alt="elszon"/><br /><sub><b>elszon</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=elszon" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ferdymercury"><img src="https://avatars3.githubusercontent.com/u/10653970?v=4?s=100" width="100px;" alt="ferdymercury"/><br /><sub><b>ferdymercury</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ferdymercury" title="Documentation">📖</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fpeng1985"><img src="https://avatars1.githubusercontent.com/u/87981?v=4?s=100" width="100px;" alt="fpeng1985"/><br /><sub><b>fpeng1985</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=fpeng1985" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geir-t"><img src="https://avatars3.githubusercontent.com/u/35292136?v=4?s=100" width="100px;" alt="geir-t"/><br /><sub><b>geir-t</b></sub></a><br /><a href="#platform-geir-t" title="Packaging/porting to new platform">📦</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gostefan"><img src="https://avatars.githubusercontent.com/u/2479455?v=4?s=100" width="100px;" alt="gostefan"/><br /><sub><b>gostefan</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=gostefan" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ncihnegn"><img src="https://avatars3.githubusercontent.com/u/12021721?v=4?s=100" width="100px;" alt="ncihnegn"/><br /><sub><b>ncihnegn</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ncihnegn" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nshaheed"><img src="https://avatars.githubusercontent.com/u/6963603?v=4?s=100" width="100px;" alt="nshaheed"/><br /><sub><b>nshaheed</b></sub></a><br /><a href="#platform-nshaheed" title="Packaging/porting to new platform">📦</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nurelin"><img src="https://avatars3.githubusercontent.com/u/5276274?v=4?s=100" width="100px;" alt="nurelin"/><br /><sub><b>nurelin</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=nurelin" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="http://polistern.i2p/"><img src="https://avatars.githubusercontent.com/u/55511995?v=4?s=100" width="100px;" alt="polistern"/><br /><sub><b>polistern</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=polistern" title="Code">💻</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ryan4729"><img src="https://avatars3.githubusercontent.com/u/40183301?v=4?s=100" width="100px;" alt="ryan4729"/><br /><sub><b>ryan4729</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ryan4729" title="Tests">⚠️</a></td>
|
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/shameekganguly"><img src="https://avatars.githubusercontent.com/u/2412842?v=4?s=100" width="100px;" alt="shameekganguly"/><br /><sub><b>shameekganguly</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=shameekganguly" title="Code">💻</a></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- markdownlint-restore -->
|
|
<!-- prettier-ignore-end -->
|
|
|
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
|
|
This project follows the
|
|
[all-contributors](https://github.com/all-contributors/all-contributors)
|
|
specification. Contributions of any kind welcome!
|
|
|
|
## License
|
|
|
|
As of version 1.0, this library is available under a 3-Clause BSD license. See
|
|
the [LICENSE](./LICENSE) file for details.
|
|
|
|
CLI11 was developed at the [University of Cincinnati][] to support of the
|
|
[GooFit][] library under [NSF Award 1414736][]. Version 0.9 was featured in a
|
|
[DIANA/HEP][] meeting at CERN ([see the slides][diana slides]). Please give it a
|
|
try! Feedback is always welcome.
|
|
|
|
[doi-badge]: https://zenodo.org/badge/80064252.svg
|
|
[doi-link]: https://zenodo.org/badge/latestdoi/80064252
|
|
[azure-badge]:
|
|
https://dev.azure.com/CLIUtils/CLI11/_apis/build/status/CLIUtils.CLI11?branchName=main
|
|
[azure]: https://dev.azure.com/CLIUtils/CLI11
|
|
[actions-link]: https://github.com/CLIUtils/CLI11/actions
|
|
[actions-badge]:
|
|
https://github.com/CLIUtils/CLI11/actions/workflows/tests.yml/badge.svg
|
|
[repology-badge]: https://repology.org/badge/latest-versions/cli11.svg
|
|
[repology]: https://repology.org/project/cli11/versions
|
|
[codecov-badge]:
|
|
https://codecov.io/gh/CLIUtils/CLI11/branch/main/graph/badge.svg?token=2O4wfs8NJO
|
|
[codecov]: https://codecov.io/gh/CLIUtils/CLI11
|
|
[gitter-badge]: https://badges.gitter.im/CLI11gitter/Lobby.svg
|
|
[gitter]: https://gitter.im/CLI11gitter/Lobby
|
|
[license-badge]: https://img.shields.io/badge/License-BSD-blue.svg
|
|
[conan-badge]: https://img.shields.io/badge/conan-io-blue
|
|
[conan-link]: https://conan.io/center/cli11
|
|
[conda-badge]: https://img.shields.io/conda/vn/conda-forge/cli11.svg
|
|
[conda-link]: https://github.com/conda-forge/cli11-feedstock
|
|
[github releases]: https://github.com/CLIUtils/CLI11/releases
|
|
[github issues]: https://github.com/CLIUtils/CLI11/issues
|
|
[github pull requests]: https://github.com/CLIUtils/CLI11/pulls
|
|
[goofit]: https://GooFit.github.io
|
|
[plumbum]: https://plumbum.readthedocs.io/en/latest/
|
|
[click]: http://click.pocoo.org
|
|
[api-docs]: https://CLIUtils.github.io/CLI11/index.html
|
|
[rang]: https://github.com/agauniyal/rang
|
|
[boost program options]:
|
|
http://www.boost.org/doc/libs/1_63_0/doc/html/program_options.html
|
|
[the lean mean c++ option parser]: http://optionparser.sourceforge.net
|
|
[tclap]: http://tclap.sourceforge.net
|
|
[cxxopts]: https://github.com/jarro2783/cxxopts
|
|
[docopt]: https://github.com/docopt/docopt.cpp
|
|
[gflags]: https://gflags.github.io/gflags
|
|
[getopt]: https://www.gnu.org/software/libc/manual/html_node/Getopt.html
|
|
[diana/hep]: http://diana-hep.org
|
|
[nsf award 1414736]: https://nsf.gov/awardsearch/showAward?AWD_ID=1414736
|
|
[university of cincinnati]: http://www.uc.edu
|
|
[gitbook]: https://cliutils.github.io/CLI11/book/
|
|
[cli11 advanced topics/custom converters]:
|
|
https://cliutils.gitlab.io/CLI11Tutorial/chapters/advanced-topics.html#custom-converters
|
|
[programoptions.hxx]: https://github.com/Fytch/ProgramOptions.hxx
|
|
[argument aggregator]: https://github.com/vietjtnguyen/argagg
|
|
[args]: https://github.com/Taywee/args
|
|
[argh!]: https://github.com/adishavit/argh
|
|
[fmt]: https://github.com/fmtlib/fmt
|
|
[catch]: https://github.com/philsquared/Catch
|
|
[clara]: https://github.com/philsquared/Clara
|
|
[version 1.0 post]: https://iscinumpy.gitlab.io/post/announcing-cli11-10/
|
|
[version 1.3 post]: https://iscinumpy.gitlab.io/post/announcing-cli11-13/
|
|
[version 1.6 post]: https://iscinumpy.gitlab.io/post/announcing-cli11-16/
|
|
[version 2.0 post]: https://iscinumpy.gitlab.io/post/announcing-cli11-20/
|
|
[wandbox-badge]: https://img.shields.io/badge/try_2.1-online-blue.svg
|
|
[wandbox-link]: https://wandbox.org/permlink/9eQyaD1DchlzukRv
|
|
[releases-badge]: https://img.shields.io/github/release/CLIUtils/CLI11.svg
|
|
[cli11-po-compare]:
|
|
https://iscinumpy.gitlab.io/post/comparing-cli11-and-boostpo/
|
|
[diana slides]:
|
|
https://indico.cern.ch/event/619465/contributions/2507949/attachments/1448567/2232649/20170424-diana-2.pdf
|
|
[awesome c++]: https://github.com/fffaraz/awesome-cpp/blob/master/README.md#cli
|
|
[cli]: https://codesynthesis.com/projects/cli/
|
|
[single file libs]:
|
|
https://github.com/nothings/single_file_libs/blob/master/README.md
|
|
[codacy-badge]:
|
|
https://app.codacy.com/project/badge/Grade/2796b969c1b54321a02ad08affec0800
|
|
[codacy-link]:
|
|
https://www.codacy.com/gh/CLIUtils/CLI11/dashboard?utm_source=github.com&utm_medium=referral&utm_content=CLIUtils/CLI11&utm_campaign=Badge_Grade
|
|
[hunter]: https://docs.hunter.sh/en/latest/packages/pkg/CLI11.html
|
|
[standard readme style]: https://github.com/RichardLitt/standard-readme
|
|
[argparse]: https://github.com/p-ranav/argparse
|
|
[toml]: https://toml.io
|
|
[lyra]: https://github.com/bfgroup/Lyra
|
|
[installation]: https://cliutils.github.io/CLI11/book/chapters/installation.html
|