Commit 1bf66bc3e5394910c5716ea98c81b7e1f411eeb0

Authored by Henry Fredrick Schreiner
1 parent 2f08c4c7

Moved to storing unique_ptr of Options, better support for --help

CHANGELOG.md 0 → 100644
  1 +## Version 0.2
  2 +
  3 +* Moved to simpler syntax, where `Option` pointers are returned and operated on
  4 +* Removed `make_` style options
  5 +* Simplified Validators, now only requires `->check(function)`
  6 +* Removed Combiners
  7 +* Fixed pointers to Options, stored in `unique_ptr` now
  8 +* Added `Option_p` and `App_p`, mostly for internal use
  9 +* Startup sequence, including help flag, can be modified by subclasses
  10 +
  11 +## Version 0.1
  12 +
  13 +Initial version
  14 +
  15 +
CMakeLists.txt
@@ -15,7 +15,7 @@ endif() @@ -15,7 +15,7 @@ endif()
15 15
16 # Be moderately paranoid with flags 16 # Be moderately paranoid with flags
17 # But only globally, don't inherit 17 # But only globally, don't inherit
18 -add_compile_options(-pedantic -Wall -Wextra) 18 +add_compile_options(-pedantic -Wall -Wextra -O0)
19 19
20 add_library(CLI INTERFACE) 20 add_library(CLI INTERFACE)
21 target_include_directories(CLI INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") 21 target_include_directories(CLI INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
README.md
@@ -15,7 +15,7 @@ The following attributes are what I believe are important in a CLI parser librar @@ -15,7 +15,7 @@ The following attributes are what I believe are important in a CLI parser librar
15 * Standard idioms supported naturally, like grouping flags, the positional seperator, etc. 15 * Standard idioms supported naturally, like grouping flags, the positional seperator, etc.
16 * Easy to execute, with help, parse errors, etc. providing correct exit and details. 16 * Easy to execute, with help, parse errors, etc. providing correct exit and details.
17 * Easy to extend as part of a framework that provides "applications". 17 * Easy to extend as part of a framework that provides "applications".
18 -* Simple support for subcommands. 18 +* Human readable support for subcommands.
19 19
20 The major CLI parsers out there include: 20 The major CLI parsers out there include:
21 21
@@ -30,7 +30,7 @@ So, this library was designed to provide a great syntax, good compiler compatibi @@ -30,7 +30,7 @@ So, this library was designed to provide a great syntax, good compiler compatibi
30 30
31 To use, there are two methods. 31 To use, there are two methods.
32 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. 32 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.
33 -2. To be added. 33 +2. Checkout the repository and add as a subdirectory for CMake. You can use the CLI interface target. (CMake 3.4+ recommended)
34 34
35 To build the tests, get the entire directory and use CMake: 35 To build the tests, get the entire directory and use CMake:
36 36
@@ -54,7 +54,7 @@ app.add_option("-f,--file", file, "A help string"); @@ -54,7 +54,7 @@ app.add_option("-f,--file", file, "A help string");
54 54
55 try { 55 try {
56 app.run(argc, argv); 56 app.run(argc, argv);
57 -} catch (const CLI::Error &e) { 57 +} catch (const CLI::ParseError &e) {
58 return app.exit(e); 58 return app.exit(e);
59 } 59 }
60 ``` 60 ```
@@ -66,33 +66,44 @@ The supported values are: @@ -66,33 +66,44 @@ The supported values are:
66 ``` 66 ```
67 app.add_options(option_name, 67 app.add_options(option_name,
68 variable_to_bind_to, // int, float, vector, or string-like 68 variable_to_bind_to, // int, float, vector, or string-like
69 - help_string,  
70 - flags, ...) // Listed below 69 + help_string="",
  70 + default=false)
71 71
72 app.add_flag(option_name, 72 app.add_flag(option_name,
73 - optional_intlike_to_bind_to,  
74 - help_string) 73 + int_or_bool = nothing,
  74 + help_string="")
75 75
76 app.add_set(option_name, 76 app.add_set(option_name,
77 variable_to_bind_to, 77 variable_to_bind_to,
78 set_of_possible_options, 78 set_of_possible_options,
79 - flags, ...) 79 + help_string="",
  80 + default=false)
80 81
81 App* subcom = app.add_subcommand(name, discription); 82 App* subcom = app.add_subcommand(name, discription);
82 83
83 ``` 84 ```
84 85
  86 +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.
85 87
86 -There are several flags: 88 +> ### Example
  89 +>
  90 +> * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--option`
  91 +> * `"this"` Can only be passed positionally
  92 +> * `"-a,-b,-c"` No limit to the number of non-positional option names
  93 +
  94 +
  95 +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:
87 96
88 -* `CLI::Default`: Print the default value in help  
89 -* `CLI::Required`: The program will quit if this option is not present  
90 -* `CLI::Opts(N)`: Take `N` values instead of as many as possible, only for vector args  
91 -* `CLI::ExistingFile`: Requires that the file exists if given  
92 -* `CLI::ExistingDirectory`: Requires that the directory exists  
93 -* `CLI::NonexistentPath`: Requires that the path does not exist 97 +* `->required()`: The program will quit if this option is not present
  98 +* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args
  99 +* `->check(CLI::ExistingFile)`: Requires that the file exists if given
  100 +* `->check(CLI::ExistingDirectory)`: Requires that the directory exists
  101 +* `->check(CLI::NonexistentPath)`: Requires that the path does not exist
94 102
95 -Options can be given as: 103 +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)`.
  104 +
  105 +
  106 +On the command line, options can be given as:
96 107
97 * `-a` (flag) 108 * `-a` (flag)
98 * `-abc` (flags can be combined) 109 * `-abc` (flags can be combined)
@@ -103,8 +114,6 @@ Options can be given as: @@ -103,8 +114,6 @@ Options can be given as:
103 * `--file filename` (space) 114 * `--file filename` (space)
104 * `--file=filename` (equals) 115 * `--file=filename` (equals)
105 116
106 -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.  
107 -  
108 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 117 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
109 If `--` is present in the command line, 118 If `--` is present in the command line,
110 everything after that is positional only. 119 everything after that is positional only.
@@ -121,40 +130,14 @@ even exit the program through the callback. The main `App` has a callback slot, @@ -121,40 +130,14 @@ even exit the program through the callback. The main `App` has a callback slot,
121 130
122 > ## Subclassing 131 > ## Subclassing
123 > 132 >
124 -> 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`. 133 +> 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.
125 > 134 >
126 -> Also, in a related note, the `App`s you get a pointer to are stored in the parent `App` and cannot be deleted.  
127 -  
128 -## Make syntax  
129 -  
130 -A second, provisional syntax looks like this:  
131 -  
132 -```cpp  
133 -CLI::App app{"App description"};  
134 -  
135 -auto filename = app.add_option("-f,--file", "default", "A help string");  
136 -auto int_value = app.add_option<int>("-i,--int", "An int with no default");  
137 -  
138 -try {  
139 - app.run(argc, argv);  
140 -} catch (const CLI::Error &e) {  
141 - return app.exit(e);  
142 -}  
143 -  
144 -std::cout << "The file was: " << *filename << std::endl;  
145 -std::cout << "This will throw an error if int not passed: " << *int_value << std::endl;  
146 -```  
147 -  
148 -  
149 -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.  
150 -  
151 -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. 135 +> 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.
152 136
153 -`Value` wraps a `shared_ptr` to a `unique_ptr` to a value, so it lasts even if the `App` object is destructed.  
154 137
155 ## How it works 138 ## How it works
156 139
157 -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 140 +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
158 false if it failed. 141 false if it failed.
159 142
160 143
examples/try.cpp
@@ -6,13 +6,13 @@ int main (int argc, char** argv) { @@ -6,13 +6,13 @@ int main (int argc, char** argv) {
6 CLI::App app("K3Pi goofit fitter"); 6 CLI::App app("K3Pi goofit fitter");
7 7
8 std::string file; 8 std::string file;
9 - app.add_option("-f,--file,file", file, "File name"); 9 + CLI::Option* opt = app.add_option("-f,--file,file", file, "File name");
10 10
11 int count; 11 int count;
12 - app.add_flag("-c,--count", count, "Counter"); 12 + CLI::Option* copt = app.add_flag("-c,--count", count, "Counter");
13 13
14 - double value = 3.14;  
15 - app.add_option("-d,--double", value, "Some Value", false); 14 + double value;// = 3.14;
  15 + app.add_option("-d,--double", value, "Some Value");
16 16
17 try { 17 try {
18 app.run(argc, argv); 18 app.run(argc, argv);
@@ -20,8 +20,14 @@ int main (int argc, char** argv) { @@ -20,8 +20,14 @@ int main (int argc, char** argv) {
20 return app.exit(e); 20 return app.exit(e);
21 } 21 }
22 22
23 - std::cout << "Working on file: " << file << ", direct count: " << app.count("--file") << std::endl;  
24 - std::cout << "Working on count: " << count << ", direct count: " << app.count("--count") << std::endl; 23 + std::cout << "Working on file: " << file
  24 + << ", direct count: " << app.count("--file")
  25 + << ", opt count: " << opt->count()
  26 + << std::endl;
  27 + std::cout << "Working on count: " << count
  28 + << ", direct count: " << app.count("--count")
  29 + << ", opt count: " << copt->count()
  30 + << std::endl;
25 std::cout << "Some value: " << value << std::endl; 31 std::cout << "Some value: " << value << std::endl;
26 32
27 return 0; 33 return 0;
examples/try1.cpp
@@ -11,8 +11,7 @@ int main (int argc, char** argv) { @@ -11,8 +11,7 @@ int main (int argc, char** argv) {
11 std::string file; 11 std::string file;
12 start->add_option("-f,--file", file, "File name"); 12 start->add_option("-f,--file", file, "File name");
13 13
14 - int count;  
15 - stop->add_flag("-c,--count", count, "Counter"); 14 + CLI::Option* s = stop->add_flag("-c,--count", "Counter");
16 15
17 try { 16 try {
18 app.run(argc, argv); 17 app.run(argc, argv);
@@ -21,7 +20,7 @@ int main (int argc, char** argv) { @@ -21,7 +20,7 @@ int main (int argc, char** argv) {
21 } 20 }
22 21
23 std::cout << "Working on file: " << file << ", direct count: " << start->count("--file") << std::endl; 22 std::cout << "Working on file: " << file << ", direct count: " << start->count("--file") << std::endl;
24 - std::cout << "Working on count: " << count << ", direct count: " << stop->count("--count") << std::endl; 23 + std::cout << "Working on count: " << s->count() << ", direct count: " << stop->count("--count") << std::endl;
25 if(app.get_subcommand() != nullptr) 24 if(app.get_subcommand() != nullptr)
26 std::cout << "Subcommand:" << app.get_subcommand()->get_name() << std::endl; 25 std::cout << "Subcommand:" << app.get_subcommand()->get_name() << std::endl;
27 26
include/CLI/App.hpp
@@ -26,6 +26,11 @@ namespace CLI { @@ -26,6 +26,11 @@ namespace CLI {
26 26
27 enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND}; 27 enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND};
28 28
  29 +class App;
  30 +
  31 +typedef std::unique_ptr<Option> Option_p;
  32 +typedef std::unique_ptr<App> App_p;
  33 +
29 /// Creates a command line program, with very few defaults. 34 /// Creates a command line program, with very few defaults.
30 /** To use, create a new Program() instance with argc, argv, and a help description. The templated 35 /** To use, create a new Program() instance with argc, argv, and a help description. The templated
31 * add_option methods make it easy to prepare options. Remember to call `.start` before starting your 36 * add_option methods make it easy to prepare options. Remember to call `.start` before starting your
@@ -35,14 +40,14 @@ protected: @@ -35,14 +40,14 @@ protected:
35 40
36 std::string name; 41 std::string name;
37 std::string prog_description; 42 std::string prog_description;
38 - std::vector<Option> options;  
39 - Option* help_flag {nullptr}; 43 + std::vector<Option_p> options;
40 std::vector<std::string> missing_options; 44 std::vector<std::string> missing_options;
41 std::deque<std::string> positionals; 45 std::deque<std::string> positionals;
42 - std::vector<std::unique_ptr<App>> subcommands; 46 + std::vector<App_p> subcommands;
43 bool parsed{false}; 47 bool parsed{false};
44 App* subcommand{nullptr}; 48 App* subcommand{nullptr};
45 std::string progname{"program"}; 49 std::string progname{"program"};
  50 + Option* help_flag {nullptr};
46 51
47 std::function<void()> app_callback; 52 std::function<void()> app_callback;
48 53
@@ -67,10 +72,10 @@ public: @@ -67,10 +72,10 @@ public:
67 parsed = false; 72 parsed = false;
68 subcommand = nullptr; 73 subcommand = nullptr;
69 74
70 - for(Option& opt : options) {  
71 - opt.clear(); 75 + for(const Option_p &opt : options) {
  76 + opt->clear();
72 } 77 }
73 - for(std::unique_ptr<App> &app : subcommands) { 78 + for(const App_p &app : subcommands) {
74 app->reset(); 79 app->reset();
75 } 80 }
76 } 81 }
@@ -100,8 +105,8 @@ public: @@ -100,8 +105,8 @@ public:
100 * After start is called, you can use count to see if the value was passed, and 105 * After start is called, you can use count to see if the value was passed, and
101 * the value will be initialized properly. 106 * the value will be initialized properly.
102 * 107 *
103 - * Program::Required, Program::Default, and the validators are options, and can be `|`  
104 - * together. The positional options take an optional number of arguments. 108 + * ->required(), ->default, and the validators are options,
  109 + * The positional options take an optional number of arguments.
105 * 110 *
106 * For example, 111 * For example,
107 * 112 *
@@ -112,14 +117,17 @@ public: @@ -112,14 +117,17 @@ public:
112 std::string name, 117 std::string name,
113 callback_t callback, 118 callback_t callback,
114 std::string description="", 119 std::string description="",
115 - bool defaulted=true 120 + bool defaulted=false
116 ) { 121 ) {
117 Option myopt{name, description, callback, defaulted}; 122 Option myopt{name, description, callback, defaulted};
118 - if(std::find(std::begin(options), std::end(options), myopt) == std::end(options))  
119 - options.push_back(myopt);  
120 - else 123 + if(std::find_if(std::begin(options), std::end(options),
  124 + [&myopt](const Option_p &v){return *v == myopt;}) == std::end(options)) {
  125 + options.emplace_back();
  126 + Option_p& option = options.back();
  127 + option.reset(new Option(name, description, callback, defaulted));
  128 + return option.get();
  129 + } else
121 throw OptionAlreadyAdded(myopt.get_name()); 130 throw OptionAlreadyAdded(myopt.get_name());
122 - return &options.back();  
123 131
124 } 132 }
125 133
@@ -129,7 +137,7 @@ public: @@ -129,7 +137,7 @@ public:
129 std::string name, 137 std::string name,
130 T &variable, ///< The variable to set 138 T &variable, ///< The variable to set
131 std::string description="", 139 std::string description="",
132 - bool defaulted=true 140 + bool defaulted=false
133 ) { 141 ) {
134 142
135 143
@@ -159,7 +167,7 @@ public: @@ -159,7 +167,7 @@ public:
159 std::string name, 167 std::string name,
160 std::vector<T> &variable, ///< The variable vector to set 168 std::vector<T> &variable, ///< The variable vector to set
161 std::string description="", 169 std::string description="",
162 - bool defaulted=true 170 + bool defaulted=false
163 ) { 171 ) {
164 172
165 CLI::callback_t fun = [&variable](CLI::results_t res){ 173 CLI::callback_t fun = [&variable](CLI::results_t res){
@@ -173,9 +181,6 @@ public: @@ -173,9 +181,6 @@ public:
173 return variable.size() > 0 && retval; 181 return variable.size() > 0 && retval;
174 }; 182 };
175 183
176 - if(variable.size() == 0)  
177 - defaulted = false;  
178 -  
179 Option* retval = add_option(name, fun, description, defaulted); 184 Option* retval = add_option(name, fun, description, defaulted);
180 retval->allow_vector = true; 185 retval->allow_vector = true;
181 retval->_expected = -1; 186 retval->_expected = -1;
@@ -252,12 +257,12 @@ public: @@ -252,12 +257,12 @@ public:
252 Option* add_set( 257 Option* add_set(
253 std::string name, 258 std::string name,
254 T &member, ///< The selected member of the set 259 T &member, ///< The selected member of the set
255 - std::set<T> options, ///< The set of posibilities 260 + std::set<T> _options, ///< The set of posibilities
256 std::string description="", 261 std::string description="",
257 - bool defaulted=true 262 + bool defaulted=false
258 ) { 263 ) {
259 264
260 - CLI::callback_t fun = [&member, options](CLI::results_t res){ 265 + CLI::callback_t fun = [&member, _options](CLI::results_t res){
261 if(res.size()!=1) { 266 if(res.size()!=1) {
262 return false; 267 return false;
263 } 268 }
@@ -267,15 +272,17 @@ public: @@ -267,15 +272,17 @@ public:
267 bool retval = detail::lexical_cast(res[0][0], member); 272 bool retval = detail::lexical_cast(res[0][0], member);
268 if(!retval) 273 if(!retval)
269 return false; 274 return false;
270 - return std::find(std::begin(options), std::end(options), member) != std::end(options); 275 + return std::find(std::begin(_options), std::end(_options), member) != std::end(_options);
271 }; 276 };
272 277
273 Option* retval = add_option(name, fun, description, defaulted); 278 Option* retval = add_option(name, fun, description, defaulted);
274 retval->typeval = detail::type_name<T>(); 279 retval->typeval = detail::type_name<T>();
275 - retval->typeval += " in {" + detail::join(options) + "}";  
276 - std::stringstream out;  
277 - out << member;  
278 - retval->defaultval = out.str(); 280 + retval->typeval += " in {" + detail::join(_options) + "}";
  281 + if(defaulted) {
  282 + std::stringstream out;
  283 + out << member;
  284 + retval->defaultval = out.str();
  285 + }
279 return retval; 286 return retval;
280 } 287 }
281 288
@@ -328,17 +335,17 @@ public: @@ -328,17 +335,17 @@ public:
328 335
329 336
330 337
331 - for(Option& opt : options) {  
332 - while (opt.get_positional() && opt.count() < opt.get_expected() && positionals.size() > 0) {  
333 - opt.get_new();  
334 - opt.add_result(0, positionals.front()); 338 + for(const Option_p& opt : options) {
  339 + while (opt->get_positional() && opt->count() < opt->get_expected() && positionals.size() > 0) {
  340 + opt->get_new();
  341 + opt->add_result(0, positionals.front());
335 positionals.pop_front(); 342 positionals.pop_front();
336 } 343 }
337 - if (opt.get_required() && opt.count() < opt.get_expected())  
338 - throw RequiredError(opt.get_name());  
339 - if (opt.count() > 0) {  
340 - if(!opt.run_callback())  
341 - throw ConversionError(opt.get_name()); 344 + if (opt->get_required() && opt->count() < opt->get_expected())
  345 + throw RequiredError(opt->get_name());
  346 + if (opt->count() > 0) {
  347 + if(!opt->run_callback())
  348 + throw ConversionError(opt->get_name());
342 } 349 }
343 350
344 } 351 }
@@ -350,7 +357,7 @@ public: @@ -350,7 +357,7 @@ public:
350 } 357 }
351 358
352 void _parse_subcommand(std::vector<std::string> &args) { 359 void _parse_subcommand(std::vector<std::string> &args) {
353 - for(std::unique_ptr<App> &com : subcommands) { 360 + for(const App_p &com : subcommands) {
354 if(com->name == args.back()){ 361 if(com->name == args.back()){
355 args.pop_back(); 362 args.pop_back();
356 subcommand = com.get(); 363 subcommand = com.get();
@@ -370,13 +377,16 @@ public: @@ -370,13 +377,16 @@ public:
370 throw HorribleError("Short"); 377 throw HorribleError("Short");
371 args.pop_back(); 378 args.pop_back();
372 379
373 - auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_sname(name);}); 380 + auto op_ptr = std::find_if(std::begin(options), std::end(options), [name](const Option_p &opt){return opt->check_sname(name);});
374 381
375 - if(op == std::end(options)) { 382 + if(op_ptr == std::end(options)) {
376 missing_options.push_back("-" + name); 383 missing_options.push_back("-" + name);
377 return; 384 return;
378 } 385 }
379 386
  387 + // Get a reference to the pointer to make syntax bearable
  388 + Option_p& op = *op_ptr;
  389 +
380 int vnum = op->get_new(); 390 int vnum = op->get_new();
381 int num = op->get_expected(); 391 int num = op->get_expected();
382 392
@@ -414,7 +424,7 @@ public: @@ -414,7 +424,7 @@ public:
414 424
415 if(current == "--") 425 if(current == "--")
416 return Classifer::POSITIONAL_MARK; 426 return Classifer::POSITIONAL_MARK;
417 - for(const std::unique_ptr<App> &com : subcommands) { 427 + for(const App_p &com : subcommands) {
418 if(com->name == current) 428 if(com->name == current)
419 return Classifer::SUBCOMMAND; 429 return Classifer::SUBCOMMAND;
420 } 430 }
@@ -434,13 +444,15 @@ public: @@ -434,13 +444,15 @@ public:
434 throw HorribleError("Long"); 444 throw HorribleError("Long");
435 args.pop_back(); 445 args.pop_back();
436 446
437 - auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_lname(name);}); 447 + auto op_ptr = std::find_if(std::begin(options), std::end(options), [name](const Option_p &v){return v->check_lname(name);});
438 448
439 - if(op == std::end(options)) { 449 + if(op_ptr == std::end(options)) {
440 missing_options.push_back("--" + name); 450 missing_options.push_back("--" + name);
441 return; 451 return;
442 } 452 }
443 453
  454 + // Get a reference to the pointer to make syntax bearable
  455 + Option_p& op = *op_ptr;
444 456
445 int vnum = op->get_new(); 457 int vnum = op->get_new();
446 int num = op->get_expected(); 458 int num = op->get_expected();
@@ -488,9 +500,9 @@ public: @@ -488,9 +500,9 @@ public:
488 500
489 /// Counts the number of times the given option was passed. 501 /// Counts the number of times the given option was passed.
490 int count(std::string name) const { 502 int count(std::string name) const {
491 - for(const Option &opt : options) {  
492 - if(opt.check_name(name)) {  
493 - return opt.count(); 503 + for(const Option_p &opt : options) {
  504 + if(opt->check_name(name)) {
  505 + return opt->count();
494 } 506 }
495 } 507 }
496 throw OptionNotFound(name); 508 throw OptionNotFound(name);
@@ -512,8 +524,8 @@ public: @@ -512,8 +524,8 @@ public:
512 524
513 // Check for options 525 // Check for options
514 bool npos = false; 526 bool npos = false;
515 - for(const Option &opt : options) {  
516 - if(opt.nonpositional()) { 527 + for(const Option_p &opt : options) {
  528 + if(opt->nonpositional()) {
517 npos = true; 529 npos = true;
518 break; 530 break;
519 } 531 }
@@ -524,10 +536,10 @@ public: @@ -524,10 +536,10 @@ public:
524 536
525 // Positionals 537 // Positionals
526 bool pos=false; 538 bool pos=false;
527 - for(const Option &opt : options)  
528 - if(opt.get_positional()) {  
529 - out << " " << opt.help_positional();  
530 - if(opt.has_description()) 539 + for(const Option_p &opt : options)
  540 + if(opt->get_positional()) {
  541 + out << " " << opt->help_positional();
  542 + if(opt->has_description())
531 pos=true; 543 pos=true;
532 } 544 }
533 545
@@ -536,9 +548,9 @@ public: @@ -536,9 +548,9 @@ public:
536 // Positional descriptions 548 // Positional descriptions
537 if(pos) { 549 if(pos) {
538 out << "Positionals:" << std::endl; 550 out << "Positionals:" << std::endl;
539 - for(const Option &opt : options)  
540 - if(opt.get_positional() && opt.has_description())  
541 - detail::format_help(out, opt.get_pname(), opt.get_description(), wid); 551 + for(const Option_p &opt : options)
  552 + if(opt->get_positional() && opt->has_description())
  553 + detail::format_help(out, opt->get_pname(), opt->get_description(), wid);
542 out << std::endl; 554 out << std::endl;
543 555
544 } 556 }
@@ -547,9 +559,9 @@ public: @@ -547,9 +559,9 @@ public:
547 // Options 559 // Options
548 if(npos) { 560 if(npos) {
549 out << "Options:" << std::endl; 561 out << "Options:" << std::endl;
550 - for(const Option &opt : options) {  
551 - if(opt.nonpositional())  
552 - detail::format_help(out, opt.help_name(), opt.get_description(), wid); 562 + for(const Option_p &opt : options) {
  563 + if(opt->nonpositional())
  564 + detail::format_help(out, opt->help_name(), opt->get_description(), wid);
553 565
554 } 566 }
555 out << std::endl; 567 out << std::endl;
@@ -558,7 +570,7 @@ public: @@ -558,7 +570,7 @@ public:
558 // Subcommands 570 // Subcommands
559 if(subcommands.size()> 0) { 571 if(subcommands.size()> 0) {
560 out << "Subcommands:" << std::endl; 572 out << "Subcommands:" << std::endl;
561 - for(const std::unique_ptr<App> &com : subcommands) 573 + for(const App_p &com : subcommands)
562 detail::format_help(out, com->get_name(), com->prog_description, wid); 574 detail::format_help(out, com->get_name(), com->prog_description, wid);
563 } 575 }
564 return out.str(); 576 return out.str();
include/CLI/Error.hpp
@@ -18,16 +18,6 @@ struct Error : public std::runtime_error { @@ -18,16 +18,6 @@ struct Error : public std::runtime_error {
18 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) {} 18 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) {}
19 }; 19 };
20 20
21 -/// This is a successful completion on parsing, supposed to exit  
22 -struct Success : public Error {  
23 - Success() : Error("Success", "Successfully completed, should be caught and quit", 0, false) {}  
24 -};  
25 -  
26 -/// -h or --help on command line  
27 -struct CallForHelp : public Error {  
28 - CallForHelp() : Error("CallForHelp", "This should be caught in your main function, see examples", 0) {}  
29 -};  
30 -  
31 // Construction errors (not in parsing) 21 // Construction errors (not in parsing)
32 22
33 struct ConstructionError : public Error { 23 struct ConstructionError : public Error {
@@ -51,10 +41,24 @@ struct OptionAlreadyAdded : public ConstructionError { @@ -51,10 +41,24 @@ struct OptionAlreadyAdded : public ConstructionError {
51 41
52 // Parsing errors 42 // Parsing errors
53 43
  44 +/// Anything that can error in Parse
54 struct ParseError : public Error { 45 struct ParseError : public Error {
55 using Error::Error; 46 using Error::Error;
56 }; 47 };
57 48
  49 +// Not really "errors"
  50 +
  51 +/// This is a successful completion on parsing, supposed to exit
  52 +struct Success : public ParseError {
  53 + Success() : ParseError("Success", "Successfully completed, should be caught and quit", 0, false) {}
  54 +};
  55 +
  56 +/// -h or --help on command line
  57 +struct CallForHelp : public ParseError {
  58 + CallForHelp() : ParseError("CallForHelp", "This should be caught in your main function, see examples", 0) {}
  59 +};
  60 +
  61 +
58 /// Thrown when conversion call back fails, such as when an int fails to coerse to a string 62 /// Thrown when conversion call back fails, such as when an int fails to coerse to a string
59 struct ConversionError : public ParseError { 63 struct ConversionError : public ParseError {
60 ConversionError(std::string name) : ParseError("ConversionError", name, 2) {} 64 ConversionError(std::string name) : ParseError("ConversionError", name, 2) {}
@@ -75,6 +79,8 @@ struct HorribleError : public ParseError { @@ -75,6 +79,8 @@ struct HorribleError : public ParseError {
75 HorribleError(std::string name) : ParseError("HorribleError", "(You should never see this error) " + name, 7) {} 79 HorribleError(std::string name) : ParseError("HorribleError", "(You should never see this error) " + name, 7) {}
76 }; 80 };
77 81
  82 +// After parsing
  83 +
78 /// Thrown when counting a non-existent option 84 /// Thrown when counting a non-existent option
79 struct OptionNotFound : public Error { 85 struct OptionNotFound : public Error {
80 OptionNotFound(std::string name) : Error("OptionNotFound", name, 4) {} 86 OptionNotFound(std::string name) : Error("OptionNotFound", name, 4) {}
include/CLI/Option.hpp
@@ -43,7 +43,7 @@ protected: @@ -43,7 +43,7 @@ protected:
43 std::vector<std::function<bool(std::string)>> _validators; 43 std::vector<std::function<bool(std::string)>> _validators;
44 44
45 // Results 45 // Results
46 - results_t results {}; 46 + results_t results;
47 47
48 48
49 public: 49 public:
@@ -206,8 +206,8 @@ public: @@ -206,8 +206,8 @@ public:
206 /// Count the total number of times an option was passed 206 /// Count the total number of times an option was passed
207 int count() const { 207 int count() const {
208 int out = 0; 208 int out = 0;
209 - for(const std::vector<std::string>& v : results)  
210 - out += v.size(); 209 + for(const std::vector<std::string>& vec : results)
  210 + out += vec.size();
211 return out; 211 return out;
212 } 212 }
213 213