mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 20:53:52 +00:00
Moved to storing unique_ptr of Options, better support for --help
This commit is contained in:
parent
2f08c4c7c3
commit
1bf66bc3e5
15
CHANGELOG.md
Normal file
15
CHANGELOG.md
Normal file
@ -0,0 +1,15 @@
|
||||
## Version 0.2
|
||||
|
||||
* Moved to simpler syntax, where `Option` pointers are returned and operated on
|
||||
* Removed `make_` style options
|
||||
* Simplified Validators, now only requires `->check(function)`
|
||||
* Removed Combiners
|
||||
* Fixed pointers to Options, stored in `unique_ptr` now
|
||||
* Added `Option_p` and `App_p`, mostly for internal use
|
||||
* Startup sequence, including help flag, can be modified by subclasses
|
||||
|
||||
## Version 0.1
|
||||
|
||||
Initial version
|
||||
|
||||
|
@ -15,7 +15,7 @@ endif()
|
||||
|
||||
# Be moderately paranoid with flags
|
||||
# But only globally, don't inherit
|
||||
add_compile_options(-pedantic -Wall -Wextra)
|
||||
add_compile_options(-pedantic -Wall -Wextra -O0)
|
||||
|
||||
add_library(CLI INTERFACE)
|
||||
target_include_directories(CLI INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
77
README.md
77
README.md
@ -15,7 +15,7 @@ The following attributes are what I believe are important in a CLI parser librar
|
||||
* Standard idioms supported naturally, like grouping flags, the positional seperator, 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".
|
||||
* Simple support for subcommands.
|
||||
* Human readable support for subcommands.
|
||||
|
||||
The major CLI parsers out there include:
|
||||
|
||||
@ -30,7 +30,7 @@ So, this library was designed to provide a great syntax, good compiler compatibi
|
||||
|
||||
To use, there are two methods.
|
||||
1. Copy `CLI11.hpp` from the [most recent release](https://github.com/henryiii/CLI11/releases) into your include directory, and you are set. This is combined from the source files for every release.
|
||||
2. To be added.
|
||||
2. Checkout the repository and add as a subdirectory for CMake. You can use the CLI interface target. (CMake 3.4+ recommended)
|
||||
|
||||
To build the tests, get the entire directory and use CMake:
|
||||
|
||||
@ -54,7 +54,7 @@ app.add_option("-f,--file", file, "A help string");
|
||||
|
||||
try {
|
||||
app.run(argc, argv);
|
||||
} catch (const CLI::Error &e) {
|
||||
} catch (const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
```
|
||||
@ -66,33 +66,44 @@ The supported values are:
|
||||
```
|
||||
app.add_options(option_name,
|
||||
variable_to_bind_to, // int, float, vector, or string-like
|
||||
help_string,
|
||||
flags, ...) // Listed below
|
||||
help_string="",
|
||||
default=false)
|
||||
|
||||
app.add_flag(option_name,
|
||||
optional_intlike_to_bind_to,
|
||||
help_string)
|
||||
int_or_bool = nothing,
|
||||
help_string="")
|
||||
|
||||
app.add_set(option_name,
|
||||
variable_to_bind_to,
|
||||
set_of_possible_options,
|
||||
flags, ...)
|
||||
help_string="",
|
||||
default=false)
|
||||
|
||||
App* subcom = app.add_subcommand(name, discription);
|
||||
|
||||
```
|
||||
|
||||
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. 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 help line for its positional form.
|
||||
|
||||
There are several flags:
|
||||
> ### Example
|
||||
>
|
||||
> * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--option`
|
||||
> * `"this"` Can only be passed positionally
|
||||
> * `"-a,-b,-c"` No limit to the number of non-positional option names
|
||||
|
||||
* `CLI::Default`: Print the default value in help
|
||||
* `CLI::Required`: The program will quit if this option is not present
|
||||
* `CLI::Opts(N)`: Take `N` values instead of as many as possible, only for vector args
|
||||
* `CLI::ExistingFile`: Requires that the file exists if given
|
||||
* `CLI::ExistingDirectory`: Requires that the directory exists
|
||||
* `CLI::NonexistentPath`: Requires that the path does not exist
|
||||
|
||||
Options can be given as:
|
||||
The add commands return a pointer to an internally stored `Option`. If you set the final argument to true, the default value is captured and printed on the command line with the help flag. This option can be used direcly to check for the count (`->count()`) after parsing to avoid a string based lookup. Before parsing, you can set the following options:
|
||||
|
||||
* `->required()`: The program will quit if this option is not present
|
||||
* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args
|
||||
* `->check(CLI::ExistingFile)`: Requires that the file exists if given
|
||||
* `->check(CLI::ExistingDirectory)`: Requires that the directory exists
|
||||
* `->check(CLI::NonexistentPath)`: Requires that the path does not exist
|
||||
|
||||
These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`.
|
||||
|
||||
|
||||
On the command line, options can be given as:
|
||||
|
||||
* `-a` (flag)
|
||||
* `-abc` (flags can be combined)
|
||||
@ -103,8 +114,6 @@ Options can be given as:
|
||||
* `--file filename` (space)
|
||||
* `--file=filename` (equals)
|
||||
|
||||
An option must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. 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 help line for its positional form.
|
||||
|
||||
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 `--` is present in the command line,
|
||||
everything after that is positional only.
|
||||
@ -121,40 +130,14 @@ even exit the program through the callback. The main `App` has a callback slot,
|
||||
|
||||
> ## Subclassing
|
||||
>
|
||||
> The App class was designed allow toolkits to subclass it, to provide default options and setup/teardown code. Subcommands remain `App`'s, since those are not expected to need setup and teardown. The default `App` only adds a help flag, `-h,--help`.
|
||||
> The App class was designed allow toolkits to subclass it, to provide default options and setup/teardown code. Subcommands remain `App`'s, since those are not expected to need setup and teardown. The default `App` only adds a help flag, `-h,--help` through the `virtual void setup()` method. If you only want to change this flag, override this method. Since subcommands are always the built in `App` object, they must have a normal help flag.
|
||||
>
|
||||
> Also, in a related note, the `App`s you get a pointer to are stored in the parent `App` and cannot be deleted.
|
||||
> Also, in a related note, the `App`s you get a pointer to are stored in the parent `App` in `unique_ptr`s (like `Option`s) and are deleted when the main `App` goes out of scope.
|
||||
|
||||
## Make syntax
|
||||
|
||||
A second, provisional syntax looks like this:
|
||||
|
||||
```cpp
|
||||
CLI::App app{"App description"};
|
||||
|
||||
auto filename = app.add_option("-f,--file", "default", "A help string");
|
||||
auto int_value = app.add_option<int>("-i,--int", "An int with no default");
|
||||
|
||||
try {
|
||||
app.run(argc, argv);
|
||||
} catch (const CLI::Error &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
std::cout << "The file was: " << *filename << std::endl;
|
||||
std::cout << "This will throw an error if int not passed: " << *int_value << std::endl;
|
||||
```
|
||||
|
||||
|
||||
Internally, it uses the same mechanism to work, it just provides a single line definition, but requires a template argument for non-strings, and creates an object that must be dereferenced to be used. This object (`CLI::Value<type>`) supports conversion to bool, allowing you to easily check if an option was passed without resorting to count. Dereferencing will also throw an error if no value was passed and no default was given.
|
||||
|
||||
The same functions as the first syntax are supported, only with `make` instead of `add`, and with the variable to bind to replaced by the default value (optional). If you want to use something other than a string option and do not want to give a default, you need to give a template parameter with the type.
|
||||
|
||||
`Value` wraps a `shared_ptr` to a `unique_ptr` to a value, so it lasts even if the `App` object is destructed.
|
||||
|
||||
## How it works
|
||||
|
||||
Every `make_` or `add_` option you've seen 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 vector of strings, so it knows how many times an option was passed, and how many arguments each passing received (flags add empty strings to keep the counts correct). The lambda returns true if it could validate the option strings, and
|
||||
Every `add_` option you've seen 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 vector of strings, so it knows how many times an option was passed, and how many arguments each passing received (flags add empty strings to keep the counts correct). The lambda returns true if it could validate the option strings, and
|
||||
false if it failed.
|
||||
|
||||
|
||||
|
@ -6,13 +6,13 @@ int main (int argc, char** argv) {
|
||||
CLI::App app("K3Pi goofit fitter");
|
||||
|
||||
std::string file;
|
||||
app.add_option("-f,--file,file", file, "File name");
|
||||
CLI::Option* opt = app.add_option("-f,--file,file", file, "File name");
|
||||
|
||||
int count;
|
||||
app.add_flag("-c,--count", count, "Counter");
|
||||
CLI::Option* copt = app.add_flag("-c,--count", count, "Counter");
|
||||
|
||||
double value = 3.14;
|
||||
app.add_option("-d,--double", value, "Some Value", false);
|
||||
double value;// = 3.14;
|
||||
app.add_option("-d,--double", value, "Some Value");
|
||||
|
||||
try {
|
||||
app.run(argc, argv);
|
||||
@ -20,8 +20,14 @@ int main (int argc, char** argv) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << app.count("--file") << std::endl;
|
||||
std::cout << "Working on count: " << count << ", direct count: " << app.count("--count") << std::endl;
|
||||
std::cout << "Working on file: " << file
|
||||
<< ", direct count: " << app.count("--file")
|
||||
<< ", opt count: " << opt->count()
|
||||
<< std::endl;
|
||||
std::cout << "Working on count: " << count
|
||||
<< ", direct count: " << app.count("--count")
|
||||
<< ", opt count: " << copt->count()
|
||||
<< std::endl;
|
||||
std::cout << "Some value: " << value << std::endl;
|
||||
|
||||
return 0;
|
||||
|
@ -11,8 +11,7 @@ int main (int argc, char** argv) {
|
||||
std::string file;
|
||||
start->add_option("-f,--file", file, "File name");
|
||||
|
||||
int count;
|
||||
stop->add_flag("-c,--count", count, "Counter");
|
||||
CLI::Option* s = stop->add_flag("-c,--count", "Counter");
|
||||
|
||||
try {
|
||||
app.run(argc, argv);
|
||||
@ -21,7 +20,7 @@ int main (int argc, char** argv) {
|
||||
}
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << start->count("--file") << std::endl;
|
||||
std::cout << "Working on count: " << count << ", direct count: " << stop->count("--count") << std::endl;
|
||||
std::cout << "Working on count: " << s->count() << ", direct count: " << stop->count("--count") << std::endl;
|
||||
if(app.get_subcommand() != nullptr)
|
||||
std::cout << "Subcommand:" << app.get_subcommand()->get_name() << std::endl;
|
||||
|
||||
|
@ -26,6 +26,11 @@ namespace CLI {
|
||||
|
||||
enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND};
|
||||
|
||||
class App;
|
||||
|
||||
typedef std::unique_ptr<Option> Option_p;
|
||||
typedef std::unique_ptr<App> App_p;
|
||||
|
||||
/// Creates a command line program, with very few defaults.
|
||||
/** To use, create a new Program() instance with argc, argv, and a help description. The templated
|
||||
* add_option methods make it easy to prepare options. Remember to call `.start` before starting your
|
||||
@ -35,14 +40,14 @@ protected:
|
||||
|
||||
std::string name;
|
||||
std::string prog_description;
|
||||
std::vector<Option> options;
|
||||
Option* help_flag {nullptr};
|
||||
std::vector<Option_p> options;
|
||||
std::vector<std::string> missing_options;
|
||||
std::deque<std::string> positionals;
|
||||
std::vector<std::unique_ptr<App>> subcommands;
|
||||
std::vector<App_p> subcommands;
|
||||
bool parsed{false};
|
||||
App* subcommand{nullptr};
|
||||
std::string progname{"program"};
|
||||
Option* help_flag {nullptr};
|
||||
|
||||
std::function<void()> app_callback;
|
||||
|
||||
@ -67,10 +72,10 @@ public:
|
||||
parsed = false;
|
||||
subcommand = nullptr;
|
||||
|
||||
for(Option& opt : options) {
|
||||
opt.clear();
|
||||
for(const Option_p &opt : options) {
|
||||
opt->clear();
|
||||
}
|
||||
for(std::unique_ptr<App> &app : subcommands) {
|
||||
for(const App_p &app : subcommands) {
|
||||
app->reset();
|
||||
}
|
||||
}
|
||||
@ -100,8 +105,8 @@ public:
|
||||
* After start is called, you can use count to see if the value was passed, and
|
||||
* the value will be initialized properly.
|
||||
*
|
||||
* Program::Required, Program::Default, and the validators are options, and can be `|`
|
||||
* together. The positional options take an optional number of arguments.
|
||||
* ->required(), ->default, and the validators are options,
|
||||
* The positional options take an optional number of arguments.
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
@ -112,14 +117,17 @@ public:
|
||||
std::string name,
|
||||
callback_t callback,
|
||||
std::string description="",
|
||||
bool defaulted=true
|
||||
bool defaulted=false
|
||||
) {
|
||||
Option myopt{name, description, callback, defaulted};
|
||||
if(std::find(std::begin(options), std::end(options), myopt) == std::end(options))
|
||||
options.push_back(myopt);
|
||||
else
|
||||
if(std::find_if(std::begin(options), std::end(options),
|
||||
[&myopt](const Option_p &v){return *v == myopt;}) == std::end(options)) {
|
||||
options.emplace_back();
|
||||
Option_p& option = options.back();
|
||||
option.reset(new Option(name, description, callback, defaulted));
|
||||
return option.get();
|
||||
} else
|
||||
throw OptionAlreadyAdded(myopt.get_name());
|
||||
return &options.back();
|
||||
|
||||
}
|
||||
|
||||
@ -129,7 +137,7 @@ public:
|
||||
std::string name,
|
||||
T &variable, ///< The variable to set
|
||||
std::string description="",
|
||||
bool defaulted=true
|
||||
bool defaulted=false
|
||||
) {
|
||||
|
||||
|
||||
@ -159,7 +167,7 @@ public:
|
||||
std::string name,
|
||||
std::vector<T> &variable, ///< The variable vector to set
|
||||
std::string description="",
|
||||
bool defaulted=true
|
||||
bool defaulted=false
|
||||
) {
|
||||
|
||||
CLI::callback_t fun = [&variable](CLI::results_t res){
|
||||
@ -173,9 +181,6 @@ public:
|
||||
return variable.size() > 0 && retval;
|
||||
};
|
||||
|
||||
if(variable.size() == 0)
|
||||
defaulted = false;
|
||||
|
||||
Option* retval = add_option(name, fun, description, defaulted);
|
||||
retval->allow_vector = true;
|
||||
retval->_expected = -1;
|
||||
@ -252,12 +257,12 @@ public:
|
||||
Option* add_set(
|
||||
std::string name,
|
||||
T &member, ///< The selected member of the set
|
||||
std::set<T> options, ///< The set of posibilities
|
||||
std::set<T> _options, ///< The set of posibilities
|
||||
std::string description="",
|
||||
bool defaulted=true
|
||||
bool defaulted=false
|
||||
) {
|
||||
|
||||
CLI::callback_t fun = [&member, options](CLI::results_t res){
|
||||
CLI::callback_t fun = [&member, _options](CLI::results_t res){
|
||||
if(res.size()!=1) {
|
||||
return false;
|
||||
}
|
||||
@ -267,15 +272,17 @@ public:
|
||||
bool retval = detail::lexical_cast(res[0][0], member);
|
||||
if(!retval)
|
||||
return false;
|
||||
return std::find(std::begin(options), std::end(options), member) != std::end(options);
|
||||
return std::find(std::begin(_options), std::end(_options), member) != std::end(_options);
|
||||
};
|
||||
|
||||
Option* retval = add_option(name, fun, description, defaulted);
|
||||
retval->typeval = detail::type_name<T>();
|
||||
retval->typeval += " in {" + detail::join(options) + "}";
|
||||
retval->typeval += " in {" + detail::join(_options) + "}";
|
||||
if(defaulted) {
|
||||
std::stringstream out;
|
||||
out << member;
|
||||
retval->defaultval = out.str();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -328,17 +335,17 @@ public:
|
||||
|
||||
|
||||
|
||||
for(Option& opt : options) {
|
||||
while (opt.get_positional() && opt.count() < opt.get_expected() && positionals.size() > 0) {
|
||||
opt.get_new();
|
||||
opt.add_result(0, positionals.front());
|
||||
for(const Option_p& opt : options) {
|
||||
while (opt->get_positional() && opt->count() < opt->get_expected() && positionals.size() > 0) {
|
||||
opt->get_new();
|
||||
opt->add_result(0, positionals.front());
|
||||
positionals.pop_front();
|
||||
}
|
||||
if (opt.get_required() && opt.count() < opt.get_expected())
|
||||
throw RequiredError(opt.get_name());
|
||||
if (opt.count() > 0) {
|
||||
if(!opt.run_callback())
|
||||
throw ConversionError(opt.get_name());
|
||||
if (opt->get_required() && opt->count() < opt->get_expected())
|
||||
throw RequiredError(opt->get_name());
|
||||
if (opt->count() > 0) {
|
||||
if(!opt->run_callback())
|
||||
throw ConversionError(opt->get_name());
|
||||
}
|
||||
|
||||
}
|
||||
@ -350,7 +357,7 @@ public:
|
||||
}
|
||||
|
||||
void _parse_subcommand(std::vector<std::string> &args) {
|
||||
for(std::unique_ptr<App> &com : subcommands) {
|
||||
for(const App_p &com : subcommands) {
|
||||
if(com->name == args.back()){
|
||||
args.pop_back();
|
||||
subcommand = com.get();
|
||||
@ -370,13 +377,16 @@ public:
|
||||
throw HorribleError("Short");
|
||||
args.pop_back();
|
||||
|
||||
auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_sname(name);});
|
||||
auto op_ptr = std::find_if(std::begin(options), std::end(options), [name](const Option_p &opt){return opt->check_sname(name);});
|
||||
|
||||
if(op == std::end(options)) {
|
||||
if(op_ptr == std::end(options)) {
|
||||
missing_options.push_back("-" + name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a reference to the pointer to make syntax bearable
|
||||
Option_p& op = *op_ptr;
|
||||
|
||||
int vnum = op->get_new();
|
||||
int num = op->get_expected();
|
||||
|
||||
@ -414,7 +424,7 @@ public:
|
||||
|
||||
if(current == "--")
|
||||
return Classifer::POSITIONAL_MARK;
|
||||
for(const std::unique_ptr<App> &com : subcommands) {
|
||||
for(const App_p &com : subcommands) {
|
||||
if(com->name == current)
|
||||
return Classifer::SUBCOMMAND;
|
||||
}
|
||||
@ -434,13 +444,15 @@ public:
|
||||
throw HorribleError("Long");
|
||||
args.pop_back();
|
||||
|
||||
auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_lname(name);});
|
||||
auto op_ptr = std::find_if(std::begin(options), std::end(options), [name](const Option_p &v){return v->check_lname(name);});
|
||||
|
||||
if(op == std::end(options)) {
|
||||
if(op_ptr == std::end(options)) {
|
||||
missing_options.push_back("--" + name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a reference to the pointer to make syntax bearable
|
||||
Option_p& op = *op_ptr;
|
||||
|
||||
int vnum = op->get_new();
|
||||
int num = op->get_expected();
|
||||
@ -488,9 +500,9 @@ public:
|
||||
|
||||
/// Counts the number of times the given option was passed.
|
||||
int count(std::string name) const {
|
||||
for(const Option &opt : options) {
|
||||
if(opt.check_name(name)) {
|
||||
return opt.count();
|
||||
for(const Option_p &opt : options) {
|
||||
if(opt->check_name(name)) {
|
||||
return opt->count();
|
||||
}
|
||||
}
|
||||
throw OptionNotFound(name);
|
||||
@ -512,8 +524,8 @@ public:
|
||||
|
||||
// Check for options
|
||||
bool npos = false;
|
||||
for(const Option &opt : options) {
|
||||
if(opt.nonpositional()) {
|
||||
for(const Option_p &opt : options) {
|
||||
if(opt->nonpositional()) {
|
||||
npos = true;
|
||||
break;
|
||||
}
|
||||
@ -524,10 +536,10 @@ public:
|
||||
|
||||
// Positionals
|
||||
bool pos=false;
|
||||
for(const Option &opt : options)
|
||||
if(opt.get_positional()) {
|
||||
out << " " << opt.help_positional();
|
||||
if(opt.has_description())
|
||||
for(const Option_p &opt : options)
|
||||
if(opt->get_positional()) {
|
||||
out << " " << opt->help_positional();
|
||||
if(opt->has_description())
|
||||
pos=true;
|
||||
}
|
||||
|
||||
@ -536,9 +548,9 @@ public:
|
||||
// Positional descriptions
|
||||
if(pos) {
|
||||
out << "Positionals:" << std::endl;
|
||||
for(const Option &opt : options)
|
||||
if(opt.get_positional() && opt.has_description())
|
||||
detail::format_help(out, opt.get_pname(), opt.get_description(), wid);
|
||||
for(const Option_p &opt : options)
|
||||
if(opt->get_positional() && opt->has_description())
|
||||
detail::format_help(out, opt->get_pname(), opt->get_description(), wid);
|
||||
out << std::endl;
|
||||
|
||||
}
|
||||
@ -547,9 +559,9 @@ public:
|
||||
// Options
|
||||
if(npos) {
|
||||
out << "Options:" << std::endl;
|
||||
for(const Option &opt : options) {
|
||||
if(opt.nonpositional())
|
||||
detail::format_help(out, opt.help_name(), opt.get_description(), wid);
|
||||
for(const Option_p &opt : options) {
|
||||
if(opt->nonpositional())
|
||||
detail::format_help(out, opt->help_name(), opt->get_description(), wid);
|
||||
|
||||
}
|
||||
out << std::endl;
|
||||
@ -558,7 +570,7 @@ public:
|
||||
// Subcommands
|
||||
if(subcommands.size()> 0) {
|
||||
out << "Subcommands:" << std::endl;
|
||||
for(const std::unique_ptr<App> &com : subcommands)
|
||||
for(const App_p &com : subcommands)
|
||||
detail::format_help(out, com->get_name(), com->prog_description, wid);
|
||||
}
|
||||
return out.str();
|
||||
|
@ -18,16 +18,6 @@ struct Error : public std::runtime_error {
|
||||
Error(std::string parent, std::string name, int exit_code=255, bool print_help=true) : runtime_error(parent + ": " + name), exit_code(exit_code), print_help(print_help) {}
|
||||
};
|
||||
|
||||
/// This is a successful completion on parsing, supposed to exit
|
||||
struct Success : public Error {
|
||||
Success() : Error("Success", "Successfully completed, should be caught and quit", 0, false) {}
|
||||
};
|
||||
|
||||
/// -h or --help on command line
|
||||
struct CallForHelp : public Error {
|
||||
CallForHelp() : Error("CallForHelp", "This should be caught in your main function, see examples", 0) {}
|
||||
};
|
||||
|
||||
// Construction errors (not in parsing)
|
||||
|
||||
struct ConstructionError : public Error {
|
||||
@ -51,10 +41,24 @@ struct OptionAlreadyAdded : public ConstructionError {
|
||||
|
||||
// Parsing errors
|
||||
|
||||
/// Anything that can error in Parse
|
||||
struct ParseError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Not really "errors"
|
||||
|
||||
/// This is a successful completion on parsing, supposed to exit
|
||||
struct Success : public ParseError {
|
||||
Success() : ParseError("Success", "Successfully completed, should be caught and quit", 0, false) {}
|
||||
};
|
||||
|
||||
/// -h or --help on command line
|
||||
struct CallForHelp : public ParseError {
|
||||
CallForHelp() : ParseError("CallForHelp", "This should be caught in your main function, see examples", 0) {}
|
||||
};
|
||||
|
||||
|
||||
/// Thrown when conversion call back fails, such as when an int fails to coerse to a string
|
||||
struct ConversionError : public ParseError {
|
||||
ConversionError(std::string name) : ParseError("ConversionError", name, 2) {}
|
||||
@ -75,6 +79,8 @@ struct HorribleError : public ParseError {
|
||||
HorribleError(std::string name) : ParseError("HorribleError", "(You should never see this error) " + name, 7) {}
|
||||
};
|
||||
|
||||
// After parsing
|
||||
|
||||
/// Thrown when counting a non-existent option
|
||||
struct OptionNotFound : public Error {
|
||||
OptionNotFound(std::string name) : Error("OptionNotFound", name, 4) {}
|
||||
|
@ -43,7 +43,7 @@ protected:
|
||||
std::vector<std::function<bool(std::string)>> _validators;
|
||||
|
||||
// Results
|
||||
results_t results {};
|
||||
results_t results;
|
||||
|
||||
|
||||
public:
|
||||
@ -206,8 +206,8 @@ public:
|
||||
/// Count the total number of times an option was passed
|
||||
int count() const {
|
||||
int out = 0;
|
||||
for(const std::vector<std::string>& v : results)
|
||||
out += v.size();
|
||||
for(const std::vector<std::string>& vec : results)
|
||||
out += vec.size();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user