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 41 friend Option;
42 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 49 /// Subcommand name or program name (from parser)
45   - std::string name {"program"};
  50 + std::string name_ {"program"};
46 51  
47 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 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 115 public:
75 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 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 129 /// it is not possible to overload on std::function (fixed in c++14
87 130 /// and backported to c++11 on newer compilers). Use capture by reference
88 131 /// to get a pointer to App if needed.
89 132 void set_callback(std::function<void()> callback) {
90   - app_callback = callback;
  133 + callback_ = callback;
91 134 }
92 135  
93 136 /// Reset the parsed data
94 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 143 opt->clear();
102 144 }
103   - for(const App_p &app : subcommands) {
  145 + for(const App_p &app : subcommands_) {
104 146 app->reset();
105 147 }
106 148 }
107 149  
108 150 /// Get a pointer to the help flag.
109 151 Option* get_help_ptr() {
110   - return help_flag;
  152 + return help_ptr_;
111 153 }
112 154  
113 155 /// Get a pointer to the config option.
114 156 Option* get_config_ptr() {
115   - return ini_setting;
  157 + return config_ptr_;
116 158 }
117 159  
118 160 /// Produce a string that could be read in as a config of the current values of the App
119 161 std::string config_to_str() const {
120 162 std::stringstream out;
121   - for(const Option_p &opt : options) {
  163 + for(const Option_p &opt : options_) {
122 164 if(opt->lnames.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
123 165 out << opt->lnames[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
124 166 }
... ... @@ -126,17 +168,17 @@ public:
126 168 }
127 169  
128 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 184 /// Add an option, will automatically understand the type for common types.
... ... @@ -144,7 +186,7 @@ public:
144 186 * After start is called, you can use count to see if the value was passed, and
145 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 190 * The positional options take an optional number of arguments.
149 191 *
150 192 * For example,
... ... @@ -153,18 +195,18 @@ public:
153 195 * program.add_option("filename", filename, "description of filename");
154 196 */
155 197 Option* add_option(
156   - std::string name_,
  198 + std::string name,
157 199 callback_t callback,
158   - std::string description_="",
  200 + std::string description="",
159 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 210 return option.get();
169 211 } else
170 212 throw OptionAlreadyAdded(myopt.get_name());
... ... @@ -174,9 +216,9 @@ public:
174 216 /// Add option for string
175 217 template<typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
176 218 Option* add_option(
177   - std::string name_,
  219 + std::string name,
178 220 T &variable, ///< The variable to set
179   - std::string description_="",
  221 + std::string description="",
180 222 bool defaulted=false
181 223 ) {
182 224  
... ... @@ -191,7 +233,7 @@ public:
191 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 237 retval->typeval = detail::type_name<T>();
196 238 if(defaulted) {
197 239 std::stringstream out;
... ... @@ -204,9 +246,9 @@ public:
204 246 /// Add option for vector of results
205 247 template<typename T>
206 248 Option* add_option(
207   - std::string name_,
  249 + std::string name,
208 250 std::vector<T> &variable, ///< The variable vector to set
209   - std::string description_="",
  251 + std::string description="",
210 252 bool defaulted=false
211 253 ) {
212 254  
... ... @@ -221,7 +263,7 @@ public:
221 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 267 retval->allow_vector = true;
226 268 retval->_expected = -1;
227 269 retval->typeval = detail::type_name<T>();
... ... @@ -233,14 +275,14 @@ public:
233 275  
234 276 /// Add option for flag
235 277 Option* add_flag(
236   - std::string name_,
237   - std::string description_=""
  278 + std::string name,
  279 + std::string description=""
238 280 ) {
239 281 CLI::callback_t fun = [](CLI::results_t){
240 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 286 if(opt->get_positional())
245 287 throw IncorrectConstruction("Flags cannot be positional");
246 288 opt->_expected = 0;
... ... @@ -251,9 +293,9 @@ public:
251 293 template<typename T,
252 294 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
253 295 Option* add_flag(
254   - std::string name_,
  296 + std::string name,
255 297 T &count, ///< A varaible holding the count
256   - std::string description_=""
  298 + std::string description=""
257 299 ) {
258 300  
259 301 count = 0;
... ... @@ -262,7 +304,7 @@ public:
262 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 308 if(opt->get_positional())
267 309 throw IncorrectConstruction("Flags cannot be positional");
268 310 opt->_expected = 0;
... ... @@ -273,9 +315,9 @@ public:
273 315 template<typename T,
274 316 enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy>
275 317 Option* add_flag(
276   - std::string name_,
  318 + std::string name,
277 319 T &count, ///< A varaible holding true if passed
278   - std::string description_=""
  320 + std::string description=""
279 321 ) {
280 322  
281 323 count = false;
... ... @@ -284,7 +326,7 @@ public:
284 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 330 if(opt->get_positional())
289 331 throw IncorrectConstruction("Flags cannot be positional");
290 332 opt->_expected = 0;
... ... @@ -292,13 +334,13 @@ public:
292 334 }
293 335  
294 336  
295   - /// Add set of options
  337 + /// Add set of options_
296 338 template<typename T>
297 339 Option* add_set(
298   - std::string name_,
  340 + std::string name,
299 341 T &member, ///< The selected member of the set
300 342 std::set<T> _options, ///< The set of posibilities
301   - std::string description_="",
  343 + std::string description="",
302 344 bool defaulted=false
303 345 ) {
304 346  
... ... @@ -315,7 +357,7 @@ public:
315 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 361 retval->typeval = detail::type_name<T>();
320 362 retval->typeval += " in {" + detail::join(_options) + "}";
321 363 if(defaulted) {
... ... @@ -328,10 +370,10 @@ public:
328 370  
329 371 /// Add set of options, string only, ignore case
330 372 Option* add_set_ignore_case(
331   - std::string name_,
  373 + std::string name,
332 374 std::string &member, ///< The selected member of the set
333 375 std::set<std::string> _options, ///< The set of posibilities
334   - std::string description_="",
  376 + std::string description="",
335 377 bool defaulted=false
336 378 ) {
337 379  
... ... @@ -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 399 retval->typeval = detail::type_name<std::string>();
358 400 retval->typeval += " in {" + detail::join(_options) + "}";
359 401 if(defaulted) {
... ... @@ -364,26 +406,26 @@ public:
364 406  
365 407  
366 408 /// Add a configuration ini file option
367   - Option* add_config(std::string name_="--config",
  409 + Option* add_config(std::string name="--config",
368 410 std::string default_filename="",
369 411 std::string help="Read an ini file",
370 412 bool required=false) {
371 413  
372 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 423 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
382 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 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 429 return true;
388 430 }
389 431 return false;
... ... @@ -396,7 +438,7 @@ public:
396 438 /// Parses the command line - throws errors
397 439 /// This must be called after the options are in but before the rest of the program.
398 440 std::vector<std::string> parse(int argc, char **argv) {
399   - name = argv[0];
  441 + name_ = argv[0];
400 442 std::vector<std::string> args;
401 443 for(int i=argc-1; i>0; i--)
402 444 args.push_back(argv[i]);
... ... @@ -412,7 +454,7 @@ public:
412 454  
413 455 /// Remove the error when extras are left over on the command line.
414 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 473 }
432 474  
433 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 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 486 std::string help(size_t wid=30, std::string prev="") const {
445 487 // Delegate to subcommand if needed
446 488 if(prev == "")
447   - prev = name;
  489 + prev = name_;
448 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 496 std::stringstream out;
455   - out << description << std::endl;
  497 + out << description_ << std::endl;
456 498 out << "Usage: " << prev;
457 499  
458   - // Check for options
  500 + // Check for options_
459 501 bool npos = false;
460 502 std::set<std::string> groups;
461   - for(const Option_p &opt : options) {
  503 + for(const Option_p &opt : options_) {
462 504 if(opt->nonpositional()) {
463 505 npos = true;
464 506 groups.insert(opt->get_group());
... ... @@ -470,7 +512,7 @@ public:
470 512  
471 513 // Positionals
472 514 bool pos=false;
473   - for(const Option_p &opt : options)
  515 + for(const Option_p &opt : options_)
474 516 if(opt->get_positional()) {
475 517 // A hidden positional should still show up in the usage statement
476 518 //if(detail::to_lower(opt->get_group()) == "hidden")
... ... @@ -480,8 +522,8 @@ public:
480 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 527 out << " SUBCOMMAND";
486 528 else
487 529 out << " [SUBCOMMAND]";
... ... @@ -492,7 +534,7 @@ public:
492 534 // Positional descriptions
493 535 if(pos) {
494 536 out << "Positionals:" << std::endl;
495   - for(const Option_p &opt : options) {
  537 + for(const Option_p &opt : options_) {
496 538 if(detail::to_lower(opt->get_group()) == "hidden")
497 539 continue;
498 540 if(opt->get_positional() && opt->has_description())
... ... @@ -509,7 +551,7 @@ public:
509 551 if(detail::to_lower(group) == "hidden")
510 552 continue;
511 553 out << group << ":" << std::endl;
512   - for(const Option_p &opt : options) {
  554 + for(const Option_p &opt : options_) {
513 555 if(opt->nonpositional() && opt->get_group() == group)
514 556 detail::format_help(out, opt->help_name(), opt->get_description(), wid);
515 557  
... ... @@ -519,43 +561,45 @@ public:
519 561 }
520 562  
521 563 // Subcommands
522   - if(subcommands.size()> 0) {
  564 + if(subcommands_.size()> 0) {
523 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 569 return out.str();
528 570 }
529 571  
530 572 /// Get a subcommand pointer list to the currently selected subcommands (after parsing)
531 573 std::vector<App*> get_subcommands() {
532   - return selected_subcommands;
  574 + return selected_subcommands_;
533 575 }
534 576  
535 577  
536 578 /// Check to see if selected subcommand in list
537 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 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 589 return true;
546 590 return false;
547 591 }
548 592  
549 593 /// Get the name of the current app
550 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 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 603 name_to_check = detail::to_lower(name_to_check);
560 604 }
561 605  
... ... @@ -564,11 +608,11 @@ public:
564 608  
565 609 /// Ignore case
566 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 618 return this;
... ... @@ -577,15 +621,15 @@ public:
577 621 /// Require a subcommand to be given (does not affect help call)
578 622 /// Does not return a pointer since it is supposed to be called on the main App.
579 623 void require_subcommand(int value = -1) {
580   - required_subcommand = value;
  624 + require_subcommand_ = value;
581 625 }
582 626  
583 627 protected:
584 628  
585 629 /// Internal function to run (App) callback
586 630 void run_callback() {
587   - if(app_callback)
588   - app_callback();
  631 + if(callback_)
  632 + callback_();
589 633 }
590 634  
591 635 /// Selects a Classifer enum based on the type of the current argument
... ... @@ -594,7 +638,7 @@ protected:
594 638  
595 639 if(current == "--")
596 640 return detail::Classifer::POSITIONAL_MARK;
597   - for(const App_p &com : subcommands) {
  641 + for(const App_p &com : subcommands_) {
598 642 if(com->check_name(current))
599 643 return detail::Classifer::SUBCOMMAND;
600 644 }
... ... @@ -608,8 +652,6 @@ protected:
608 652  
609 653 /// Internal parse function
610 654 std::vector<std::string>& _parse(std::vector<std::string> &args) {
611   - parsed = true;
612   -
613 655 bool positional_only = false;
614 656  
615 657 while(args.size()>0) {
... ... @@ -618,7 +660,7 @@ protected:
618 660 detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back());
619 661 switch(classifer) {
620 662 case detail::Classifer::POSITIONAL_MARK:
621   - missing.emplace_back(classifer, args.back());
  663 + missing_.emplace_back(classifer, args.back());
622 664 args.pop_back();
623 665 positional_only = true;
624 666 break;
... ... @@ -626,29 +668,29 @@ protected:
626 668 _parse_subcommand(args);
627 669 break;
628 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 674 args.pop_back();
633 675 } else
634 676 _parse_long(args);
635 677 break;
636 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 682 args.pop_back();
641 683 } else
642 684 _parse_short(args);
643 685 break;
644 686 case detail::Classifer::NONE:
645 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 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 694 throw CallForHelp();
653 695 }
654 696  
... ... @@ -656,52 +698,52 @@ protected:
656 698 // Collect positionals
657 699  
658 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 703 // Skip non-positionals (speedup)
662   - if(missing.at(i).first != detail::Classifer::NONE)
  704 + if(missing_.at(i).first != detail::Classifer::NONE)
663 705 continue;
664 706  
665 707 // Loop over all options
666   - for(const Option_p& opt : options) {
  708 + for(const Option_p& opt : options_) {
667 709  
668 710 // Eat options, one by one, until done
669 711 while ( opt->get_positional()
670 712 && opt->count() < opt->get_expected()
671   - && i < missing.size()
  713 + && i < missing_.size()
672 714 ) {
673 715  
674 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 718 i++;
677 719 continue;
678 720 }
679 721  
680 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 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 730 // Process an INI file
689   - if (ini_setting != nullptr && ini_file != "") {
  731 + if (config_ptr_ != nullptr && config_name_ != "") {
690 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 734 while(values.size() > 0) {
693 735 _parse_long(values, false);
694 736 }
695 737  
696 738 } catch (const FileError &) {
697   - if(ini_required)
  739 + if(config_required_)
698 740 throw;
699 741 }
700 742 }
701 743  
702 744  
703 745 // Get envname options if not yet passed
704   - for(const Option_p& opt : options) {
  746 + for(const Option_p& opt : options_) {
705 747 if (opt->count() == 0 && opt->_envname != "") {
706 748 char *ename = std::getenv(opt->_envname.c_str());
707 749 if(ename != nullptr) {
... ... @@ -712,14 +754,14 @@ protected:
712 754 }
713 755  
714 756 // Process callbacks
715   - for(const Option_p& opt : options) {
  757 + for(const Option_p& opt : options_) {
716 758 if (opt->count() > 0) {
717 759 opt->run_callback();
718 760 }
719 761 }
720 762  
721 763 // Verify required options
722   - for(const Option_p& opt : options) {
  764 + for(const Option_p& opt : options_) {
723 765 // Required
724 766 if (opt->get_required()
725 767 && (opt->count() < opt->get_expected() || opt->count() == 0))
... ... @@ -734,21 +776,21 @@ protected:
734 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 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 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 787 [](const std::pair<detail::Classifer, std::string>& val){return val.second;});
746 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 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 794 throw ExtrasError("[" + detail::join(args, " ") + "]");
753 795  
754 796 pre_callback();
... ... @@ -760,10 +802,10 @@ protected:
760 802  
761 803 /// Parse a subcommand, modify args and continue
762 804 void _parse_subcommand(std::vector<std::string> &args) {
763   - for(const App_p &com : subcommands) {
  805 + for(const App_p &com : subcommands_) {
764 806 if(com->check_name(args.back())){
765 807 args.pop_back();
766   - selected_subcommands.push_back(com.get());
  808 + selected_subcommands_.push_back(com.get());
767 809 com->parse(args);
768 810 return;
769 811 }
... ... @@ -775,16 +817,16 @@ protected:
775 817 void _parse_short(std::vector<std::string> &args) {
776 818 std::string current = args.back();
777 819  
778   - std::string name_;
  820 + std::string name;
779 821 std::string rest;
780   - if(!detail::split_short(current, name_, rest))
  822 + if(!detail::split_short(current, name, rest))
781 823 throw HorribleError("Short");
782 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 830 return;
789 831 }
790 832  
... ... @@ -826,16 +868,16 @@ protected:
826 868 void _parse_long(std::vector<std::string> &args, bool overwrite=true) {
827 869 std::string current = args.back();
828 870  
829   - std::string name_;
  871 + std::string name;
830 872 std::string value;
831   - if(!detail::split_long(current, name_, value))
  873 + if(!detail::split_long(current, name, value))
832 874 throw HorribleError("Long");
833 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 881 return;
840 882 }
841 883  
... ... @@ -843,7 +885,7 @@ protected:
843 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 889 if(!overwrite && op->count() > 0)
848 890 return;
849 891  
... ...
include/CLI/Option.hpp
... ... @@ -29,36 +29,85 @@ typedef std::unique_ptr&lt;Option&gt; Option_p;
29 29 class Option {
30 30 friend App;
31 31 protected:
32   - // Config
  32 + /// @name Names
  33 + ///@{
  34 +
  35 + /// A list of the short names (-a) without the leading dashes
33 36 std::vector<std::string> snames;
  37 +
  38 + /// A list of the long names (--a) without the leading dashes
34 39 std::vector<std::string> lnames;
  40 +
  41 + /// A positional name
35 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 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 55 std::string defaultval;
  56 +
  57 + /// A human readable type value, set when App creates this
42 58 std::string typeval;
  59 +
  60 + /// The group membership
43 61 std::string _group {"Options"};
44 62  
  63 + /// True if this option has a default
45 64 bool _default {false};
  65 +
  66 + ///@}
  67 + /// @name Configuration
  68 + ///@{
  69 +
  70 + /// True if this is a required option
46 71 bool _required {false};
  72 +
  73 + /// The number of expected values, 0 for flag, -1 for unlimited vector
47 74 int _expected {1};
  75 +
  76 + /// A private setting to allow non-vector args to not be able to accept incorrect _expected values
48 77 bool allow_vector {false};
  78 +
  79 + /// Ignore the case when matching (option, not value)
49 80 bool case_insensitive {false};
  81 +
  82 + /// A list of validators to run on each value parsed
50 83 std::vector<std::function<bool(std::string)>> _validators;
51 84  
  85 + /// A list of options that are required with this option
52 86 std::set<Option*> _requires;
  87 +
  88 + /// A list of options that are excluded with this option
53 89 std::set<Option*> _excludes;
54   - std::string _envname;
  90 +
  91 + ///@}
  92 + /// @name Other
  93 + ///@{
55 94  
56 95 /// Remember the parent app
57 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 106 /// Results of parsing
60 107 results_t results;
61 108  
  109 + ///@}
  110 +
62 111 /// Making an option by hand is not defined, it must be made by the App class
63 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 113 description(description), callback(callback), _default(_default), parent(parent) {
... ... @@ -247,12 +296,13 @@ public:
247 296 }
248 297  
249 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 302 template<typename T=App>
253 303 Option* ignore_case(bool value = true) {
254 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 306 if(opt.get() != this && *opt == *this)
257 307 throw OptionAlreadyAdded(opt->get_name());
258 308 return this;
... ...