Commit 1dfe8dcea1b3fee1844cc0ad9640137f5a52165e

Authored by Henry Fredrick Schreiner
1 parent 63bd1867

Rename App members, originize help

include/CLI/App.hpp
@@ -41,84 +41,126 @@ class App { @@ -41,84 +41,126 @@ class App {
41 friend Option; 41 friend Option;
42 protected: 42 protected:
43 43
  44 + // This library follows the Google style guide for member names ending in underscores
  45 +
  46 + /// @name Basics
  47 + ///@{
  48 +
44 /// Subcommand name or program name (from parser) 49 /// Subcommand name or program name (from parser)
45 - std::string name {"program"}; 50 + std::string name_ {"program"};
46 51
47 /// Description of the current program/subcommand 52 /// Description of the current program/subcommand
48 - std::string description;  
49 - std::vector<Option_p> options; 53 + std::string description_;
  54 +
  55 + /// If true, allow extra arguments (ie, don't throw an error).
  56 + bool allow_extras_ {false};
  57 +
  58 + /// This is a function that runs when complete. Great for subcommands. Can throw.
  59 + std::function<void()> callback_;
  60 +
  61 + ///@}
  62 + /// @name Options
  63 + ///@{
  64 +
  65 + /// The list of options, stored locally
  66 + std::vector<Option_p> options_;
  67 +
  68 + /// A pointer to the help flag if there is one
  69 + Option* help_ptr_ {nullptr};
  70 +
  71 + ///@}
  72 + /// @name Parsing
  73 + ///@{
  74 +
  75 + /// Pair of classifier, string for missing options. (extra detail is removed on returning from parse)
  76 + ///
  77 + /// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator.
  78 + std::vector<std::pair<detail::Classifer, std::string>> missing_;
50 79
51 - /// Pair of classifer, string for missing options. (extra detail is removed on returning from parse)  
52 - std::vector<std::pair<detail::Classifer, std::string>> missing;  
53 - bool no_extras {true}; 80 + ///@}
  81 + /// @name Subcommands
  82 + ///@{
  83 +
  84 + /// Storage for subcommand list
  85 + std::vector<App_p> subcommands_;
  86 +
  87 + /// If true, the program name is not case sensitive
  88 + bool ignore_case_ {false};
54 89
55 - std::vector<App_p> subcommands;  
56 - bool parsed {false};  
57 - std::vector<App*> selected_subcommands; 90 + /// A pointer to the parent if this is a subcommand
  91 + App* parent_ {nullptr};
  92 +
  93 + /// A list of all the subcommand pointers that have been collected on the command line
  94 + std::vector<App*> selected_subcommands_;
58 95
59 /// -1 for 1 or more, 0 for not required, # for exact number required 96 /// -1 for 1 or more, 0 for not required, # for exact number required
60 - int required_subcommand = 0; 97 + int require_subcommand_ = 0;
  98 +
  99 + ///@}
  100 + /// @name Config
  101 + ///@{
61 102
62 - Option* help_flag {nullptr}; 103 + /// The name of the connected config file
  104 + std::string config_name_;
63 105
64 - std::function<void()> app_callback; 106 + /// True if ini is required (throws if not present), if false simply keep going.
  107 + bool config_required_ {false};
65 108
66 - std::string ini_file;  
67 - bool ini_required {false};  
68 - Option* ini_setting {nullptr}; 109 + /// Pointer to the config option
  110 + Option* config_ptr_ {nullptr};
69 111
70 - bool case_insensitive {false};  
71 - App* parent {nullptr}; 112 + ///@}
72 113
73 114
74 public: 115 public:
75 /// Create a new program. Pass in the same arguments as main(), along with a help string. 116 /// Create a new program. Pass in the same arguments as main(), along with a help string.
76 - App(std::string description="", bool help=true)  
77 - : description(description) { 117 + App(std::string description_="", bool help=true)
  118 + : description_(description_) {
78 119
79 if(help) 120 if(help)
80 - help_flag = add_flag("-h,--help", "Print this help message and exit"); 121 + help_ptr_ = add_flag("-h,--help", "Print this help message and exit");
81 122
82 } 123 }
83 124
84 125
85 - /// Set a callback for the end of parsing. Due to a bug in c++11, 126 + /// Set a callback for the end of parsing.
  127 + ///
  128 + /// Due to a bug in c++11,
86 /// it is not possible to overload on std::function (fixed in c++14 129 /// it is not possible to overload on std::function (fixed in c++14
87 /// and backported to c++11 on newer compilers). Use capture by reference 130 /// and backported to c++11 on newer compilers). Use capture by reference
88 /// to get a pointer to App if needed. 131 /// to get a pointer to App if needed.
89 void set_callback(std::function<void()> callback) { 132 void set_callback(std::function<void()> callback) {
90 - app_callback = callback; 133 + callback_ = callback;
91 } 134 }
92 135
93 /// Reset the parsed data 136 /// Reset the parsed data
94 void reset() { 137 void reset() {
95 138
96 - parsed = false;  
97 - selected_subcommands.clear();  
98 - missing.clear(); 139 + selected_subcommands_.clear();
  140 + missing_.clear();
99 141
100 - for(const Option_p &opt : options) { 142 + for(const Option_p &opt : options_) {
101 opt->clear(); 143 opt->clear();
102 } 144 }
103 - for(const App_p &app : subcommands) { 145 + for(const App_p &app : subcommands_) {
104 app->reset(); 146 app->reset();
105 } 147 }
106 } 148 }
107 149
108 /// Get a pointer to the help flag. 150 /// Get a pointer to the help flag.
109 Option* get_help_ptr() { 151 Option* get_help_ptr() {
110 - return help_flag; 152 + return help_ptr_;
111 } 153 }
112 154
113 /// Get a pointer to the config option. 155 /// Get a pointer to the config option.
114 Option* get_config_ptr() { 156 Option* get_config_ptr() {
115 - return ini_setting; 157 + return config_ptr_;
116 } 158 }
117 159
118 /// Produce a string that could be read in as a config of the current values of the App 160 /// Produce a string that could be read in as a config of the current values of the App
119 std::string config_to_str() const { 161 std::string config_to_str() const {
120 std::stringstream out; 162 std::stringstream out;
121 - for(const Option_p &opt : options) { 163 + for(const Option_p &opt : options_) {
122 if(opt->lnames.size() > 0 && opt->count() > 0 && opt->get_expected() > 0) 164 if(opt->lnames.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
123 out << opt->lnames[0] << "=" << detail::join(opt->flatten_results()) << std::endl; 165 out << opt->lnames[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
124 } 166 }
@@ -126,17 +168,17 @@ public: @@ -126,17 +168,17 @@ public:
126 } 168 }
127 169
128 /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false 170 /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
129 - App* add_subcommand(std::string name_, std::string description_="", bool help=true) {  
130 - subcommands.emplace_back(new App(description_, help));  
131 - subcommands.back()->name = name_;  
132 - subcommands.back()->allow_extras();  
133 - subcommands.back()->parent = this;  
134 - subcommands.back()->case_insensitive = case_insensitive;  
135 - for(const auto& subc : subcommands)  
136 - if(subc.get() != subcommands.back().get())  
137 - if(subc->check_name(subcommands.back()->name) || subcommands.back()->check_name(subc->name))  
138 - throw OptionAlreadyAdded(subc->name);  
139 - return subcommands.back().get(); 171 + App* add_subcommand(std::string name, std::string description="", bool help=true) {
  172 + subcommands_.emplace_back(new App(description, help));
  173 + subcommands_.back()->name_ = name;
  174 + subcommands_.back()->allow_extras();
  175 + subcommands_.back()->parent_ = this;
  176 + subcommands_.back()->ignore_case_ = ignore_case_;
  177 + for(const auto& subc : subcommands_)
  178 + if(subc.get() != subcommands_.back().get())
  179 + if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
  180 + throw OptionAlreadyAdded(subc->name_);
  181 + return subcommands_.back().get();
140 } 182 }
141 183
142 /// Add an option, will automatically understand the type for common types. 184 /// Add an option, will automatically understand the type for common types.
@@ -144,7 +186,7 @@ public: @@ -144,7 +186,7 @@ public:
144 * After start is called, you can use count to see if the value was passed, and 186 * After start is called, you can use count to see if the value was passed, and
145 * the value will be initialized properly. 187 * the value will be initialized properly.
146 * 188 *
147 - * ->required(), ->default, and the validators are options, 189 + * ->required(), ->default, and the validators are options_,
148 * The positional options take an optional number of arguments. 190 * The positional options take an optional number of arguments.
149 * 191 *
150 * For example, 192 * For example,
@@ -153,18 +195,18 @@ public: @@ -153,18 +195,18 @@ public:
153 * program.add_option("filename", filename, "description of filename"); 195 * program.add_option("filename", filename, "description of filename");
154 */ 196 */
155 Option* add_option( 197 Option* add_option(
156 - std::string name_, 198 + std::string name,
157 callback_t callback, 199 callback_t callback,
158 - std::string description_="", 200 + std::string description="",
159 bool defaulted=false 201 bool defaulted=false
160 ) { 202 ) {
161 - Option myopt{name_, description_, callback, defaulted, this}; 203 + Option myopt{name, description, callback, defaulted, this};
162 204
163 - if(std::find_if(std::begin(options), std::end(options),  
164 - [&myopt](const Option_p &v){return *v == myopt;}) == std::end(options)) {  
165 - options.emplace_back();  
166 - Option_p& option = options.back();  
167 - option.reset(new Option(name_, description_, callback, defaulted, this)); 205 + if(std::find_if(std::begin(options_), std::end(options_),
  206 + [&myopt](const Option_p &v){return *v == myopt;}) == std::end(options_)) {
  207 + options_.emplace_back();
  208 + Option_p& option = options_.back();
  209 + option.reset(new Option(name, description, callback, defaulted, this));
168 return option.get(); 210 return option.get();
169 } else 211 } else
170 throw OptionAlreadyAdded(myopt.get_name()); 212 throw OptionAlreadyAdded(myopt.get_name());
@@ -174,9 +216,9 @@ public: @@ -174,9 +216,9 @@ public:
174 /// Add option for string 216 /// Add option for string
175 template<typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> 217 template<typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
176 Option* add_option( 218 Option* add_option(
177 - std::string name_, 219 + std::string name,
178 T &variable, ///< The variable to set 220 T &variable, ///< The variable to set
179 - std::string description_="", 221 + std::string description="",
180 bool defaulted=false 222 bool defaulted=false
181 ) { 223 ) {
182 224
@@ -191,7 +233,7 @@ public: @@ -191,7 +233,7 @@ public:
191 return detail::lexical_cast(res[0][0], variable); 233 return detail::lexical_cast(res[0][0], variable);
192 }; 234 };
193 235
194 - Option* retval = add_option(name_, fun, description_, defaulted); 236 + Option* retval = add_option(name, fun, description, defaulted);
195 retval->typeval = detail::type_name<T>(); 237 retval->typeval = detail::type_name<T>();
196 if(defaulted) { 238 if(defaulted) {
197 std::stringstream out; 239 std::stringstream out;
@@ -204,9 +246,9 @@ public: @@ -204,9 +246,9 @@ public:
204 /// Add option for vector of results 246 /// Add option for vector of results
205 template<typename T> 247 template<typename T>
206 Option* add_option( 248 Option* add_option(
207 - std::string name_, 249 + std::string name,
208 std::vector<T> &variable, ///< The variable vector to set 250 std::vector<T> &variable, ///< The variable vector to set
209 - std::string description_="", 251 + std::string description="",
210 bool defaulted=false 252 bool defaulted=false
211 ) { 253 ) {
212 254
@@ -221,7 +263,7 @@ public: @@ -221,7 +263,7 @@ public:
221 return variable.size() > 0 && retval; 263 return variable.size() > 0 && retval;
222 }; 264 };
223 265
224 - Option* retval = add_option(name_, fun, description_, defaulted); 266 + Option* retval = add_option(name, fun, description, defaulted);
225 retval->allow_vector = true; 267 retval->allow_vector = true;
226 retval->_expected = -1; 268 retval->_expected = -1;
227 retval->typeval = detail::type_name<T>(); 269 retval->typeval = detail::type_name<T>();
@@ -233,14 +275,14 @@ public: @@ -233,14 +275,14 @@ public:
233 275
234 /// Add option for flag 276 /// Add option for flag
235 Option* add_flag( 277 Option* add_flag(
236 - std::string name_,  
237 - std::string description_="" 278 + std::string name,
  279 + std::string description=""
238 ) { 280 ) {
239 CLI::callback_t fun = [](CLI::results_t){ 281 CLI::callback_t fun = [](CLI::results_t){
240 return true; 282 return true;
241 }; 283 };
242 284
243 - Option* opt = add_option(name_, fun, description_, false); 285 + Option* opt = add_option(name, fun, description, false);
244 if(opt->get_positional()) 286 if(opt->get_positional())
245 throw IncorrectConstruction("Flags cannot be positional"); 287 throw IncorrectConstruction("Flags cannot be positional");
246 opt->_expected = 0; 288 opt->_expected = 0;
@@ -251,9 +293,9 @@ public: @@ -251,9 +293,9 @@ public:
251 template<typename T, 293 template<typename T,
252 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy> 294 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
253 Option* add_flag( 295 Option* add_flag(
254 - std::string name_, 296 + std::string name,
255 T &count, ///< A varaible holding the count 297 T &count, ///< A varaible holding the count
256 - std::string description_="" 298 + std::string description=""
257 ) { 299 ) {
258 300
259 count = 0; 301 count = 0;
@@ -262,7 +304,7 @@ public: @@ -262,7 +304,7 @@ public:
262 return true; 304 return true;
263 }; 305 };
264 306
265 - Option* opt = add_option(name_, fun, description_, false); 307 + Option* opt = add_option(name, fun, description, false);
266 if(opt->get_positional()) 308 if(opt->get_positional())
267 throw IncorrectConstruction("Flags cannot be positional"); 309 throw IncorrectConstruction("Flags cannot be positional");
268 opt->_expected = 0; 310 opt->_expected = 0;
@@ -273,9 +315,9 @@ public: @@ -273,9 +315,9 @@ public:
273 template<typename T, 315 template<typename T,
274 enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy> 316 enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy>
275 Option* add_flag( 317 Option* add_flag(
276 - std::string name_, 318 + std::string name,
277 T &count, ///< A varaible holding true if passed 319 T &count, ///< A varaible holding true if passed
278 - std::string description_="" 320 + std::string description=""
279 ) { 321 ) {
280 322
281 count = false; 323 count = false;
@@ -284,7 +326,7 @@ public: @@ -284,7 +326,7 @@ public:
284 return res.size() == 1; 326 return res.size() == 1;
285 }; 327 };
286 328
287 - Option* opt = add_option(name_, fun, description_, false); 329 + Option* opt = add_option(name, fun, description, false);
288 if(opt->get_positional()) 330 if(opt->get_positional())
289 throw IncorrectConstruction("Flags cannot be positional"); 331 throw IncorrectConstruction("Flags cannot be positional");
290 opt->_expected = 0; 332 opt->_expected = 0;
@@ -292,13 +334,13 @@ public: @@ -292,13 +334,13 @@ public:
292 } 334 }
293 335
294 336
295 - /// Add set of options 337 + /// Add set of options_
296 template<typename T> 338 template<typename T>
297 Option* add_set( 339 Option* add_set(
298 - std::string name_, 340 + std::string name,
299 T &member, ///< The selected member of the set 341 T &member, ///< The selected member of the set
300 std::set<T> _options, ///< The set of posibilities 342 std::set<T> _options, ///< The set of posibilities
301 - std::string description_="", 343 + std::string description="",
302 bool defaulted=false 344 bool defaulted=false
303 ) { 345 ) {
304 346
@@ -315,7 +357,7 @@ public: @@ -315,7 +357,7 @@ public:
315 return std::find(std::begin(_options), std::end(_options), member) != std::end(_options); 357 return std::find(std::begin(_options), std::end(_options), member) != std::end(_options);
316 }; 358 };
317 359
318 - Option* retval = add_option(name_, fun, description_, defaulted); 360 + Option* retval = add_option(name, fun, description, defaulted);
319 retval->typeval = detail::type_name<T>(); 361 retval->typeval = detail::type_name<T>();
320 retval->typeval += " in {" + detail::join(_options) + "}"; 362 retval->typeval += " in {" + detail::join(_options) + "}";
321 if(defaulted) { 363 if(defaulted) {
@@ -328,10 +370,10 @@ public: @@ -328,10 +370,10 @@ public:
328 370
329 /// Add set of options, string only, ignore case 371 /// Add set of options, string only, ignore case
330 Option* add_set_ignore_case( 372 Option* add_set_ignore_case(
331 - std::string name_, 373 + std::string name,
332 std::string &member, ///< The selected member of the set 374 std::string &member, ///< The selected member of the set
333 std::set<std::string> _options, ///< The set of posibilities 375 std::set<std::string> _options, ///< The set of posibilities
334 - std::string description_="", 376 + std::string description="",
335 bool defaulted=false 377 bool defaulted=false
336 ) { 378 ) {
337 379
@@ -353,7 +395,7 @@ public: @@ -353,7 +395,7 @@ public:
353 } 395 }
354 }; 396 };
355 397
356 - Option* retval = add_option(name_, fun, description_, defaulted); 398 + Option* retval = add_option(name, fun, description, defaulted);
357 retval->typeval = detail::type_name<std::string>(); 399 retval->typeval = detail::type_name<std::string>();
358 retval->typeval += " in {" + detail::join(_options) + "}"; 400 retval->typeval += " in {" + detail::join(_options) + "}";
359 if(defaulted) { 401 if(defaulted) {
@@ -364,26 +406,26 @@ public: @@ -364,26 +406,26 @@ public:
364 406
365 407
366 /// Add a configuration ini file option 408 /// Add a configuration ini file option
367 - Option* add_config(std::string name_="--config", 409 + Option* add_config(std::string name="--config",
368 std::string default_filename="", 410 std::string default_filename="",
369 std::string help="Read an ini file", 411 std::string help="Read an ini file",
370 bool required=false) { 412 bool required=false) {
371 413
372 // Remove existing config if present 414 // Remove existing config if present
373 - if(ini_setting != nullptr)  
374 - remove_option(ini_setting);  
375 - ini_file = default_filename;  
376 - ini_required = required;  
377 - ini_setting = add_option(name_, ini_file, help, default_filename!="");  
378 - return ini_setting; 415 + if(config_ptr_ != nullptr)
  416 + remove_option(config_ptr_);
  417 + config_name_ = default_filename;
  418 + config_required_ = required;
  419 + config_ptr_ = add_option(name, config_name_, help, default_filename!="");
  420 + return config_ptr_;
379 } 421 }
380 422
381 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed. 423 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
382 bool remove_option(Option* opt) { 424 bool remove_option(Option* opt) {
383 - auto iterator = std::find_if(std::begin(options), std::end(options), 425 + auto iterator = std::find_if(std::begin(options_), std::end(options_),
384 [opt](const Option_p &v){return v.get() == opt;}); 426 [opt](const Option_p &v){return v.get() == opt;});
385 - if (iterator != std::end(options)) {  
386 - options.erase(iterator); 427 + if (iterator != std::end(options_)) {
  428 + options_.erase(iterator);
387 return true; 429 return true;
388 } 430 }
389 return false; 431 return false;
@@ -396,7 +438,7 @@ public: @@ -396,7 +438,7 @@ public:
396 /// Parses the command line - throws errors 438 /// Parses the command line - throws errors
397 /// This must be called after the options are in but before the rest of the program. 439 /// This must be called after the options are in but before the rest of the program.
398 std::vector<std::string> parse(int argc, char **argv) { 440 std::vector<std::string> parse(int argc, char **argv) {
399 - name = argv[0]; 441 + name_ = argv[0];
400 std::vector<std::string> args; 442 std::vector<std::string> args;
401 for(int i=argc-1; i>0; i--) 443 for(int i=argc-1; i>0; i--)
402 args.push_back(argv[i]); 444 args.push_back(argv[i]);
@@ -412,7 +454,7 @@ public: @@ -412,7 +454,7 @@ public:
412 454
413 /// Remove the error when extras are left over on the command line. 455 /// Remove the error when extras are left over on the command line.
414 void allow_extras (bool allow=true) { 456 void allow_extras (bool allow=true) {
415 - no_extras = !allow; 457 + allow_extras_ = allow;
416 } 458 }
417 459
418 460
@@ -431,34 +473,34 @@ public: @@ -431,34 +473,34 @@ public:
431 } 473 }
432 474
433 /// Counts the number of times the given option was passed. 475 /// Counts the number of times the given option was passed.
434 - int count(std::string name_) const {  
435 - for(const Option_p &opt : options) {  
436 - if(opt->check_name(name_)) { 476 + int count(std::string name) const {
  477 + for(const Option_p &opt : options_) {
  478 + if(opt->check_name(name)) {
437 return opt->count(); 479 return opt->count();
438 } 480 }
439 } 481 }
440 - throw OptionNotFound(name_); 482 + throw OptionNotFound(name);
441 } 483 }
442 484
443 - /// Makes a help message, with a column `wid` for column 1 485 + /// Makes a help message, with a column wid for column 1
444 std::string help(size_t wid=30, std::string prev="") const { 486 std::string help(size_t wid=30, std::string prev="") const {
445 // Delegate to subcommand if needed 487 // Delegate to subcommand if needed
446 if(prev == "") 488 if(prev == "")
447 - prev = name; 489 + prev = name_;
448 else 490 else
449 - prev += " " + name; 491 + prev += " " + name_;
450 492
451 - if(selected_subcommands.size() > 0)  
452 - return selected_subcommands.at(0)->help(wid, prev); 493 + if(selected_subcommands_.size() > 0)
  494 + return selected_subcommands_.at(0)->help(wid, prev);
453 495
454 std::stringstream out; 496 std::stringstream out;
455 - out << description << std::endl; 497 + out << description_ << std::endl;
456 out << "Usage: " << prev; 498 out << "Usage: " << prev;
457 499
458 - // Check for options 500 + // Check for options_
459 bool npos = false; 501 bool npos = false;
460 std::set<std::string> groups; 502 std::set<std::string> groups;
461 - for(const Option_p &opt : options) { 503 + for(const Option_p &opt : options_) {
462 if(opt->nonpositional()) { 504 if(opt->nonpositional()) {
463 npos = true; 505 npos = true;
464 groups.insert(opt->get_group()); 506 groups.insert(opt->get_group());
@@ -470,7 +512,7 @@ public: @@ -470,7 +512,7 @@ public:
470 512
471 // Positionals 513 // Positionals
472 bool pos=false; 514 bool pos=false;
473 - for(const Option_p &opt : options) 515 + for(const Option_p &opt : options_)
474 if(opt->get_positional()) { 516 if(opt->get_positional()) {
475 // A hidden positional should still show up in the usage statement 517 // A hidden positional should still show up in the usage statement
476 //if(detail::to_lower(opt->get_group()) == "hidden") 518 //if(detail::to_lower(opt->get_group()) == "hidden")
@@ -480,8 +522,8 @@ public: @@ -480,8 +522,8 @@ public:
480 pos=true; 522 pos=true;
481 } 523 }
482 524
483 - if(subcommands.size() > 0) {  
484 - if(required_subcommand != 0) 525 + if(subcommands_.size() > 0) {
  526 + if(require_subcommand_ != 0)
485 out << " SUBCOMMAND"; 527 out << " SUBCOMMAND";
486 else 528 else
487 out << " [SUBCOMMAND]"; 529 out << " [SUBCOMMAND]";
@@ -492,7 +534,7 @@ public: @@ -492,7 +534,7 @@ public:
492 // Positional descriptions 534 // Positional descriptions
493 if(pos) { 535 if(pos) {
494 out << "Positionals:" << std::endl; 536 out << "Positionals:" << std::endl;
495 - for(const Option_p &opt : options) { 537 + for(const Option_p &opt : options_) {
496 if(detail::to_lower(opt->get_group()) == "hidden") 538 if(detail::to_lower(opt->get_group()) == "hidden")
497 continue; 539 continue;
498 if(opt->get_positional() && opt->has_description()) 540 if(opt->get_positional() && opt->has_description())
@@ -509,7 +551,7 @@ public: @@ -509,7 +551,7 @@ public:
509 if(detail::to_lower(group) == "hidden") 551 if(detail::to_lower(group) == "hidden")
510 continue; 552 continue;
511 out << group << ":" << std::endl; 553 out << group << ":" << std::endl;
512 - for(const Option_p &opt : options) { 554 + for(const Option_p &opt : options_) {
513 if(opt->nonpositional() && opt->get_group() == group) 555 if(opt->nonpositional() && opt->get_group() == group)
514 detail::format_help(out, opt->help_name(), opt->get_description(), wid); 556 detail::format_help(out, opt->help_name(), opt->get_description(), wid);
515 557
@@ -519,43 +561,45 @@ public: @@ -519,43 +561,45 @@ public:
519 } 561 }
520 562
521 // Subcommands 563 // Subcommands
522 - if(subcommands.size()> 0) { 564 + if(subcommands_.size()> 0) {
523 out << "Subcommands:" << std::endl; 565 out << "Subcommands:" << std::endl;
524 - for(const App_p &com : subcommands)  
525 - detail::format_help(out, com->get_name(), com->description, wid); 566 + for(const App_p &com : subcommands_)
  567 + detail::format_help(out, com->get_name(), com->description_, wid);
526 } 568 }
527 return out.str(); 569 return out.str();
528 } 570 }
529 571
530 /// Get a subcommand pointer list to the currently selected subcommands (after parsing) 572 /// Get a subcommand pointer list to the currently selected subcommands (after parsing)
531 std::vector<App*> get_subcommands() { 573 std::vector<App*> get_subcommands() {
532 - return selected_subcommands; 574 + return selected_subcommands_;
533 } 575 }
534 576
535 577
536 /// Check to see if selected subcommand in list 578 /// Check to see if selected subcommand in list
537 bool got_subcommand(App* subcom) const { 579 bool got_subcommand(App* subcom) const {
538 - return std::find(std::begin(selected_subcommands), std::end(selected_subcommands), subcom) != std::end(selected_subcommands); 580 + return std::find(std::begin(selected_subcommands_),
  581 + std::end(selected_subcommands_), subcom)
  582 + != std::end(selected_subcommands_);
539 } 583 }
540 584
541 /// Check with name instead of pointer 585 /// Check with name instead of pointer
542 - bool got_subcommand(std::string name_) const {  
543 - for(const auto subcomptr : selected_subcommands)  
544 - if(subcomptr->check_name(name_)) 586 + bool got_subcommand(std::string name) const {
  587 + for(const auto subcomptr : selected_subcommands_)
  588 + if(subcomptr->check_name(name))
545 return true; 589 return true;
546 return false; 590 return false;
547 } 591 }
548 592
549 /// Get the name of the current app 593 /// Get the name of the current app
550 std::string get_name() const { 594 std::string get_name() const {
551 - return name; 595 + return name_;
552 } 596 }
553 597
554 - /// Check the name, case insensitive if set 598 + /// Check the name_, case insensitive if set
555 bool check_name(std::string name_to_check) const { 599 bool check_name(std::string name_to_check) const {
556 - std::string local_name = name;  
557 - if(case_insensitive) {  
558 - local_name = detail::to_lower(name); 600 + std::string local_name = name_;
  601 + if(ignore_case_) {
  602 + local_name = detail::to_lower(name_);
559 name_to_check = detail::to_lower(name_to_check); 603 name_to_check = detail::to_lower(name_to_check);
560 } 604 }
561 605
@@ -564,11 +608,11 @@ public: @@ -564,11 +608,11 @@ public:
564 608
565 /// Ignore case 609 /// Ignore case
566 App* ignore_case(bool value = true) { 610 App* ignore_case(bool value = true) {
567 - case_insensitive = value;  
568 - if(parent != nullptr) {  
569 - for(const auto &subc : parent->subcommands) {  
570 - if(subc.get() != this && (this->check_name(subc->name) || subc->check_name(this->name)))  
571 - throw OptionAlreadyAdded(subc->name); 611 + ignore_case_ = value;
  612 + if(parent_ != nullptr) {
  613 + for(const auto &subc : parent_->subcommands_) {
  614 + if(subc.get() != this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
  615 + throw OptionAlreadyAdded(subc->name_);
572 } 616 }
573 } 617 }
574 return this; 618 return this;
@@ -577,15 +621,15 @@ public: @@ -577,15 +621,15 @@ public:
577 /// Require a subcommand to be given (does not affect help call) 621 /// Require a subcommand to be given (does not affect help call)
578 /// Does not return a pointer since it is supposed to be called on the main App. 622 /// Does not return a pointer since it is supposed to be called on the main App.
579 void require_subcommand(int value = -1) { 623 void require_subcommand(int value = -1) {
580 - required_subcommand = value; 624 + require_subcommand_ = value;
581 } 625 }
582 626
583 protected: 627 protected:
584 628
585 /// Internal function to run (App) callback 629 /// Internal function to run (App) callback
586 void run_callback() { 630 void run_callback() {
587 - if(app_callback)  
588 - app_callback(); 631 + if(callback_)
  632 + callback_();
589 } 633 }
590 634
591 /// Selects a Classifer enum based on the type of the current argument 635 /// Selects a Classifer enum based on the type of the current argument
@@ -594,7 +638,7 @@ protected: @@ -594,7 +638,7 @@ protected:
594 638
595 if(current == "--") 639 if(current == "--")
596 return detail::Classifer::POSITIONAL_MARK; 640 return detail::Classifer::POSITIONAL_MARK;
597 - for(const App_p &com : subcommands) { 641 + for(const App_p &com : subcommands_) {
598 if(com->check_name(current)) 642 if(com->check_name(current))
599 return detail::Classifer::SUBCOMMAND; 643 return detail::Classifer::SUBCOMMAND;
600 } 644 }
@@ -608,8 +652,6 @@ protected: @@ -608,8 +652,6 @@ protected:
608 652
609 /// Internal parse function 653 /// Internal parse function
610 std::vector<std::string>& _parse(std::vector<std::string> &args) { 654 std::vector<std::string>& _parse(std::vector<std::string> &args) {
611 - parsed = true;  
612 -  
613 bool positional_only = false; 655 bool positional_only = false;
614 656
615 while(args.size()>0) { 657 while(args.size()>0) {
@@ -618,7 +660,7 @@ protected: @@ -618,7 +660,7 @@ protected:
618 detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back()); 660 detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back());
619 switch(classifer) { 661 switch(classifer) {
620 case detail::Classifer::POSITIONAL_MARK: 662 case detail::Classifer::POSITIONAL_MARK:
621 - missing.emplace_back(classifer, args.back()); 663 + missing_.emplace_back(classifer, args.back());
622 args.pop_back(); 664 args.pop_back();
623 positional_only = true; 665 positional_only = true;
624 break; 666 break;
@@ -626,29 +668,29 @@ protected: @@ -626,29 +668,29 @@ protected:
626 _parse_subcommand(args); 668 _parse_subcommand(args);
627 break; 669 break;
628 case detail::Classifer::LONG: 670 case detail::Classifer::LONG:
629 - // If already parsed a subcommand, don't accept options  
630 - if(selected_subcommands.size() > 0) {  
631 - missing.emplace_back(classifer, args.back()); 671 + // If already parsed a subcommand, don't accept options_
  672 + if(selected_subcommands_.size() > 0) {
  673 + missing_.emplace_back(classifer, args.back());
632 args.pop_back(); 674 args.pop_back();
633 } else 675 } else
634 _parse_long(args); 676 _parse_long(args);
635 break; 677 break;
636 case detail::Classifer::SHORT: 678 case detail::Classifer::SHORT:
637 - // If already parsed a subcommand, don't accept options  
638 - if(selected_subcommands.size() > 0) {  
639 - missing.emplace_back(classifer, args.back()); 679 + // If already parsed a subcommand, don't accept options_
  680 + if(selected_subcommands_.size() > 0) {
  681 + missing_.emplace_back(classifer, args.back());
640 args.pop_back(); 682 args.pop_back();
641 } else 683 } else
642 _parse_short(args); 684 _parse_short(args);
643 break; 685 break;
644 case detail::Classifer::NONE: 686 case detail::Classifer::NONE:
645 // Probably a positional or something for a parent (sub)command 687 // Probably a positional or something for a parent (sub)command
646 - missing.emplace_back(classifer, args.back()); 688 + missing_.emplace_back(classifer, args.back());
647 args.pop_back(); 689 args.pop_back();
648 } 690 }
649 } 691 }
650 692
651 - if (help_flag != nullptr && help_flag->count() > 0) { 693 + if (help_ptr_ != nullptr && help_ptr_->count() > 0) {
652 throw CallForHelp(); 694 throw CallForHelp();
653 } 695 }
654 696
@@ -656,52 +698,52 @@ protected: @@ -656,52 +698,52 @@ protected:
656 // Collect positionals 698 // Collect positionals
657 699
658 // Loop over all positionals 700 // Loop over all positionals
659 - for(size_t i=0; i<missing.size(); i++) { 701 + for(size_t i=0; i<missing_.size(); i++) {
660 702
661 // Skip non-positionals (speedup) 703 // Skip non-positionals (speedup)
662 - if(missing.at(i).first != detail::Classifer::NONE) 704 + if(missing_.at(i).first != detail::Classifer::NONE)
663 continue; 705 continue;
664 706
665 // Loop over all options 707 // Loop over all options
666 - for(const Option_p& opt : options) { 708 + for(const Option_p& opt : options_) {
667 709
668 // Eat options, one by one, until done 710 // Eat options, one by one, until done
669 while ( opt->get_positional() 711 while ( opt->get_positional()
670 && opt->count() < opt->get_expected() 712 && opt->count() < opt->get_expected()
671 - && i < missing.size() 713 + && i < missing_.size()
672 ) { 714 ) {
673 715
674 // Skip options, only eat positionals 716 // Skip options, only eat positionals
675 - if(missing.at(i).first != detail::Classifer::NONE) { 717 + if(missing_.at(i).first != detail::Classifer::NONE) {
676 i++; 718 i++;
677 continue; 719 continue;
678 } 720 }
679 721
680 opt->get_new(); 722 opt->get_new();
681 - opt->add_result(0, missing.at(i).second);  
682 - missing.erase(missing.begin() + i); // Remove option that was eaten 723 + opt->add_result(0, missing_.at(i).second);
  724 + missing_.erase(missing_.begin() + i); // Remove option that was eaten
683 // Don't need to remove 1 from i since this while loop keeps reading i 725 // Don't need to remove 1 from i since this while loop keeps reading i
684 } 726 }
685 } 727 }
686 } 728 }
687 729
688 // Process an INI file 730 // Process an INI file
689 - if (ini_setting != nullptr && ini_file != "") { 731 + if (config_ptr_ != nullptr && config_name_ != "") {
690 try { 732 try {
691 - std::vector<std::string> values = detail::parse_ini(ini_file); 733 + std::vector<std::string> values = detail::parse_ini(config_name_);
692 while(values.size() > 0) { 734 while(values.size() > 0) {
693 _parse_long(values, false); 735 _parse_long(values, false);
694 } 736 }
695 737
696 } catch (const FileError &) { 738 } catch (const FileError &) {
697 - if(ini_required) 739 + if(config_required_)
698 throw; 740 throw;
699 } 741 }
700 } 742 }
701 743
702 744
703 // Get envname options if not yet passed 745 // Get envname options if not yet passed
704 - for(const Option_p& opt : options) { 746 + for(const Option_p& opt : options_) {
705 if (opt->count() == 0 && opt->_envname != "") { 747 if (opt->count() == 0 && opt->_envname != "") {
706 char *ename = std::getenv(opt->_envname.c_str()); 748 char *ename = std::getenv(opt->_envname.c_str());
707 if(ename != nullptr) { 749 if(ename != nullptr) {
@@ -712,14 +754,14 @@ protected: @@ -712,14 +754,14 @@ protected:
712 } 754 }
713 755
714 // Process callbacks 756 // Process callbacks
715 - for(const Option_p& opt : options) { 757 + for(const Option_p& opt : options_) {
716 if (opt->count() > 0) { 758 if (opt->count() > 0) {
717 opt->run_callback(); 759 opt->run_callback();
718 } 760 }
719 } 761 }
720 762
721 // Verify required options 763 // Verify required options
722 - for(const Option_p& opt : options) { 764 + for(const Option_p& opt : options_) {
723 // Required 765 // Required
724 if (opt->get_required() 766 if (opt->get_required()
725 && (opt->count() < opt->get_expected() || opt->count() == 0)) 767 && (opt->count() < opt->get_expected() || opt->count() == 0))
@@ -734,21 +776,21 @@ protected: @@ -734,21 +776,21 @@ protected:
734 throw ExcludesError(opt->get_name(), opt_ex->get_name()); 776 throw ExcludesError(opt->get_name(), opt_ex->get_name());
735 } 777 }
736 778
737 - if(required_subcommand < 0 && selected_subcommands.size() == 0) 779 + if(require_subcommand_ < 0 && selected_subcommands_.size() == 0)
738 throw RequiredError("Subcommand required"); 780 throw RequiredError("Subcommand required");
739 - else if(required_subcommand > 0 && selected_subcommands.size() != required_subcommand)  
740 - throw RequiredError(std::to_string(required_subcommand) + " subcommand(s) required"); 781 + else if(require_subcommand_ > 0 && selected_subcommands_.size() != require_subcommand_)
  782 + throw RequiredError(std::to_string(require_subcommand_) + " subcommand(s) required");
741 783
742 // Convert missing (pairs) to extras (string only) 784 // Convert missing (pairs) to extras (string only)
743 - args.resize(missing.size());  
744 - std::transform(std::begin(missing), std::end(missing), std::begin(args), 785 + args.resize(missing_.size());
  786 + std::transform(std::begin(missing_), std::end(missing_), std::begin(args),
745 [](const std::pair<detail::Classifer, std::string>& val){return val.second;}); 787 [](const std::pair<detail::Classifer, std::string>& val){return val.second;});
746 std::reverse(std::begin(args), std::end(args)); 788 std::reverse(std::begin(args), std::end(args));
747 789
748 - size_t num_left_over = std::count_if(std::begin(missing), std::end(missing), 790 + size_t num_left_over = std::count_if(std::begin(missing_), std::end(missing_),
749 [](std::pair<detail::Classifer, std::string>& val){return val.first != detail::Classifer::POSITIONAL_MARK;}); 791 [](std::pair<detail::Classifer, std::string>& val){return val.first != detail::Classifer::POSITIONAL_MARK;});
750 792
751 - if(num_left_over>0 && no_extras) 793 + if(num_left_over>0 && !allow_extras_)
752 throw ExtrasError("[" + detail::join(args, " ") + "]"); 794 throw ExtrasError("[" + detail::join(args, " ") + "]");
753 795
754 pre_callback(); 796 pre_callback();
@@ -760,10 +802,10 @@ protected: @@ -760,10 +802,10 @@ protected:
760 802
761 /// Parse a subcommand, modify args and continue 803 /// Parse a subcommand, modify args and continue
762 void _parse_subcommand(std::vector<std::string> &args) { 804 void _parse_subcommand(std::vector<std::string> &args) {
763 - for(const App_p &com : subcommands) { 805 + for(const App_p &com : subcommands_) {
764 if(com->check_name(args.back())){ 806 if(com->check_name(args.back())){
765 args.pop_back(); 807 args.pop_back();
766 - selected_subcommands.push_back(com.get()); 808 + selected_subcommands_.push_back(com.get());
767 com->parse(args); 809 com->parse(args);
768 return; 810 return;
769 } 811 }
@@ -775,16 +817,16 @@ protected: @@ -775,16 +817,16 @@ protected:
775 void _parse_short(std::vector<std::string> &args) { 817 void _parse_short(std::vector<std::string> &args) {
776 std::string current = args.back(); 818 std::string current = args.back();
777 819
778 - std::string name_; 820 + std::string name;
779 std::string rest; 821 std::string rest;
780 - if(!detail::split_short(current, name_, rest)) 822 + if(!detail::split_short(current, name, rest))
781 throw HorribleError("Short"); 823 throw HorribleError("Short");
782 args.pop_back(); 824 args.pop_back();
783 825
784 - auto op_ptr = std::find_if(std::begin(options), std::end(options), [name_](const Option_p &opt){return opt->check_sname(name_);}); 826 + auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name](const Option_p &opt){return opt->check_sname(name);});
785 827
786 - if(op_ptr == std::end(options)) {  
787 - missing.emplace_back(detail::Classifer::SHORT, "-" + name_); 828 + if(op_ptr == std::end(options_)) {
  829 + missing_.emplace_back(detail::Classifer::SHORT, "-" + name);
788 return; 830 return;
789 } 831 }
790 832
@@ -826,16 +868,16 @@ protected: @@ -826,16 +868,16 @@ protected:
826 void _parse_long(std::vector<std::string> &args, bool overwrite=true) { 868 void _parse_long(std::vector<std::string> &args, bool overwrite=true) {
827 std::string current = args.back(); 869 std::string current = args.back();
828 870
829 - std::string name_; 871 + std::string name;
830 std::string value; 872 std::string value;
831 - if(!detail::split_long(current, name_, value)) 873 + if(!detail::split_long(current, name, value))
832 throw HorribleError("Long"); 874 throw HorribleError("Long");
833 args.pop_back(); 875 args.pop_back();
834 876
835 - auto op_ptr = std::find_if(std::begin(options), std::end(options), [name_](const Option_p &v){return v->check_lname(name_);}); 877 + auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name](const Option_p &v){return v->check_lname(name);});
836 878
837 - if(op_ptr == std::end(options)) {  
838 - missing.emplace_back(detail::Classifer::LONG, "--" + name_); 879 + if(op_ptr == std::end(options_)) {
  880 + missing_.emplace_back(detail::Classifer::LONG, "--" + name);
839 return; 881 return;
840 } 882 }
841 883
@@ -843,7 +885,7 @@ protected: @@ -843,7 +885,7 @@ protected:
843 Option_p& op = *op_ptr; 885 Option_p& op = *op_ptr;
844 886
845 887
846 - // Stop if not overwriting options (for ini parse) 888 + // Stop if not overwriting options_ (for ini parse)
847 if(!overwrite && op->count() > 0) 889 if(!overwrite && op->count() > 0)
848 return; 890 return;
849 891
include/CLI/Option.hpp
@@ -29,36 +29,85 @@ typedef std::unique_ptr&lt;Option&gt; Option_p; @@ -29,36 +29,85 @@ typedef std::unique_ptr&lt;Option&gt; Option_p;
29 class Option { 29 class Option {
30 friend App; 30 friend App;
31 protected: 31 protected:
32 - // Config 32 + /// @name Names
  33 + ///@{
  34 +
  35 + /// A list of the short names (-a) without the leading dashes
33 std::vector<std::string> snames; 36 std::vector<std::string> snames;
  37 +
  38 + /// A list of the long names (--a) without the leading dashes
34 std::vector<std::string> lnames; 39 std::vector<std::string> lnames;
  40 +
  41 + /// A positional name
35 std::string pname; 42 std::string pname;
36 43
  44 + /// If given, check the environment for this option
  45 + std::string _envname;
  46 +
  47 + ///@}
  48 + /// @name Help
  49 + ///@{
  50 +
  51 + /// The description for help strings
37 std::string description; 52 std::string description;
38 - callback_t callback;  
39 53
40 - // These are for help strings 54 + /// A human readable default value, usually only set if default is true in creation
41 std::string defaultval; 55 std::string defaultval;
  56 +
  57 + /// A human readable type value, set when App creates this
42 std::string typeval; 58 std::string typeval;
  59 +
  60 + /// The group membership
43 std::string _group {"Options"}; 61 std::string _group {"Options"};
44 62
  63 + /// True if this option has a default
45 bool _default {false}; 64 bool _default {false};
  65 +
  66 + ///@}
  67 + /// @name Configuration
  68 + ///@{
  69 +
  70 + /// True if this is a required option
46 bool _required {false}; 71 bool _required {false};
  72 +
  73 + /// The number of expected values, 0 for flag, -1 for unlimited vector
47 int _expected {1}; 74 int _expected {1};
  75 +
  76 + /// A private setting to allow non-vector args to not be able to accept incorrect _expected values
48 bool allow_vector {false}; 77 bool allow_vector {false};
  78 +
  79 + /// Ignore the case when matching (option, not value)
49 bool case_insensitive {false}; 80 bool case_insensitive {false};
  81 +
  82 + /// A list of validators to run on each value parsed
50 std::vector<std::function<bool(std::string)>> _validators; 83 std::vector<std::function<bool(std::string)>> _validators;
51 84
  85 + /// A list of options that are required with this option
52 std::set<Option*> _requires; 86 std::set<Option*> _requires;
  87 +
  88 + /// A list of options that are excluded with this option
53 std::set<Option*> _excludes; 89 std::set<Option*> _excludes;
54 - std::string _envname; 90 +
  91 + ///@}
  92 + /// @name Other
  93 + ///@{
55 94
56 /// Remember the parent app 95 /// Remember the parent app
57 App* parent; 96 App* parent;
58 97
  98 + /// Options store a callback to do all the work
  99 + callback_t callback;
  100 +
  101 +
  102 + ///@}
  103 + /// @name Parsing results
  104 + ///@{
  105 +
59 /// Results of parsing 106 /// Results of parsing
60 results_t results; 107 results_t results;
61 108
  109 + ///@}
  110 +
62 /// Making an option by hand is not defined, it must be made by the App class 111 /// Making an option by hand is not defined, it must be made by the App class
63 Option(std::string name, std::string description = "", std::function<bool(results_t)> callback=[](results_t){return true;}, bool _default=true, App* parent = nullptr) : 112 Option(std::string name, std::string description = "", std::function<bool(results_t)> callback=[](results_t){return true;}, bool _default=true, App* parent = nullptr) :
64 description(description), callback(callback), _default(_default), parent(parent) { 113 description(description), callback(callback), _default(_default), parent(parent) {
@@ -247,12 +296,13 @@ public: @@ -247,12 +296,13 @@ public:
247 } 296 }
248 297
249 /// Ignore case 298 /// Ignore case
250 - /// The template hides the fact that we don't have the definition of App yet  
251 - /// You are never expected to add an argument to the template here 299 + ///
  300 + /// The template hides the fact that we don't have the definition of App yet.
  301 + /// You are never expected to add an argument to the template here.
252 template<typename T=App> 302 template<typename T=App>
253 Option* ignore_case(bool value = true) { 303 Option* ignore_case(bool value = true) {
254 case_insensitive = value; 304 case_insensitive = value;
255 - for(const Option_p& opt : dynamic_cast<T*>(parent)->options) 305 + for(const Option_p& opt : dynamic_cast<T*>(parent)->options_)
256 if(opt.get() != this && *opt == *this) 306 if(opt.get() != this && *opt == *this)
257 throw OptionAlreadyAdded(opt->get_name()); 307 throw OptionAlreadyAdded(opt->get_name());
258 return this; 308 return this;