1 // Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner 2 // under NSF AWARD 1414736 and by the respective contributors. 3 // All rights reserved. 4 // 5 // SPDX-License-Identifier: BSD-3-Clause 6 7 #pragma once 8 9 // [CLI11:public_includes:set] 10 #include <algorithm> 11 #include <functional> 12 #include <memory> 13 #include <set> 14 #include <string> 15 #include <tuple> 16 #include <utility> 17 #include <vector> 18 // [CLI11:public_includes:end] 19 20 #include "Error.hpp" 21 #include "Macros.hpp" 22 #include "Split.hpp" 23 #include "StringTools.hpp" 24 #include "Validators.hpp" 25 26 namespace CLI { 27 // [CLI11:option_hpp:verbatim] 28 29 using results_t = std::vector<std::string>; 30 /// callback function definition 31 using callback_t = std::function<bool(const results_t &)>; 32 33 class Option; 34 class App; 35 36 using Option_p = std::unique_ptr<Option>; 37 /// Enumeration of the multiOption Policy selection 38 enum class MultiOptionPolicy : char { 39 Throw, //!< Throw an error if any extra arguments were given 40 TakeLast, //!< take only the last Expected number of arguments 41 TakeFirst, //!< take only the first Expected number of arguments 42 Join, //!< merge all the arguments together into a single string via the delimiter character default('\n') 43 TakeAll //!< just get all the passed argument regardless 44 }; 45 46 /// This is the CRTP base class for Option and OptionDefaults. It was designed this way 47 /// to share parts of the class; an OptionDefaults can copy to an Option. 48 template <typename CRTP> class OptionBase { 49 friend App; 50 51 protected: 52 /// The group membership 53 std::string group_ = std::string("Options"); 54 55 /// True if this is a required option 56 bool required_{false}; 57 58 /// Ignore the case when matching (option, not value) 59 bool ignore_case_{false}; 60 61 /// Ignore underscores when matching (option, not value) 62 bool ignore_underscore_{false}; 63 64 /// Allow this option to be given in a configuration file 65 bool configurable_{true}; 66 67 /// Disable overriding flag values with '=value' 68 bool disable_flag_override_{false}; 69 70 /// Specify a delimiter character for vector arguments 71 char delimiter_{'\0'}; 72 73 /// Automatically capture default value 74 bool always_capture_default_{false}; 75 76 /// Policy for handling multiple arguments beyond the expected Max 77 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw}; 78 79 /// Copy the contents to another similar class (one based on OptionBase) copy_to(T * other) const80 template <typename T> void copy_to(T *other) const { 81 other->group(group_); 82 other->required(required_); 83 other->ignore_case(ignore_case_); 84 other->ignore_underscore(ignore_underscore_); 85 other->configurable(configurable_); 86 other->disable_flag_override(disable_flag_override_); 87 other->delimiter(delimiter_); 88 other->always_capture_default(always_capture_default_); 89 other->multi_option_policy(multi_option_policy_); 90 } 91 92 public: 93 // setters 94 95 /// Changes the group membership group(const std::string & name)96 CRTP *group(const std::string &name) { 97 if(!detail::valid_alias_name_string(name)) { 98 throw IncorrectConstruction("Group names may not contain newlines or null characters"); 99 } 100 group_ = name; 101 return static_cast<CRTP *>(this); 102 } 103 104 /// Set the option as required required(bool value=true)105 CRTP *required(bool value = true) { 106 required_ = value; 107 return static_cast<CRTP *>(this); 108 } 109 110 /// Support Plumbum term mandatory(bool value=true)111 CRTP *mandatory(bool value = true) { return required(value); } 112 always_capture_default(bool value=true)113 CRTP *always_capture_default(bool value = true) { 114 always_capture_default_ = value; 115 return static_cast<CRTP *>(this); 116 } 117 118 // Getters 119 120 /// Get the group of this option get_group() const121 const std::string &get_group() const { return group_; } 122 123 /// True if this is a required option get_required() const124 bool get_required() const { return required_; } 125 126 /// The status of ignore case get_ignore_case() const127 bool get_ignore_case() const { return ignore_case_; } 128 129 /// The status of ignore_underscore get_ignore_underscore() const130 bool get_ignore_underscore() const { return ignore_underscore_; } 131 132 /// The status of configurable get_configurable() const133 bool get_configurable() const { return configurable_; } 134 135 /// The status of configurable get_disable_flag_override() const136 bool get_disable_flag_override() const { return disable_flag_override_; } 137 138 /// Get the current delimiter char get_delimiter() const139 char get_delimiter() const { return delimiter_; } 140 141 /// Return true if this will automatically capture the default value for help printing get_always_capture_default() const142 bool get_always_capture_default() const { return always_capture_default_; } 143 144 /// The status of the multi option policy get_multi_option_policy() const145 MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; } 146 147 // Shortcuts for multi option policy 148 149 /// Set the multi option policy to take last take_last()150 CRTP *take_last() { 151 auto self = static_cast<CRTP *>(this); 152 self->multi_option_policy(MultiOptionPolicy::TakeLast); 153 return self; 154 } 155 156 /// Set the multi option policy to take last take_first()157 CRTP *take_first() { 158 auto self = static_cast<CRTP *>(this); 159 self->multi_option_policy(MultiOptionPolicy::TakeFirst); 160 return self; 161 } 162 163 /// Set the multi option policy to take all arguments take_all()164 CRTP *take_all() { 165 auto self = static_cast<CRTP *>(this); 166 self->multi_option_policy(MultiOptionPolicy::TakeAll); 167 return self; 168 } 169 170 /// Set the multi option policy to join join()171 CRTP *join() { 172 auto self = static_cast<CRTP *>(this); 173 self->multi_option_policy(MultiOptionPolicy::Join); 174 return self; 175 } 176 177 /// Set the multi option policy to join with a specific delimiter join(char delim)178 CRTP *join(char delim) { 179 auto self = static_cast<CRTP *>(this); 180 self->delimiter_ = delim; 181 self->multi_option_policy(MultiOptionPolicy::Join); 182 return self; 183 } 184 185 /// Allow in a configuration file configurable(bool value=true)186 CRTP *configurable(bool value = true) { 187 configurable_ = value; 188 return static_cast<CRTP *>(this); 189 } 190 191 /// Allow in a configuration file delimiter(char value='\\0')192 CRTP *delimiter(char value = '\0') { 193 delimiter_ = value; 194 return static_cast<CRTP *>(this); 195 } 196 }; 197 198 /// This is a version of OptionBase that only supports setting values, 199 /// for defaults. It is stored as the default option in an App. 200 class OptionDefaults : public OptionBase<OptionDefaults> { 201 public: 202 OptionDefaults() = default; 203 204 // Methods here need a different implementation if they are Option vs. OptionDefault 205 206 /// Take the last argument if given multiple times multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)207 OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) { 208 multi_option_policy_ = value; 209 return this; 210 } 211 212 /// Ignore the case of the option name ignore_case(bool value=true)213 OptionDefaults *ignore_case(bool value = true) { 214 ignore_case_ = value; 215 return this; 216 } 217 218 /// Ignore underscores in the option name ignore_underscore(bool value=true)219 OptionDefaults *ignore_underscore(bool value = true) { 220 ignore_underscore_ = value; 221 return this; 222 } 223 224 /// Disable overriding flag values with an '=<value>' segment disable_flag_override(bool value=true)225 OptionDefaults *disable_flag_override(bool value = true) { 226 disable_flag_override_ = value; 227 return this; 228 } 229 230 /// set a delimiter character to split up single arguments to treat as multiple inputs delimiter(char value='\\0')231 OptionDefaults *delimiter(char value = '\0') { 232 delimiter_ = value; 233 return this; 234 } 235 }; 236 237 class Option : public OptionBase<Option> { 238 friend App; 239 240 protected: 241 /// @name Names 242 ///@{ 243 244 /// A list of the short names (`-a`) without the leading dashes 245 std::vector<std::string> snames_{}; 246 247 /// A list of the long names (`--long`) without the leading dashes 248 std::vector<std::string> lnames_{}; 249 250 /// A list of the flag names with the appropriate default value, the first part of the pair should be duplicates of 251 /// what is in snames or lnames but will trigger a particular response on a flag 252 std::vector<std::pair<std::string, std::string>> default_flag_values_{}; 253 254 /// a list of flag names with specified default values; 255 std::vector<std::string> fnames_{}; 256 257 /// A positional name 258 std::string pname_{}; 259 260 /// If given, check the environment for this option 261 std::string envname_{}; 262 263 ///@} 264 /// @name Help 265 ///@{ 266 267 /// The description for help strings 268 std::string description_{}; 269 270 /// A human readable default value, either manually set, captured, or captured by default 271 std::string default_str_{}; 272 273 /// If given, replace the text that describes the option type and usage in the help text 274 std::string option_text_{}; 275 276 /// A human readable type value, set when App creates this 277 /// 278 /// This is a lambda function so "types" can be dynamic, such as when a set prints its contents. __anond6b818020102() 279 std::function<std::string()> type_name_{[]() { return std::string(); }}; 280 281 /// Run this function to capture a default (ignore if empty) 282 std::function<std::string()> default_function_{}; 283 284 ///@} 285 /// @name Configuration 286 ///@{ 287 288 /// The number of arguments that make up one option. max is the nominal type size, min is the minimum number of 289 /// strings 290 int type_size_max_{1}; 291 /// The minimum number of arguments an option should be expecting 292 int type_size_min_{1}; 293 294 /// The minimum number of expected values 295 int expected_min_{1}; 296 /// The maximum number of expected values 297 int expected_max_{1}; 298 299 /// A list of Validators to run on each value parsed 300 std::vector<Validator> validators_{}; 301 302 /// A list of options that are required with this option 303 std::set<Option *> needs_{}; 304 305 /// A list of options that are excluded with this option 306 std::set<Option *> excludes_{}; 307 308 ///@} 309 /// @name Other 310 ///@{ 311 312 /// link back up to the parent App for fallthrough 313 App *parent_{nullptr}; 314 315 /// Options store a callback to do all the work 316 callback_t callback_{}; 317 318 ///@} 319 /// @name Parsing results 320 ///@{ 321 322 /// complete Results of parsing 323 results_t results_{}; 324 /// results after reduction 325 results_t proc_results_{}; 326 /// enumeration for the option state machine 327 enum class option_state : char { 328 parsing = 0, //!< The option is currently collecting parsed results 329 validated = 2, //!< the results have been validated 330 reduced = 4, //!< a subset of results has been generated 331 callback_run = 6, //!< the callback has been executed 332 }; 333 /// Whether the callback has run (needed for INI parsing) 334 option_state current_option_state_{option_state::parsing}; 335 /// Specify that extra args beyond type_size_max should be allowed 336 bool allow_extra_args_{false}; 337 /// Specify that the option should act like a flag vs regular option 338 bool flag_like_{false}; 339 /// Control option to run the callback to set the default 340 bool run_callback_for_default_{false}; 341 /// flag indicating a separator needs to be injected after each argument call 342 bool inject_separator_{false}; 343 /// flag indicating that the option should trigger the validation and callback chain on each result when loaded 344 bool trigger_on_result_{false}; 345 /// flag indicating that the option should force the callback regardless if any results present 346 bool force_callback_{false}; 347 ///@} 348 349 /// Making an option by hand is not defined, it must be made by the App class Option(std::string option_name,std::string option_description,callback_t callback,App * parent)350 Option(std::string option_name, std::string option_description, callback_t callback, App *parent) 351 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) { 352 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name)); 353 } 354 355 public: 356 /// @name Basic 357 ///@{ 358 359 Option(const Option &) = delete; 360 Option &operator=(const Option &) = delete; 361 362 /// Count the total number of times an option was passed count() const363 std::size_t count() const { return results_.size(); } 364 365 /// True if the option was not passed empty() const366 bool empty() const { return results_.empty(); } 367 368 /// This bool operator returns true if any arguments were passed or the option callback is forced operator bool() const369 explicit operator bool() const { return !empty() || force_callback_; } 370 371 /// Clear the parsed results (mostly for testing) clear()372 void clear() { 373 results_.clear(); 374 current_option_state_ = option_state::parsing; 375 } 376 377 ///@} 378 /// @name Setting options 379 ///@{ 380 381 /// Set the number of expected arguments expected(int value)382 Option *expected(int value) { 383 if(value < 0) { 384 expected_min_ = -value; 385 if(expected_max_ < expected_min_) { 386 expected_max_ = expected_min_; 387 } 388 allow_extra_args_ = true; 389 flag_like_ = false; 390 } else if(value == detail::expected_max_vector_size) { 391 expected_min_ = 1; 392 expected_max_ = detail::expected_max_vector_size; 393 allow_extra_args_ = true; 394 flag_like_ = false; 395 } else { 396 expected_min_ = value; 397 expected_max_ = value; 398 flag_like_ = (expected_min_ == 0); 399 } 400 return this; 401 } 402 403 /// Set the range of expected arguments expected(int value_min,int value_max)404 Option *expected(int value_min, int value_max) { 405 if(value_min < 0) { 406 value_min = -value_min; 407 } 408 409 if(value_max < 0) { 410 value_max = detail::expected_max_vector_size; 411 } 412 if(value_max < value_min) { 413 expected_min_ = value_max; 414 expected_max_ = value_min; 415 } else { 416 expected_max_ = value_max; 417 expected_min_ = value_min; 418 } 419 420 return this; 421 } 422 /// Set the value of allow_extra_args which allows extra value arguments on the flag or option to be included 423 /// with each instance allow_extra_args(bool value=true)424 Option *allow_extra_args(bool value = true) { 425 allow_extra_args_ = value; 426 return this; 427 } 428 /// Get the current value of allow extra args get_allow_extra_args() const429 bool get_allow_extra_args() const { return allow_extra_args_; } 430 /// Set the value of trigger_on_parse which specifies that the option callback should be triggered on every parse trigger_on_parse(bool value=true)431 Option *trigger_on_parse(bool value = true) { 432 trigger_on_result_ = value; 433 return this; 434 } 435 /// The status of trigger on parse get_trigger_on_parse() const436 bool get_trigger_on_parse() const { return trigger_on_result_; } 437 438 /// Set the value of force_callback force_callback(bool value=true)439 Option *force_callback(bool value = true) { 440 force_callback_ = value; 441 return this; 442 } 443 /// The status of force_callback get_force_callback() const444 bool get_force_callback() const { return force_callback_; } 445 446 /// Set the value of run_callback_for_default which controls whether the callback function should be called to set 447 /// the default This is controlled automatically but could be manipulated by the user. run_callback_for_default(bool value=true)448 Option *run_callback_for_default(bool value = true) { 449 run_callback_for_default_ = value; 450 return this; 451 } 452 /// Get the current value of run_callback_for_default get_run_callback_for_default() const453 bool get_run_callback_for_default() const { return run_callback_for_default_; } 454 455 /// Adds a Validator with a built in type name check(Validator validator,const std::string & validator_name="")456 Option *check(Validator validator, const std::string &validator_name = "") { 457 validator.non_modifying(); 458 validators_.push_back(std::move(validator)); 459 if(!validator_name.empty()) 460 validators_.back().name(validator_name); 461 return this; 462 } 463 464 /// Adds a Validator. Takes a const string& and returns an error message (empty if conversion/check is okay). check(std::function<std::string (const std::string &)> Validator,std::string Validator_description="",std::string Validator_name="")465 Option *check(std::function<std::string(const std::string &)> Validator, 466 std::string Validator_description = "", 467 std::string Validator_name = "") { 468 validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name)); 469 validators_.back().non_modifying(); 470 return this; 471 } 472 473 /// Adds a transforming Validator with a built in type name transform(Validator Validator,const std::string & Validator_name="")474 Option *transform(Validator Validator, const std::string &Validator_name = "") { 475 validators_.insert(validators_.begin(), std::move(Validator)); 476 if(!Validator_name.empty()) 477 validators_.front().name(Validator_name); 478 return this; 479 } 480 481 /// Adds a Validator-like function that can change result transform(const std::function<std::string (std::string)> & func,std::string transform_description="",std::string transform_name="")482 Option *transform(const std::function<std::string(std::string)> &func, 483 std::string transform_description = "", 484 std::string transform_name = "") { 485 validators_.insert(validators_.begin(), 486 Validator( 487 [func](std::string &val) { 488 val = func(val); 489 return std::string{}; 490 }, 491 std::move(transform_description), 492 std::move(transform_name))); 493 494 return this; 495 } 496 497 /// Adds a user supplied function to run on each item passed in (communicate though lambda capture) each(const std::function<void (std::string)> & func)498 Option *each(const std::function<void(std::string)> &func) { 499 validators_.emplace_back( 500 [func](std::string &inout) { 501 func(inout); 502 return std::string{}; 503 }, 504 std::string{}); 505 return this; 506 } 507 /// Get a named Validator get_validator(const std::string & Validator_name="")508 Validator *get_validator(const std::string &Validator_name = "") { 509 for(auto &Validator : validators_) { 510 if(Validator_name == Validator.get_name()) { 511 return &Validator; 512 } 513 } 514 if((Validator_name.empty()) && (!validators_.empty())) { 515 return &(validators_.front()); 516 } 517 throw OptionNotFound(std::string{"Validator "} + Validator_name + " Not Found"); 518 } 519 520 /// Get a Validator by index NOTE: this may not be the order of definition get_validator(int index)521 Validator *get_validator(int index) { 522 // This is an signed int so that it is not equivalent to a pointer. 523 if(index >= 0 && index < static_cast<int>(validators_.size())) { 524 return &(validators_[static_cast<decltype(validators_)::size_type>(index)]); 525 } 526 throw OptionNotFound("Validator index is not valid"); 527 } 528 529 /// Sets required options needs(Option * opt)530 Option *needs(Option *opt) { 531 if(opt != this) { 532 needs_.insert(opt); 533 } 534 return this; 535 } 536 537 /// Can find a string if needed needs(std::string opt_name)538 template <typename T = App> Option *needs(std::string opt_name) { 539 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name); 540 if(opt == nullptr) { 541 throw IncorrectConstruction::MissingOption(opt_name); 542 } 543 return needs(opt); 544 } 545 546 /// Any number supported, any mix of string and Opt needs(A opt,B opt1,ARG...args)547 template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) { 548 needs(opt); 549 return needs(opt1, args...); 550 } 551 552 /// Remove needs link from an option. Returns true if the option really was in the needs list. remove_needs(Option * opt)553 bool remove_needs(Option *opt) { 554 auto iterator = std::find(std::begin(needs_), std::end(needs_), opt); 555 556 if(iterator == std::end(needs_)) { 557 return false; 558 } 559 needs_.erase(iterator); 560 return true; 561 } 562 563 /// Sets excluded options excludes(Option * opt)564 Option *excludes(Option *opt) { 565 if(opt == this) { 566 throw(IncorrectConstruction("and option cannot exclude itself")); 567 } 568 excludes_.insert(opt); 569 570 // Help text should be symmetric - excluding a should exclude b 571 opt->excludes_.insert(this); 572 573 // Ignoring the insert return value, excluding twice is now allowed. 574 // (Mostly to allow both directions to be excluded by user, even though the library does it for you.) 575 576 return this; 577 } 578 579 /// Can find a string if needed excludes(std::string opt_name)580 template <typename T = App> Option *excludes(std::string opt_name) { 581 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name); 582 if(opt == nullptr) { 583 throw IncorrectConstruction::MissingOption(opt_name); 584 } 585 return excludes(opt); 586 } 587 588 /// Any number supported, any mix of string and Opt excludes(A opt,B opt1,ARG...args)589 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) { 590 excludes(opt); 591 return excludes(opt1, args...); 592 } 593 594 /// Remove needs link from an option. Returns true if the option really was in the needs list. remove_excludes(Option * opt)595 bool remove_excludes(Option *opt) { 596 auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt); 597 598 if(iterator == std::end(excludes_)) { 599 return false; 600 } 601 excludes_.erase(iterator); 602 return true; 603 } 604 605 /// Sets environment variable to read if no option given envname(std::string name)606 Option *envname(std::string name) { 607 envname_ = std::move(name); 608 return this; 609 } 610 611 /// Ignore case 612 /// 613 /// The template hides the fact that we don't have the definition of App yet. 614 /// You are never expected to add an argument to the template here. ignore_case(bool value=true)615 template <typename T = App> Option *ignore_case(bool value = true) { 616 if(!ignore_case_ && value) { 617 ignore_case_ = value; 618 auto *parent = static_cast<T *>(parent_); 619 for(const Option_p &opt : parent->options_) { 620 if(opt.get() == this) { 621 continue; 622 } 623 auto &omatch = opt->matching_name(*this); 624 if(!omatch.empty()) { 625 ignore_case_ = false; 626 throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch); 627 } 628 } 629 } else { 630 ignore_case_ = value; 631 } 632 return this; 633 } 634 635 /// Ignore underscores in the option names 636 /// 637 /// The template hides the fact that we don't have the definition of App yet. 638 /// You are never expected to add an argument to the template here. ignore_underscore(bool value=true)639 template <typename T = App> Option *ignore_underscore(bool value = true) { 640 641 if(!ignore_underscore_ && value) { 642 ignore_underscore_ = value; 643 auto *parent = static_cast<T *>(parent_); 644 for(const Option_p &opt : parent->options_) { 645 if(opt.get() == this) { 646 continue; 647 } 648 auto &omatch = opt->matching_name(*this); 649 if(!omatch.empty()) { 650 ignore_underscore_ = false; 651 throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch); 652 } 653 } 654 } else { 655 ignore_underscore_ = value; 656 } 657 return this; 658 } 659 660 /// Take the last argument if given multiple times (or another policy) multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)661 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) { 662 if(value != multi_option_policy_) { 663 if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size && 664 expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility 665 // with the previous behavior of expected_ with vectors 666 expected_max_ = expected_min_; 667 } 668 multi_option_policy_ = value; 669 current_option_state_ = option_state::parsing; 670 } 671 return this; 672 } 673 674 /// Disable flag overrides values, e.g. --flag=<value> is not allowed disable_flag_override(bool value=true)675 Option *disable_flag_override(bool value = true) { 676 disable_flag_override_ = value; 677 return this; 678 } 679 ///@} 680 /// @name Accessors 681 ///@{ 682 683 /// The number of arguments the option expects get_type_size() const684 int get_type_size() const { return type_size_min_; } 685 686 /// The minimum number of arguments the option expects get_type_size_min() const687 int get_type_size_min() const { return type_size_min_; } 688 /// The maximum number of arguments the option expects get_type_size_max() const689 int get_type_size_max() const { return type_size_max_; } 690 691 /// Return the inject_separator flag get_inject_separator() const692 int get_inject_separator() const { return inject_separator_; } 693 694 /// The environment variable associated to this value get_envname() const695 std::string get_envname() const { return envname_; } 696 697 /// The set of options needed get_needs() const698 std::set<Option *> get_needs() const { return needs_; } 699 700 /// The set of options excluded get_excludes() const701 std::set<Option *> get_excludes() const { return excludes_; } 702 703 /// The default value (for help printing) get_default_str() const704 std::string get_default_str() const { return default_str_; } 705 706 /// Get the callback function get_callback() const707 callback_t get_callback() const { return callback_; } 708 709 /// Get the long names get_lnames() const710 const std::vector<std::string> &get_lnames() const { return lnames_; } 711 712 /// Get the short names get_snames() const713 const std::vector<std::string> &get_snames() const { return snames_; } 714 715 /// Get the flag names with specified default values get_fnames() const716 const std::vector<std::string> &get_fnames() const { return fnames_; } 717 /// Get a single name for the option, first of lname, pname, sname, envname get_single_name() const718 const std::string &get_single_name() const { 719 if(!lnames_.empty()) { 720 return lnames_[0]; 721 } 722 if(!pname_.empty()) { 723 return pname_; 724 } 725 if(!snames_.empty()) { 726 return snames_[0]; 727 } 728 return envname_; 729 } 730 /// The number of times the option expects to be included get_expected() const731 int get_expected() const { return expected_min_; } 732 733 /// The number of times the option expects to be included get_expected_min() const734 int get_expected_min() const { return expected_min_; } 735 /// The max number of times the option expects to be included get_expected_max() const736 int get_expected_max() const { return expected_max_; } 737 738 /// The total min number of expected string values to be used get_items_expected_min() const739 int get_items_expected_min() const { return type_size_min_ * expected_min_; } 740 741 /// Get the maximum number of items expected to be returned and used for the callback get_items_expected_max() const742 int get_items_expected_max() const { 743 int t = type_size_max_; 744 return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size; 745 } 746 /// The total min number of expected string values to be used get_items_expected() const747 int get_items_expected() const { return get_items_expected_min(); } 748 749 /// True if the argument can be given directly get_positional() const750 bool get_positional() const { return pname_.length() > 0; } 751 752 /// True if option has at least one non-positional name nonpositional() const753 bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; } 754 755 /// True if option has description has_description() const756 bool has_description() const { return description_.length() > 0; } 757 758 /// Get the description get_description() const759 const std::string &get_description() const { return description_; } 760 761 /// Set the description description(std::string option_description)762 Option *description(std::string option_description) { 763 description_ = std::move(option_description); 764 return this; 765 } 766 option_text(std::string text)767 Option *option_text(std::string text) { 768 option_text_ = std::move(text); 769 return this; 770 } 771 get_option_text() const772 const std::string &get_option_text() const { return option_text_; } 773 774 ///@} 775 /// @name Help tools 776 ///@{ 777 778 /// \brief Gets a comma separated list of names. 779 /// Will include / prefer the positional name if positional is true. 780 /// If all_options is false, pick just the most descriptive name to show. 781 /// Use `get_name(true)` to get the positional name (replaces `get_pname`) get_name(bool positional=false,bool all_options=false) const782 std::string get_name(bool positional = false, ///< Show the positional name 783 bool all_options = false ///< Show every option 784 ) const { 785 if(get_group().empty()) 786 return {}; // Hidden 787 788 if(all_options) { 789 790 std::vector<std::string> name_list; 791 792 /// The all list will never include a positional unless asked or that's the only name. 793 if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) { 794 name_list.push_back(pname_); 795 } 796 if((get_items_expected() == 0) && (!fnames_.empty())) { 797 for(const std::string &sname : snames_) { 798 name_list.push_back("-" + sname); 799 if(check_fname(sname)) { 800 name_list.back() += "{" + get_flag_value(sname, "") + "}"; 801 } 802 } 803 804 for(const std::string &lname : lnames_) { 805 name_list.push_back("--" + lname); 806 if(check_fname(lname)) { 807 name_list.back() += "{" + get_flag_value(lname, "") + "}"; 808 } 809 } 810 } else { 811 for(const std::string &sname : snames_) 812 name_list.push_back("-" + sname); 813 814 for(const std::string &lname : lnames_) 815 name_list.push_back("--" + lname); 816 } 817 818 return detail::join(name_list); 819 } 820 821 // This returns the positional name no matter what 822 if(positional) 823 return pname_; 824 825 // Prefer long name 826 if(!lnames_.empty()) 827 return std::string(2, '-') + lnames_[0]; 828 829 // Or short name if no long name 830 if(!snames_.empty()) 831 return std::string(1, '-') + snames_[0]; 832 833 // If positional is the only name, it's okay to use that 834 return pname_; 835 } 836 837 ///@} 838 /// @name Parser tools 839 ///@{ 840 841 /// Process the callback run_callback()842 void run_callback() { 843 if(force_callback_ && results_.empty()) { 844 add_result(default_str_); 845 } 846 if(current_option_state_ == option_state::parsing) { 847 _validate_results(results_); 848 current_option_state_ = option_state::validated; 849 } 850 851 if(current_option_state_ < option_state::reduced) { 852 _reduce_results(proc_results_, results_); 853 current_option_state_ = option_state::reduced; 854 } 855 if(current_option_state_ >= option_state::reduced) { 856 current_option_state_ = option_state::callback_run; 857 if(!(callback_)) { 858 return; 859 } 860 const results_t &send_results = proc_results_.empty() ? results_ : proc_results_; 861 bool local_result = callback_(send_results); 862 863 if(!local_result) 864 throw ConversionError(get_name(), results_); 865 } 866 } 867 868 /// If options share any of the same names, find it matching_name(const Option & other) const869 const std::string &matching_name(const Option &other) const { 870 static const std::string estring; 871 for(const std::string &sname : snames_) 872 if(other.check_sname(sname)) 873 return sname; 874 for(const std::string &lname : lnames_) 875 if(other.check_lname(lname)) 876 return lname; 877 878 if(ignore_case_ || 879 ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore 880 for(const std::string &sname : other.snames_) 881 if(check_sname(sname)) 882 return sname; 883 for(const std::string &lname : other.lnames_) 884 if(check_lname(lname)) 885 return lname; 886 } 887 return estring; 888 } 889 /// If options share any of the same names, they are equal (not counting positional) operator ==(const Option & other) const890 bool operator==(const Option &other) const { return !matching_name(other).empty(); } 891 892 /// Check a name. Requires "-" or "--" for short / long, supports positional name check_name(const std::string & name) const893 bool check_name(const std::string &name) const { 894 895 if(name.length() > 2 && name[0] == '-' && name[1] == '-') 896 return check_lname(name.substr(2)); 897 if(name.length() > 1 && name.front() == '-') 898 return check_sname(name.substr(1)); 899 if(!pname_.empty()) { 900 std::string local_pname = pname_; 901 std::string local_name = name; 902 if(ignore_underscore_) { 903 local_pname = detail::remove_underscore(local_pname); 904 local_name = detail::remove_underscore(local_name); 905 } 906 if(ignore_case_) { 907 local_pname = detail::to_lower(local_pname); 908 local_name = detail::to_lower(local_name); 909 } 910 if(local_name == local_pname) { 911 return true; 912 } 913 } 914 915 if(!envname_.empty()) { 916 // this needs to be the original since envname_ shouldn't match on case insensitivity 917 return (name == envname_); 918 } 919 return false; 920 } 921 922 /// Requires "-" to be removed from string check_sname(std::string name) const923 bool check_sname(std::string name) const { 924 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0); 925 } 926 927 /// Requires "--" to be removed from string check_lname(std::string name) const928 bool check_lname(std::string name) const { 929 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0); 930 } 931 932 /// Requires "--" to be removed from string check_fname(std::string name) const933 bool check_fname(std::string name) const { 934 if(fnames_.empty()) { 935 return false; 936 } 937 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0); 938 } 939 940 /// Get the value that goes for a flag, nominally gets the default value but allows for overrides if not 941 /// disabled get_flag_value(const std::string & name,std::string input_value) const942 std::string get_flag_value(const std::string &name, std::string input_value) const { 943 static const std::string trueString{"true"}; 944 static const std::string falseString{"false"}; 945 static const std::string emptyString{"{}"}; 946 // check for disable flag override_ 947 if(disable_flag_override_) { 948 if(!((input_value.empty()) || (input_value == emptyString))) { 949 auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_); 950 if(default_ind >= 0) { 951 // We can static cast this to std::size_t because it is more than 0 in this block 952 if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) { 953 throw(ArgumentMismatch::FlagOverride(name)); 954 } 955 } else { 956 if(input_value != trueString) { 957 throw(ArgumentMismatch::FlagOverride(name)); 958 } 959 } 960 } 961 } 962 auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_); 963 if((input_value.empty()) || (input_value == emptyString)) { 964 if(flag_like_) { 965 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second; 966 } else { 967 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second; 968 } 969 } 970 if(ind < 0) { 971 return input_value; 972 } 973 if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) { 974 try { 975 auto val = detail::to_flag_value(input_value); 976 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val)); 977 } catch(const std::invalid_argument &) { 978 return input_value; 979 } 980 } else { 981 return input_value; 982 } 983 } 984 985 /// Puts a result at the end add_result(std::string s)986 Option *add_result(std::string s) { 987 _add_result(std::move(s), results_); 988 current_option_state_ = option_state::parsing; 989 return this; 990 } 991 992 /// Puts a result at the end and get a count of the number of arguments actually added add_result(std::string s,int & results_added)993 Option *add_result(std::string s, int &results_added) { 994 results_added = _add_result(std::move(s), results_); 995 current_option_state_ = option_state::parsing; 996 return this; 997 } 998 999 /// Puts a result at the end add_result(std::vector<std::string> s)1000 Option *add_result(std::vector<std::string> s) { 1001 current_option_state_ = option_state::parsing; 1002 for(auto &str : s) { 1003 _add_result(std::move(str), results_); 1004 } 1005 return this; 1006 } 1007 1008 /// Get the current complete results set results() const1009 const results_t &results() const { return results_; } 1010 1011 /// Get a copy of the results reduced_results() const1012 results_t reduced_results() const { 1013 results_t res = proc_results_.empty() ? results_ : proc_results_; 1014 if(current_option_state_ < option_state::reduced) { 1015 if(current_option_state_ == option_state::parsing) { 1016 res = results_; 1017 _validate_results(res); 1018 } 1019 if(!res.empty()) { 1020 results_t extra; 1021 _reduce_results(extra, res); 1022 if(!extra.empty()) { 1023 res = std::move(extra); 1024 } 1025 } 1026 } 1027 return res; 1028 } 1029 1030 /// Get the results as a specified type results(T & output) const1031 template <typename T> void results(T &output) const { 1032 bool retval; 1033 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) { 1034 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_; 1035 retval = detail::lexical_conversion<T, T>(res, output); 1036 } else { 1037 results_t res; 1038 if(results_.empty()) { 1039 if(!default_str_.empty()) { 1040 // _add_results takes an rvalue only 1041 _add_result(std::string(default_str_), res); 1042 _validate_results(res); 1043 results_t extra; 1044 _reduce_results(extra, res); 1045 if(!extra.empty()) { 1046 res = std::move(extra); 1047 } 1048 } else { 1049 res.emplace_back(); 1050 } 1051 } else { 1052 res = reduced_results(); 1053 } 1054 retval = detail::lexical_conversion<T, T>(res, output); 1055 } 1056 if(!retval) { 1057 throw ConversionError(get_name(), results_); 1058 } 1059 } 1060 1061 /// Return the results as the specified type as() const1062 template <typename T> T as() const { 1063 T output; 1064 results(output); 1065 return output; 1066 } 1067 1068 /// See if the callback has been run already get_callback_run() const1069 bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); } 1070 1071 ///@} 1072 /// @name Custom options 1073 ///@{ 1074 1075 /// Set the type function to run when displayed on this option type_name_fn(std::function<std::string ()> typefun)1076 Option *type_name_fn(std::function<std::string()> typefun) { 1077 type_name_ = std::move(typefun); 1078 return this; 1079 } 1080 1081 /// Set a custom option typestring type_name(std::string typeval)1082 Option *type_name(std::string typeval) { 1083 type_name_fn([typeval]() { return typeval; }); 1084 return this; 1085 } 1086 1087 /// Set a custom option size type_size(int option_type_size)1088 Option *type_size(int option_type_size) { 1089 if(option_type_size < 0) { 1090 // this section is included for backwards compatibility 1091 type_size_max_ = -option_type_size; 1092 type_size_min_ = -option_type_size; 1093 expected_max_ = detail::expected_max_vector_size; 1094 } else { 1095 type_size_max_ = option_type_size; 1096 if(type_size_max_ < detail::expected_max_vector_size) { 1097 type_size_min_ = option_type_size; 1098 } else { 1099 inject_separator_ = true; 1100 } 1101 if(type_size_max_ == 0) 1102 required_ = false; 1103 } 1104 return this; 1105 } 1106 /// Set a custom option type size range type_size(int option_type_size_min,int option_type_size_max)1107 Option *type_size(int option_type_size_min, int option_type_size_max) { 1108 if(option_type_size_min < 0 || option_type_size_max < 0) { 1109 // this section is included for backwards compatibility 1110 expected_max_ = detail::expected_max_vector_size; 1111 option_type_size_min = (std::abs)(option_type_size_min); 1112 option_type_size_max = (std::abs)(option_type_size_max); 1113 } 1114 1115 if(option_type_size_min > option_type_size_max) { 1116 type_size_max_ = option_type_size_min; 1117 type_size_min_ = option_type_size_max; 1118 } else { 1119 type_size_min_ = option_type_size_min; 1120 type_size_max_ = option_type_size_max; 1121 } 1122 if(type_size_max_ == 0) { 1123 required_ = false; 1124 } 1125 if(type_size_max_ >= detail::expected_max_vector_size) { 1126 inject_separator_ = true; 1127 } 1128 return this; 1129 } 1130 1131 /// Set the value of the separator injection flag inject_separator(bool value=true)1132 void inject_separator(bool value = true) { inject_separator_ = value; } 1133 1134 /// Set a capture function for the default. Mostly used by App. default_function(const std::function<std::string ()> & func)1135 Option *default_function(const std::function<std::string()> &func) { 1136 default_function_ = func; 1137 return this; 1138 } 1139 1140 /// Capture the default value from the original value (if it can be captured) capture_default_str()1141 Option *capture_default_str() { 1142 if(default_function_) { 1143 default_str_ = default_function_(); 1144 } 1145 return this; 1146 } 1147 1148 /// Set the default value string representation (does not change the contained value) default_str(std::string val)1149 Option *default_str(std::string val) { 1150 default_str_ = std::move(val); 1151 return this; 1152 } 1153 1154 /// Set the default value and validate the results and run the callback if appropriate to set the value into the 1155 /// bound value only available for types that can be converted to a string default_val(const X & val)1156 template <typename X> Option *default_val(const X &val) { 1157 std::string val_str = detail::to_string(val); 1158 auto old_option_state = current_option_state_; 1159 results_t old_results{std::move(results_)}; 1160 results_.clear(); 1161 try { 1162 add_result(val_str); 1163 // if trigger_on_result_ is set the callback already ran 1164 if(run_callback_for_default_ && !trigger_on_result_) { 1165 run_callback(); // run callback sets the state we need to reset it again 1166 current_option_state_ = option_state::parsing; 1167 } else { 1168 _validate_results(results_); 1169 current_option_state_ = old_option_state; 1170 } 1171 } catch(const CLI::Error &) { 1172 // this should be done 1173 results_ = std::move(old_results); 1174 current_option_state_ = old_option_state; 1175 throw; 1176 } 1177 results_ = std::move(old_results); 1178 default_str_ = std::move(val_str); 1179 return this; 1180 } 1181 1182 /// Get the full typename for this option get_type_name() const1183 std::string get_type_name() const { 1184 std::string full_type_name = type_name_(); 1185 if(!validators_.empty()) { 1186 for(auto &Validator : validators_) { 1187 std::string vtype = Validator.get_description(); 1188 if(!vtype.empty()) { 1189 full_type_name += ":" + vtype; 1190 } 1191 } 1192 } 1193 return full_type_name; 1194 } 1195 1196 private: 1197 /// Run the results through the Validators _validate_results(results_t & res) const1198 void _validate_results(results_t &res) const { 1199 // Run the Validators (can change the string) 1200 if(!validators_.empty()) { 1201 if(type_size_max_ > 1) { // in this context index refers to the index in the type 1202 int index = 0; 1203 if(get_items_expected_max() < static_cast<int>(res.size()) && 1204 multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) { 1205 // create a negative index for the earliest ones 1206 index = get_items_expected_max() - static_cast<int>(res.size()); 1207 } 1208 1209 for(std::string &result : res) { 1210 if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) { 1211 index = 0; // reset index for variable size chunks 1212 continue; 1213 } 1214 auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index); 1215 if(!err_msg.empty()) 1216 throw ValidationError(get_name(), err_msg); 1217 ++index; 1218 } 1219 } else { 1220 int index = 0; 1221 if(expected_max_ < static_cast<int>(res.size()) && 1222 multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) { 1223 // create a negative index for the earliest ones 1224 index = expected_max_ - static_cast<int>(res.size()); 1225 } 1226 for(std::string &result : res) { 1227 auto err_msg = _validate(result, index); 1228 ++index; 1229 if(!err_msg.empty()) 1230 throw ValidationError(get_name(), err_msg); 1231 } 1232 } 1233 } 1234 } 1235 1236 /** reduce the results in accordance with the MultiOptionPolicy 1237 @param[out] res results are assigned to res if there if they are different 1238 */ _reduce_results(results_t & res,const results_t & original) const1239 void _reduce_results(results_t &res, const results_t &original) const { 1240 1241 // max num items expected or length of vector, always at least 1 1242 // Only valid for a trimming policy 1243 1244 res.clear(); 1245 // Operation depends on the policy setting 1246 switch(multi_option_policy_) { 1247 case MultiOptionPolicy::TakeAll: 1248 break; 1249 case MultiOptionPolicy::TakeLast: { 1250 // Allow multi-option sizes (including 0) 1251 std::size_t trim_size = std::min<std::size_t>( 1252 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size()); 1253 if(original.size() != trim_size) { 1254 res.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end()); 1255 } 1256 } break; 1257 case MultiOptionPolicy::TakeFirst: { 1258 std::size_t trim_size = std::min<std::size_t>( 1259 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size()); 1260 if(original.size() != trim_size) { 1261 res.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size)); 1262 } 1263 } break; 1264 case MultiOptionPolicy::Join: 1265 if(results_.size() > 1) { 1266 res.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_))); 1267 } 1268 break; 1269 case MultiOptionPolicy::Throw: 1270 default: { 1271 auto num_min = static_cast<std::size_t>(get_items_expected_min()); 1272 auto num_max = static_cast<std::size_t>(get_items_expected_max()); 1273 if(num_min == 0) { 1274 num_min = 1; 1275 } 1276 if(num_max == 0) { 1277 num_max = 1; 1278 } 1279 if(original.size() < num_min) { 1280 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size()); 1281 } 1282 if(original.size() > num_max) { 1283 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size()); 1284 } 1285 break; 1286 } 1287 } 1288 } 1289 1290 // Run a result through the Validators _validate(std::string & result,int index) const1291 std::string _validate(std::string &result, int index) const { 1292 std::string err_msg; 1293 if(result.empty() && expected_min_ == 0) { 1294 // an empty with nothing expected is allowed 1295 return err_msg; 1296 } 1297 for(const auto &vali : validators_) { 1298 auto v = vali.get_application_index(); 1299 if(v == -1 || v == index) { 1300 try { 1301 err_msg = vali(result); 1302 } catch(const ValidationError &err) { 1303 err_msg = err.what(); 1304 } 1305 if(!err_msg.empty()) 1306 break; 1307 } 1308 } 1309 1310 return err_msg; 1311 } 1312 1313 /// Add a single result to the result set, taking into account delimiters _add_result(std::string && result,std::vector<std::string> & res) const1314 int _add_result(std::string &&result, std::vector<std::string> &res) const { 1315 int result_count = 0; 1316 if(allow_extra_args_ && !result.empty() && result.front() == '[' && 1317 result.back() == ']') { // this is now a vector string likely from the default or user entry 1318 result.pop_back(); 1319 1320 for(auto &var : CLI::detail::split(result.substr(1), ',')) { 1321 if(!var.empty()) { 1322 result_count += _add_result(std::move(var), res); 1323 } 1324 } 1325 return result_count; 1326 } 1327 if(delimiter_ == '\0') { 1328 res.push_back(std::move(result)); 1329 ++result_count; 1330 } else { 1331 if((result.find_first_of(delimiter_) != std::string::npos)) { 1332 for(const auto &var : CLI::detail::split(result, delimiter_)) { 1333 if(!var.empty()) { 1334 res.push_back(var); 1335 ++result_count; 1336 } 1337 } 1338 } else { 1339 res.push_back(std::move(result)); 1340 ++result_count; 1341 } 1342 } 1343 return result_count; 1344 } 1345 }; // namespace CLI 1346 1347 // [CLI11:option_hpp:end] 1348 } // namespace CLI 1349