Commit b56ae237e5750c94182cf6b29cca9ccc491866de

Authored by Daniel Herrera Castro
Committed by Henry Schreiner
1 parent c57000e5

[precompiled] Initial proof-of-concept with App.cpp

- Add C11_COMPILE cmake option that creates a static lib instead of header-only
- Add C11_INLINE macro that depends on C11_COMPILE
- Split App.hpp into App.hpp and impl/App_inl.hpp
- Add App.cpp that compiles App_inl.hpp into an object file
- CMake modifications to handle impl headers differently for sinlge-header, headers-only, and compiled versions
CLI11.hpp.in
@@ -62,6 +62,8 @@ namespace {namespace} {{ @@ -62,6 +62,8 @@ namespace {namespace} {{
62 62
63 {app_hpp} 63 {app_hpp}
64 64
  65 +{app_inl_hpp}
  66 +
65 {config_hpp} 67 {config_hpp}
66 68
67 {formatter_hpp} 69 {formatter_hpp}
CMakeLists.txt
@@ -77,6 +77,7 @@ endif() @@ -77,6 +77,7 @@ endif()
77 77
78 option(CLI11_WARNINGS_AS_ERRORS "Turn all warnings into errors (for CI)") 78 option(CLI11_WARNINGS_AS_ERRORS "Turn all warnings into errors (for CI)")
79 option(CLI11_SINGLE_FILE "Generate a single header file") 79 option(CLI11_SINGLE_FILE "Generate a single header file")
  80 +option(CLI11_PRECOMPILED "Generate a precompiled static library instead of a header-only")
80 cmake_dependent_option(CLI11_SANITIZERS "Download the sanitizers CMake config" OFF 81 cmake_dependent_option(CLI11_SANITIZERS "Download the sanitizers CMake config" OFF
81 "NOT CMAKE_VERSION VERSION_LESS 3.11" OFF) 82 "NOT CMAKE_VERSION VERSION_LESS 3.11" OFF)
82 83
@@ -105,6 +106,11 @@ cmake_dependent_option( @@ -105,6 +106,11 @@ cmake_dependent_option(
105 CLI11_CUDA_TESTS "Build the tests with NVCC to check for warnings there - requires CMake 3.9+" 106 CLI11_CUDA_TESTS "Build the tests with NVCC to check for warnings there - requires CMake 3.9+"
106 OFF "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME" OFF) 107 OFF "CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME" OFF)
107 108
  109 +if(CLI11_PRECOMPILED AND CLI11_SINGLE_FILE)
  110 + # Sanity check
  111 + message(FATAL_ERROR "CLI11_PRECOMPILE and CLI11_SINGLE_FILE are mutually exclusive")
  112 +endif()
  113 +
108 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND NOT DEFINED CMAKE_CXX_STANDARD) 114 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND NOT DEFINED CMAKE_CXX_STANDARD)
109 set(CMAKE_CXX_STANDARD 11) 115 set(CMAKE_CXX_STANDARD 11)
110 endif() 116 endif()
@@ -160,13 +166,35 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.13) @@ -160,13 +166,35 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.13)
160 target_link_options(CLI11_warnings INTERFACE $<$<BOOL:${CLI11_FORCE_LIBCXX}>:-stdlib=libc++>) 166 target_link_options(CLI11_warnings INTERFACE $<$<BOOL:${CLI11_FORCE_LIBCXX}>:-stdlib=libc++>)
161 endif() 167 endif()
162 168
  169 +# To see in IDE, headers must be listed for target
  170 +set(MAYBE_CONFIGURE_DEPENDS "")
  171 +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND NOT CMAKE_VERSION VERSION_LESS 3.12)
  172 + list(INSERT MAYBE_CONFIGURE_DEPENDS 0 CONFIGURE_DEPENDS)
  173 +endif()
  174 +
  175 +file(GLOB CLI11_headers ${MAYBE_CONFIGURE_DEPENDS} "${PROJECT_SOURCE_DIR}/include/CLI/*.hpp")
  176 +file(GLOB CLI11_impl_headers ${MAYBE_CONFIGURE_DEPENDS}
  177 + "${PROJECT_SOURCE_DIR}/include/CLI/impl/*.hpp")
  178 +
  179 +if(CLI11_PRECOMPILED)
  180 + # Create static lib
  181 + file(GLOB CLI11_precompile_sources "${PROJECT_SOURCE_DIR}/src/*.cpp")
  182 + add_library(CLI11 STATIC ${CLI11_headers} ${CLI11_impl_headers} ${CLI11_precompile_sources})
  183 + target_compile_definitions(CLI11 PUBLIC -DCLI11_COMPILE)
  184 +
  185 + set(PUBLIC_OR_INTERFACE PUBLIC)
  186 +else()
  187 + add_library(CLI11 INTERFACE)
  188 + set(PUBLIC_OR_INTERFACE INTERFACE)
  189 +endif()
  190 +
163 # Allow IDE's to group targets into folders 191 # Allow IDE's to group targets into folders
164 -add_library(CLI11 INTERFACE)  
165 add_library(CLI11::CLI11 ALIAS CLI11) # for add_subdirectory calls 192 add_library(CLI11::CLI11 ALIAS CLI11) # for add_subdirectory calls
166 193
167 # Duplicated because CMake adds the current source dir if you don't. 194 # Duplicated because CMake adds the current source dir if you don't.
168 -target_include_directories(CLI11 INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>  
169 - $<INSTALL_INTERFACE:include>) 195 +target_include_directories(
  196 + CLI11 ${PUBLIC_OR_INTERFACE} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  197 + $<INSTALL_INTERFACE:include>)
170 198
171 if(CMAKE_VERSION VERSION_LESS 3.8) 199 if(CMAKE_VERSION VERSION_LESS 3.8)
172 # This might not be a complete list 200 # This might not be a complete list
@@ -184,14 +212,6 @@ else() @@ -184,14 +212,6 @@ else()
184 target_compile_features(CLI11 INTERFACE cxx_std_11) 212 target_compile_features(CLI11 INTERFACE cxx_std_11)
185 endif() 213 endif()
186 214
187 -# To see in IDE, headers must be listed for target  
188 -set(header-patterns "${PROJECT_SOURCE_DIR}/include/CLI/*")  
189 -if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND NOT CMAKE_VERSION VERSION_LESS 3.12)  
190 - list(INSERT header-patterns 0 CONFIGURE_DEPENDS)  
191 -endif()  
192 -  
193 -file(GLOB CLI11_headers ${header-patterns})  
194 -  
195 # Allow tests to be run on CUDA 215 # Allow tests to be run on CUDA
196 if(CLI11_CUDA_TESTS) 216 if(CLI11_CUDA_TESTS)
197 enable_language(CUDA) 217 enable_language(CUDA)
@@ -202,7 +222,10 @@ endif() @@ -202,7 +222,10 @@ endif()
202 222
203 # This folder should be installed 223 # This folder should be installed
204 if(CLI11_INSTALL) 224 if(CLI11_INSTALL)
205 - install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") 225 + install(FILES ${CLI11_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CLI")
  226 + if(NOT CLI11_COMPILE)
  227 + install(FILES ${CLI11_impl_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CLI/impl")
  228 + endif()
206 229
207 # Make an export target 230 # Make an export target
208 install(TARGETS CLI11 EXPORT CLI11Targets) 231 install(TARGETS CLI11 EXPORT CLI11Targets)
@@ -257,9 +280,10 @@ if(CLI11_SINGLE_FILE) @@ -257,9 +280,10 @@ if(CLI11_SINGLE_FILE)
257 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" 280 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
258 COMMAND 281 COMMAND
259 Python::Interpreter "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" 282 Python::Interpreter "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py"
260 - ${CLI11_headers} --main "${CMAKE_CURRENT_SOURCE_DIR}/CLI11.hpp.in" --output  
261 - "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" --version "${CLI11_VERSION}"  
262 - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI11_headers}) 283 + ${CLI11_headers} ${CLI11_impl_headers} --main "${CMAKE_CURRENT_SOURCE_DIR}/CLI11.hpp.in"
  284 + --output "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" --version "${CLI11_VERSION}"
  285 + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI11_headers}
  286 + ${CLI11_impl_headers})
263 add_custom_target(CLI11-generate-single-file ALL 287 add_custom_target(CLI11-generate-single-file ALL
264 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp") 288 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp")
265 set_property(TARGET CLI11-generate-single-file PROPERTY FOLDER "Scripts") 289 set_property(TARGET CLI11-generate-single-file PROPERTY FOLDER "Scripts")
include/CLI/App.hpp
@@ -282,39 +282,7 @@ class App { @@ -282,39 +282,7 @@ class App {
282 ///@} 282 ///@}
283 283
284 /// Special private constructor for subcommand 284 /// Special private constructor for subcommand
285 - App(std::string app_description, std::string app_name, App *parent)  
286 - : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {  
287 - // Inherit if not from a nullptr  
288 - if(parent_ != nullptr) {  
289 - if(parent_->help_ptr_ != nullptr)  
290 - set_help_flag(parent_->help_ptr_->get_name(false, true), parent_->help_ptr_->get_description());  
291 - if(parent_->help_all_ptr_ != nullptr)  
292 - set_help_all_flag(parent_->help_all_ptr_->get_name(false, true),  
293 - parent_->help_all_ptr_->get_description());  
294 -  
295 - /// OptionDefaults  
296 - option_defaults_ = parent_->option_defaults_;  
297 -  
298 - // INHERITABLE  
299 - failure_message_ = parent_->failure_message_;  
300 - allow_extras_ = parent_->allow_extras_;  
301 - allow_config_extras_ = parent_->allow_config_extras_;  
302 - prefix_command_ = parent_->prefix_command_;  
303 - immediate_callback_ = parent_->immediate_callback_;  
304 - ignore_case_ = parent_->ignore_case_;  
305 - ignore_underscore_ = parent_->ignore_underscore_;  
306 - fallthrough_ = parent_->fallthrough_;  
307 - validate_positionals_ = parent_->validate_positionals_;  
308 - validate_optional_arguments_ = parent_->validate_optional_arguments_;  
309 - configurable_ = parent_->configurable_;  
310 - allow_windows_style_options_ = parent_->allow_windows_style_options_;  
311 - group_ = parent_->group_;  
312 - footer_ = parent_->footer_;  
313 - formatter_ = parent_->formatter_;  
314 - config_formatter_ = parent_->config_formatter_;  
315 - require_subcommand_max_ = parent_->require_subcommand_max_;  
316 - }  
317 - } 285 + App(std::string app_description, std::string app_name, App *parent);
318 286
319 public: 287 public:
320 /// @name Basic 288 /// @name Basic
@@ -369,41 +337,10 @@ class App { @@ -369,41 +337,10 @@ class App {
369 } 337 }
370 338
371 /// Set a name for the app (empty will use parser to set the name) 339 /// Set a name for the app (empty will use parser to set the name)
372 - App *name(std::string app_name = "") {  
373 -  
374 - if(parent_ != nullptr) {  
375 - auto oname = name_;  
376 - name_ = app_name;  
377 - const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());  
378 - if(!res.empty()) {  
379 - name_ = oname;  
380 - throw(OptionAlreadyAdded(app_name + " conflicts with existing subcommand names"));  
381 - }  
382 - } else {  
383 - name_ = app_name;  
384 - }  
385 - has_automatic_name_ = false;  
386 - return this;  
387 - } 340 + App *name(std::string app_name = "");
388 341
389 /// Set an alias for the app 342 /// Set an alias for the app
390 - App *alias(std::string app_name) {  
391 - if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {  
392 - throw IncorrectConstruction("Aliases may not be empty or contain newlines or null characters");  
393 - }  
394 - if(parent_ != nullptr) {  
395 - aliases_.push_back(app_name);  
396 - const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());  
397 - if(!res.empty()) {  
398 - aliases_.pop_back();  
399 - throw(OptionAlreadyAdded("alias already matches an existing subcommand: " + app_name));  
400 - }  
401 - } else {  
402 - aliases_.push_back(app_name);  
403 - }  
404 -  
405 - return this;  
406 - } 343 + App *alias(std::string app_name);
407 344
408 /// Remove the error when extras are left over on the command line. 345 /// Remove the error when extras are left over on the command line.
409 App *allow_extras(bool allow = true) { 346 App *allow_extras(bool allow = true) {
@@ -452,17 +389,7 @@ class App { @@ -452,17 +389,7 @@ class App {
452 } 389 }
453 390
454 /// Set the subcommand callback to be executed immediately on subcommand completion 391 /// Set the subcommand callback to be executed immediately on subcommand completion
455 - App *immediate_callback(bool immediate = true) {  
456 - immediate_callback_ = immediate;  
457 - if(immediate_callback_) {  
458 - if(final_callback_ && !(parse_complete_callback_)) {  
459 - std::swap(final_callback_, parse_complete_callback_);  
460 - }  
461 - } else if(!(final_callback_) && parse_complete_callback_) {  
462 - std::swap(final_callback_, parse_complete_callback_);  
463 - }  
464 - return this;  
465 - } 392 + App *immediate_callback(bool immediate = true);
466 393
467 /// Set the subcommand to validate positional arguments before assigning 394 /// Set the subcommand to validate positional arguments before assigning
468 App *validate_positionals(bool validate = true) { 395 App *validate_positionals(bool validate = true) {
@@ -500,19 +427,7 @@ class App { @@ -500,19 +427,7 @@ class App {
500 } 427 }
501 428
502 /// Ignore case. Subcommands inherit value. 429 /// Ignore case. Subcommands inherit value.
503 - App *ignore_case(bool value = true) {  
504 - if(value && !ignore_case_) {  
505 - ignore_case_ = true;  
506 - auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;  
507 - const auto &match = _compare_subcommand_names(*this, *p);  
508 - if(!match.empty()) {  
509 - ignore_case_ = false; // we are throwing so need to be exception invariant  
510 - throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);  
511 - }  
512 - }  
513 - ignore_case_ = value;  
514 - return this;  
515 - } 430 + App *ignore_case(bool value = true);
516 431
517 /// Allow windows style options, such as `/opt`. First matching short or long name used. Subcommands inherit 432 /// Allow windows style options, such as `/opt`. First matching short or long name used. Subcommands inherit
518 /// value. 433 /// value.
@@ -534,19 +449,7 @@ class App { @@ -534,19 +449,7 @@ class App {
534 } 449 }
535 450
536 /// Ignore underscore. Subcommands inherit value. 451 /// Ignore underscore. Subcommands inherit value.
537 - App *ignore_underscore(bool value = true) {  
538 - if(value && !ignore_underscore_) {  
539 - ignore_underscore_ = true;  
540 - auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;  
541 - const auto &match = _compare_subcommand_names(*this, *p);  
542 - if(!match.empty()) {  
543 - ignore_underscore_ = false;  
544 - throw OptionAlreadyAdded("ignore underscore would cause subcommand name conflicts: " + match);  
545 - }  
546 - }  
547 - ignore_underscore_ = value;  
548 - return this;  
549 - } 452 + App *ignore_underscore(bool value = true);
550 453
551 /// Set the help formatter 454 /// Set the help formatter
552 App *formatter(std::shared_ptr<FormatterBase> fmt) { 455 App *formatter(std::shared_ptr<FormatterBase> fmt) {
@@ -594,42 +497,7 @@ class App { @@ -594,42 +497,7 @@ class App {
594 callback_t option_callback, 497 callback_t option_callback,
595 std::string option_description = "", 498 std::string option_description = "",
596 bool defaulted = false, 499 bool defaulted = false,
597 - std::function<std::string()> func = {}) {  
598 - Option myopt{option_name, option_description, option_callback, this};  
599 -  
600 - if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) {  
601 - return *v == myopt;  
602 - }) == std::end(options_)) {  
603 - options_.emplace_back();  
604 - Option_p &option = options_.back();  
605 - option.reset(new Option(option_name, option_description, option_callback, this));  
606 -  
607 - // Set the default string capture function  
608 - option->default_function(func);  
609 -  
610 - // For compatibility with CLI11 1.7 and before, capture the default string here  
611 - if(defaulted)  
612 - option->capture_default_str();  
613 -  
614 - // Transfer defaults to the new option  
615 - option_defaults_.copy_to(option.get());  
616 -  
617 - // Don't bother to capture if we already did  
618 - if(!defaulted && option->get_always_capture_default())  
619 - option->capture_default_str();  
620 -  
621 - return option.get();  
622 - }  
623 - // we know something matches now find what it is so we can produce more error information  
624 - for(auto &opt : options_) {  
625 - const auto &matchname = opt->matching_name(myopt);  
626 - if(!matchname.empty()) {  
627 - throw(OptionAlreadyAdded("added option matched existing option name: " + matchname));  
628 - }  
629 - }  
630 - // this line should not be reached the above loop should trigger the throw  
631 - throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE  
632 - } 500 + std::function<std::string()> func = {});
633 501
634 /// Add option for assigning to a variable 502 /// Add option for assigning to a variable
635 template <typename AssignTo, 503 template <typename AssignTo,
@@ -711,103 +579,24 @@ class App { @@ -711,103 +579,24 @@ class App {
711 } 579 }
712 580
713 /// Set a help flag, replace the existing one if present 581 /// Set a help flag, replace the existing one if present
714 - Option *set_help_flag(std::string flag_name = "", const std::string &help_description = "") {  
715 - // take flag_description by const reference otherwise add_flag tries to assign to help_description  
716 - if(help_ptr_ != nullptr) {  
717 - remove_option(help_ptr_);  
718 - help_ptr_ = nullptr;  
719 - }  
720 -  
721 - // Empty name will simply remove the help flag  
722 - if(!flag_name.empty()) {  
723 - help_ptr_ = add_flag(flag_name, help_description);  
724 - help_ptr_->configurable(false);  
725 - }  
726 -  
727 - return help_ptr_;  
728 - } 582 + Option *set_help_flag(std::string flag_name = "", const std::string &help_description = "");
729 583
730 /// Set a help all flag, replaced the existing one if present 584 /// Set a help all flag, replaced the existing one if present
731 - Option *set_help_all_flag(std::string help_name = "", const std::string &help_description = "") {  
732 - // take flag_description by const reference otherwise add_flag tries to assign to flag_description  
733 - if(help_all_ptr_ != nullptr) {  
734 - remove_option(help_all_ptr_);  
735 - help_all_ptr_ = nullptr;  
736 - }  
737 -  
738 - // Empty name will simply remove the help all flag  
739 - if(!help_name.empty()) {  
740 - help_all_ptr_ = add_flag(help_name, help_description);  
741 - help_all_ptr_->configurable(false);  
742 - }  
743 -  
744 - return help_all_ptr_;  
745 - } 585 + Option *set_help_all_flag(std::string help_name = "", const std::string &help_description = "");
746 586
747 /// Set a version flag and version display string, replace the existing one if present 587 /// Set a version flag and version display string, replace the existing one if present
748 Option *set_version_flag(std::string flag_name = "", 588 Option *set_version_flag(std::string flag_name = "",
749 const std::string &versionString = "", 589 const std::string &versionString = "",
750 - const std::string &version_help = "Display program version information and exit") {  
751 - // take flag_description by const reference otherwise add_flag tries to assign to version_description  
752 - if(version_ptr_ != nullptr) {  
753 - remove_option(version_ptr_);  
754 - version_ptr_ = nullptr;  
755 - } 590 + const std::string &version_help = "Display program version information and exit");
756 591
757 - // Empty name will simply remove the version flag  
758 - if(!flag_name.empty()) {  
759 - version_ptr_ = add_flag_callback(  
760 - flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);  
761 - version_ptr_->configurable(false);  
762 - }  
763 -  
764 - return version_ptr_;  
765 - }  
766 /// Generate the version string through a callback function 592 /// Generate the version string through a callback function
767 Option *set_version_flag(std::string flag_name, 593 Option *set_version_flag(std::string flag_name,
768 std::function<std::string()> vfunc, 594 std::function<std::string()> vfunc,
769 - const std::string &version_help = "Display program version information and exit") {  
770 - if(version_ptr_ != nullptr) {  
771 - remove_option(version_ptr_);  
772 - version_ptr_ = nullptr;  
773 - }  
774 -  
775 - // Empty name will simply remove the version flag  
776 - if(!flag_name.empty()) {  
777 - version_ptr_ = add_flag_callback(  
778 - flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);  
779 - version_ptr_->configurable(false);  
780 - }  
781 -  
782 - return version_ptr_;  
783 - } 595 + const std::string &version_help = "Display program version information and exit");
784 596
785 private: 597 private:
786 /// Internal function for adding a flag 598 /// Internal function for adding a flag
787 - Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {  
788 - Option *opt = nullptr;  
789 - if(detail::has_default_flag_values(flag_name)) {  
790 - // check for default values and if it has them  
791 - auto flag_defaults = detail::get_default_flag_values(flag_name);  
792 - detail::remove_default_flag_values(flag_name);  
793 - opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);  
794 - for(const auto &fname : flag_defaults)  
795 - opt->fnames_.push_back(fname.first);  
796 - opt->default_flag_values_ = std::move(flag_defaults);  
797 - } else {  
798 - opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);  
799 - }  
800 - // flags cannot have positional values  
801 - if(opt->get_positional()) {  
802 - auto pos_name = opt->get_name(true);  
803 - remove_option(opt);  
804 - throw IncorrectConstruction::PositionalFlag(pos_name);  
805 - }  
806 - opt->multi_option_policy(MultiOptionPolicy::TakeLast);  
807 - opt->expected(0);  
808 - opt->required(false);  
809 - return opt;  
810 - } 599 + Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description);
811 600
812 public: 601 public:
813 /// Add a flag with no description or variable assignment 602 /// Add a flag with no description or variable assignment
@@ -863,33 +652,12 @@ class App { @@ -863,33 +652,12 @@ class App {
863 /// Add option for callback that is triggered with a true flag and takes no arguments 652 /// Add option for callback that is triggered with a true flag and takes no arguments
864 Option *add_flag_callback(std::string flag_name, 653 Option *add_flag_callback(std::string flag_name,
865 std::function<void(void)> function, ///< A function to call, void(void) 654 std::function<void(void)> function, ///< A function to call, void(void)
866 - std::string flag_description = "") {  
867 -  
868 - CLI::callback_t fun = [function](const CLI::results_t &res) {  
869 - bool trigger{false};  
870 - auto result = CLI::detail::lexical_cast(res[0], trigger);  
871 - if(result && trigger) {  
872 - function();  
873 - }  
874 - return result;  
875 - };  
876 - return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));  
877 - } 655 + std::string flag_description = "");
878 656
879 /// Add option for callback with an integer value 657 /// Add option for callback with an integer value
880 Option *add_flag_function(std::string flag_name, 658 Option *add_flag_function(std::string flag_name,
881 std::function<void(std::int64_t)> function, ///< A function to call, void(int) 659 std::function<void(std::int64_t)> function, ///< A function to call, void(int)
882 - std::string flag_description = "") {  
883 -  
884 - CLI::callback_t fun = [function](const CLI::results_t &res) {  
885 - std::int64_t flag_count{0};  
886 - CLI::detail::lexical_cast(res[0], flag_count);  
887 - function(flag_count);  
888 - return true;  
889 - };  
890 - return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))  
891 - ->multi_option_policy(MultiOptionPolicy::Sum);  
892 - } 660 + std::string flag_description = "");
893 661
894 #ifdef CLI11_CPP14 662 #ifdef CLI11_CPP14
895 /// Add option for callback (C++14 or better only) 663 /// Add option for callback (C++14 or better only)
@@ -904,50 +672,10 @@ class App { @@ -904,50 +672,10 @@ class App {
904 Option *set_config(std::string option_name = "", 672 Option *set_config(std::string option_name = "",
905 std::string default_filename = "", 673 std::string default_filename = "",
906 const std::string &help_message = "Read an ini file", 674 const std::string &help_message = "Read an ini file",
907 - bool config_required = false) {  
908 -  
909 - // Remove existing config if present  
910 - if(config_ptr_ != nullptr) {  
911 - remove_option(config_ptr_);  
912 - config_ptr_ = nullptr; // need to remove the config_ptr completely  
913 - }  
914 -  
915 - // Only add config if option passed  
916 - if(!option_name.empty()) {  
917 - config_ptr_ = add_option(option_name, help_message);  
918 - if(config_required) {  
919 - config_ptr_->required();  
920 - }  
921 - if(!default_filename.empty()) {  
922 - config_ptr_->default_str(std::move(default_filename));  
923 - }  
924 - config_ptr_->configurable(false);  
925 - }  
926 -  
927 - return config_ptr_;  
928 - } 675 + bool config_required = false);
929 676
930 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed. 677 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
931 - bool remove_option(Option *opt) {  
932 - // Make sure no links exist  
933 - for(Option_p &op : options_) {  
934 - op->remove_needs(opt);  
935 - op->remove_excludes(opt);  
936 - }  
937 -  
938 - if(help_ptr_ == opt)  
939 - help_ptr_ = nullptr;  
940 - if(help_all_ptr_ == opt)  
941 - help_all_ptr_ = nullptr;  
942 -  
943 - auto iterator =  
944 - std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });  
945 - if(iterator != std::end(options_)) {  
946 - options_.erase(iterator);  
947 - return true;  
948 - }  
949 - return false;  
950 - } 678 + bool remove_option(Option *opt);
951 679
952 /// creates an option group as part of the given app 680 /// creates an option group as part of the given app
953 template <typename T = Option_group> 681 template <typename T = Option_group>
@@ -968,119 +696,35 @@ class App { @@ -968,119 +696,35 @@ class App {
968 ///@{ 696 ///@{
969 697
970 /// Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag 698 /// Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag
971 - App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "") {  
972 - if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {  
973 - if(!detail::valid_first_char(subcommand_name[0])) {  
974 - throw IncorrectConstruction(  
975 - "Subcommand name starts with invalid character, '!' and '-' are not allowed");  
976 - }  
977 - for(auto c : subcommand_name) {  
978 - if(!detail::valid_later_char(c)) {  
979 - throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +  
980 - "'), all characters are allowed except"  
981 - "'=',':','{','}', and ' '");  
982 - }  
983 - }  
984 - }  
985 - CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));  
986 - return add_subcommand(std::move(subcom));  
987 - } 699 + App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "");
988 700
989 /// Add a previously created app as a subcommand 701 /// Add a previously created app as a subcommand
990 - App *add_subcommand(CLI::App_p subcom) {  
991 - if(!subcom)  
992 - throw IncorrectConstruction("passed App is not valid");  
993 - auto *ckapp = (name_.empty() && parent_ != nullptr) ? _get_fallthrough_parent() : this;  
994 - const auto &mstrg = _compare_subcommand_names(*subcom, *ckapp);  
995 - if(!mstrg.empty()) {  
996 - throw(OptionAlreadyAdded("subcommand name or alias matches existing subcommand: " + mstrg));  
997 - }  
998 - subcom->parent_ = this;  
999 - subcommands_.push_back(std::move(subcom));  
1000 - return subcommands_.back().get();  
1001 - } 702 + App *add_subcommand(CLI::App_p subcom);
1002 703
1003 /// Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed. 704 /// Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
1004 - bool remove_subcommand(App *subcom) {  
1005 - // Make sure no links exist  
1006 - for(App_p &sub : subcommands_) {  
1007 - sub->remove_excludes(subcom);  
1008 - sub->remove_needs(subcom);  
1009 - } 705 + bool remove_subcommand(App *subcom);
1010 706
1011 - auto iterator = std::find_if(  
1012 - std::begin(subcommands_), std::end(subcommands_), [subcom](const App_p &v) { return v.get() == subcom; });  
1013 - if(iterator != std::end(subcommands_)) {  
1014 - subcommands_.erase(iterator);  
1015 - return true;  
1016 - }  
1017 - return false;  
1018 - }  
1019 /// Check to see if a subcommand is part of this command (doesn't have to be in command line) 707 /// Check to see if a subcommand is part of this command (doesn't have to be in command line)
1020 /// returns the first subcommand if passed a nullptr 708 /// returns the first subcommand if passed a nullptr
1021 - App *get_subcommand(const App *subcom) const {  
1022 - if(subcom == nullptr)  
1023 - throw OptionNotFound("nullptr passed");  
1024 - for(const App_p &subcomptr : subcommands_)  
1025 - if(subcomptr.get() == subcom)  
1026 - return subcomptr.get();  
1027 - throw OptionNotFound(subcom->get_name());  
1028 - } 709 + App *get_subcommand(const App *subcom) const;
1029 710
1030 /// Check to see if a subcommand is part of this command (text version) 711 /// Check to see if a subcommand is part of this command (text version)
1031 - CLI11_NODISCARD App *get_subcommand(std::string subcom) const {  
1032 - auto *subc = _find_subcommand(subcom, false, false);  
1033 - if(subc == nullptr)  
1034 - throw OptionNotFound(subcom);  
1035 - return subc;  
1036 - } 712 + CLI11_NODISCARD App *get_subcommand(std::string subcom) const;
  713 +
1037 /// Get a pointer to subcommand by index 714 /// Get a pointer to subcommand by index
1038 - CLI11_NODISCARD App *get_subcommand(int index = 0) const {  
1039 - if(index >= 0) {  
1040 - auto uindex = static_cast<unsigned>(index);  
1041 - if(uindex < subcommands_.size())  
1042 - return subcommands_[uindex].get();  
1043 - }  
1044 - throw OptionNotFound(std::to_string(index));  
1045 - } 715 + CLI11_NODISCARD App *get_subcommand(int index = 0) const;
1046 716
1047 /// Check to see if a subcommand is part of this command and get a shared_ptr to it 717 /// Check to see if a subcommand is part of this command and get a shared_ptr to it
1048 - CLI::App_p get_subcommand_ptr(App *subcom) const {  
1049 - if(subcom == nullptr)  
1050 - throw OptionNotFound("nullptr passed");  
1051 - for(const App_p &subcomptr : subcommands_)  
1052 - if(subcomptr.get() == subcom)  
1053 - return subcomptr;  
1054 - throw OptionNotFound(subcom->get_name());  
1055 - } 718 + CLI::App_p get_subcommand_ptr(App *subcom) const;
1056 719
1057 /// Check to see if a subcommand is part of this command (text version) 720 /// Check to see if a subcommand is part of this command (text version)
1058 - CLI11_NODISCARD CLI::App_p get_subcommand_ptr(std::string subcom) const {  
1059 - for(const App_p &subcomptr : subcommands_)  
1060 - if(subcomptr->check_name(subcom))  
1061 - return subcomptr;  
1062 - throw OptionNotFound(subcom);  
1063 - } 721 + CLI11_NODISCARD CLI::App_p get_subcommand_ptr(std::string subcom) const;
1064 722
1065 /// Get an owning pointer to subcommand by index 723 /// Get an owning pointer to subcommand by index
1066 - CLI11_NODISCARD CLI::App_p get_subcommand_ptr(int index = 0) const {  
1067 - if(index >= 0) {  
1068 - auto uindex = static_cast<unsigned>(index);  
1069 - if(uindex < subcommands_.size())  
1070 - return subcommands_[uindex];  
1071 - }  
1072 - throw OptionNotFound(std::to_string(index));  
1073 - } 724 + CLI11_NODISCARD CLI::App_p get_subcommand_ptr(int index = 0) const;
1074 725
1075 /// Check to see if an option group is part of this App 726 /// Check to see if an option group is part of this App
1076 - CLI11_NODISCARD App *get_option_group(std::string group_name) const {  
1077 - for(const App_p &app : subcommands_) {  
1078 - if(app->name_.empty() && app->group_ == group_name) {  
1079 - return app.get();  
1080 - }  
1081 - }  
1082 - throw OptionNotFound(group_name);  
1083 - } 727 + CLI11_NODISCARD App *get_option_group(std::string group_name) const;
1084 728
1085 /// No argument version of count counts the number of times this subcommand was 729 /// No argument version of count counts the number of times this subcommand was
1086 /// passed in. The main app will return 1. Unnamed subcommands will also return 1 unless 730 /// passed in. The main app will return 1. Unnamed subcommands will also return 1 unless
@@ -1089,19 +733,7 @@ class App { @@ -1089,19 +733,7 @@ class App {
1089 733
1090 /// Get a count of all the arguments processed in options and subcommands, this excludes arguments which were 734 /// Get a count of all the arguments processed in options and subcommands, this excludes arguments which were
1091 /// treated as extras. 735 /// treated as extras.
1092 - CLI11_NODISCARD std::size_t count_all() const {  
1093 - std::size_t cnt{0};  
1094 - for(const auto &opt : options_) {  
1095 - cnt += opt->count();  
1096 - }  
1097 - for(const auto &sub : subcommands_) {  
1098 - cnt += sub->count_all();  
1099 - }  
1100 - if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called  
1101 - cnt += parsed_;  
1102 - }  
1103 - return cnt;  
1104 - } 736 + CLI11_NODISCARD std::size_t count_all() const;
1105 737
1106 /// Changes the group membership 738 /// Changes the group membership
1107 App *group(std::string group_name) { 739 App *group(std::string group_name) {
@@ -1192,153 +824,34 @@ class App { @@ -1192,153 +824,34 @@ class App {
1192 ///@{ 824 ///@{
1193 // 825 //
1194 /// Reset the parsed data 826 /// Reset the parsed data
1195 - void clear() {  
1196 -  
1197 - parsed_ = 0;  
1198 - pre_parse_called_ = false;  
1199 -  
1200 - missing_.clear();  
1201 - parsed_subcommands_.clear();  
1202 - for(const Option_p &opt : options_) {  
1203 - opt->clear();  
1204 - }  
1205 - for(const App_p &subc : subcommands_) {  
1206 - subc->clear();  
1207 - }  
1208 - } 827 + void clear();
1209 828
1210 /// Parses the command line - throws errors. 829 /// Parses the command line - throws errors.
1211 /// This must be called after the options are in but before the rest of the program. 830 /// This must be called after the options are in but before the rest of the program.
1212 - void parse(int argc, const char *const *argv) {  
1213 - // If the name is not set, read from command line  
1214 - if(name_.empty() || has_automatic_name_) {  
1215 - has_automatic_name_ = true;  
1216 - name_ = argv[0];  
1217 - }  
1218 -  
1219 - std::vector<std::string> args;  
1220 - args.reserve(static_cast<std::size_t>(argc) - 1U);  
1221 - for(auto i = static_cast<std::size_t>(argc) - 1U; i > 0U; --i)  
1222 - args.emplace_back(argv[i]);  
1223 - parse(std::move(args));  
1224 - } 831 + void parse(int argc, const char *const *argv);
1225 832
1226 /// Parse a single string as if it contained command line arguments. 833 /// Parse a single string as if it contained command line arguments.
1227 /// This function splits the string into arguments then calls parse(std::vector<std::string> &) 834 /// This function splits the string into arguments then calls parse(std::vector<std::string> &)
1228 /// the function takes an optional boolean argument specifying if the programName is included in the string to 835 /// the function takes an optional boolean argument specifying if the programName is included in the string to
1229 /// process 836 /// process
1230 - void parse(std::string commandline, bool program_name_included = false) {  
1231 -  
1232 - if(program_name_included) {  
1233 - auto nstr = detail::split_program_name(commandline);  
1234 - if((name_.empty()) || (has_automatic_name_)) {  
1235 - has_automatic_name_ = true;  
1236 - name_ = nstr.first;  
1237 - }  
1238 - commandline = std::move(nstr.second);  
1239 - } else {  
1240 - detail::trim(commandline);  
1241 - }  
1242 - // the next section of code is to deal with quoted arguments after an '=' or ':' for windows like operations  
1243 - if(!commandline.empty()) {  
1244 - commandline = detail::find_and_modify(commandline, "=", detail::escape_detect);  
1245 - if(allow_windows_style_options_)  
1246 - commandline = detail::find_and_modify(commandline, ":", detail::escape_detect);  
1247 - }  
1248 -  
1249 - auto args = detail::split_up(std::move(commandline));  
1250 - // remove all empty strings  
1251 - args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());  
1252 - std::reverse(args.begin(), args.end());  
1253 -  
1254 - parse(std::move(args));  
1255 - } 837 + void parse(std::string commandline, bool program_name_included = false);
1256 838
1257 /// The real work is done here. Expects a reversed vector. 839 /// The real work is done here. Expects a reversed vector.
1258 /// Changes the vector to the remaining options. 840 /// Changes the vector to the remaining options.
1259 - void parse(std::vector<std::string> &args) {  
1260 - // Clear if parsed  
1261 - if(parsed_ > 0)  
1262 - clear();  
1263 -  
1264 - // parsed_ is incremented in commands/subcommands,  
1265 - // but placed here to make sure this is cleared when  
1266 - // running parse after an error is thrown, even by _validate or _configure.  
1267 - parsed_ = 1;  
1268 - _validate();  
1269 - _configure();  
1270 - // set the parent as nullptr as this object should be the top now  
1271 - parent_ = nullptr;  
1272 - parsed_ = 0;  
1273 -  
1274 - _parse(args);  
1275 - run_callback();  
1276 - } 841 + void parse(std::vector<std::string> &args);
1277 842
1278 /// The real work is done here. Expects a reversed vector. 843 /// The real work is done here. Expects a reversed vector.
1279 - void parse(std::vector<std::string> &&args) {  
1280 - // Clear if parsed  
1281 - if(parsed_ > 0)  
1282 - clear();  
1283 -  
1284 - // parsed_ is incremented in commands/subcommands,  
1285 - // but placed here to make sure this is cleared when  
1286 - // running parse after an error is thrown, even by _validate or _configure.  
1287 - parsed_ = 1;  
1288 - _validate();  
1289 - _configure();  
1290 - // set the parent as nullptr as this object should be the top now  
1291 - parent_ = nullptr;  
1292 - parsed_ = 0;  
1293 -  
1294 - _parse(std::move(args));  
1295 - run_callback();  
1296 - }  
1297 -  
1298 - void parse_from_stream(std::istream &input) {  
1299 - if(parsed_ == 0) {  
1300 - _validate();  
1301 - _configure();  
1302 - // set the parent as nullptr as this object should be the top now  
1303 - } 844 + void parse(std::vector<std::string> &&args);
  845 +
  846 + void parse_from_stream(std::istream &input);
1304 847
1305 - _parse_stream(input);  
1306 - run_callback();  
1307 - }  
1308 /// Provide a function to print a help message. The function gets access to the App pointer and error. 848 /// Provide a function to print a help message. The function gets access to the App pointer and error.
1309 void failure_message(std::function<std::string(const App *, const Error &e)> function) { 849 void failure_message(std::function<std::string(const App *, const Error &e)> function) {
1310 failure_message_ = function; 850 failure_message_ = function;
1311 } 851 }
1312 852
1313 /// Print a nice error message and return the exit code 853 /// Print a nice error message and return the exit code
1314 - int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {  
1315 -  
1316 - /// Avoid printing anything if this is a CLI::RuntimeError  
1317 - if(e.get_name() == "RuntimeError")  
1318 - return e.get_exit_code();  
1319 -  
1320 - if(e.get_name() == "CallForHelp") {  
1321 - out << help();  
1322 - return e.get_exit_code();  
1323 - }  
1324 -  
1325 - if(e.get_name() == "CallForAllHelp") {  
1326 - out << help("", AppFormatMode::All);  
1327 - return e.get_exit_code();  
1328 - }  
1329 -  
1330 - if(e.get_name() == "CallForVersion") {  
1331 - out << e.what() << std::endl;  
1332 - return e.get_exit_code();  
1333 - }  
1334 -  
1335 - if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {  
1336 - if(failure_message_)  
1337 - err << failure_message_(this, e) << std::flush;  
1338 - }  
1339 -  
1340 - return e.get_exit_code();  
1341 - } 854 + int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const;
1342 855
1343 ///@} 856 ///@}
1344 /// @name Post parsing 857 /// @name Post parsing
@@ -1353,38 +866,11 @@ class App { @@ -1353,38 +866,11 @@ class App {
1353 866
1354 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all 867 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all
1355 /// subcommands (const) 868 /// subcommands (const)
1356 - std::vector<const App *> get_subcommands(const std::function<bool(const App *)> &filter) const {  
1357 - std::vector<const App *> subcomms(subcommands_.size());  
1358 - std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {  
1359 - return v.get();  
1360 - });  
1361 -  
1362 - if(filter) {  
1363 - subcomms.erase(std::remove_if(std::begin(subcomms),  
1364 - std::end(subcomms),  
1365 - [&filter](const App *app) { return !filter(app); }),  
1366 - std::end(subcomms));  
1367 - }  
1368 -  
1369 - return subcomms;  
1370 - } 869 + std::vector<const App *> get_subcommands(const std::function<bool(const App *)> &filter) const;
1371 870
1372 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all 871 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all
1373 /// subcommands 872 /// subcommands
1374 - std::vector<App *> get_subcommands(const std::function<bool(App *)> &filter) {  
1375 - std::vector<App *> subcomms(subcommands_.size());  
1376 - std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {  
1377 - return v.get();  
1378 - });  
1379 -  
1380 - if(filter) {  
1381 - subcomms.erase(  
1382 - std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *app) { return !filter(app); }),  
1383 - std::end(subcomms));  
1384 - }  
1385 -  
1386 - return subcomms;  
1387 - } 873 + std::vector<App *> get_subcommands(const std::function<bool(App *)> &filter);
1388 874
1389 /// Check to see if given subcommand was selected 875 /// Check to see if given subcommand was selected
1390 bool got_subcommand(const App *subcom) const { 876 bool got_subcommand(const App *subcom) const {
@@ -1442,47 +928,16 @@ class App { @@ -1442,47 +928,16 @@ class App {
1442 } 928 }
1443 929
1444 /// Removes an option from the excludes list of this subcommand 930 /// Removes an option from the excludes list of this subcommand
1445 - bool remove_excludes(Option *opt) {  
1446 - auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);  
1447 - if(iterator == std::end(exclude_options_)) {  
1448 - return false;  
1449 - }  
1450 - exclude_options_.erase(iterator);  
1451 - return true;  
1452 - } 931 + bool remove_excludes(Option *opt);
1453 932
1454 /// Removes a subcommand from the excludes list of this subcommand 933 /// Removes a subcommand from the excludes list of this subcommand
1455 - bool remove_excludes(App *app) {  
1456 - auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);  
1457 - if(iterator == std::end(exclude_subcommands_)) {  
1458 - return false;  
1459 - }  
1460 - auto *other_app = *iterator;  
1461 - exclude_subcommands_.erase(iterator);  
1462 - other_app->remove_excludes(this);  
1463 - return true;  
1464 - } 934 + bool remove_excludes(App *app);
1465 935
1466 /// Removes an option from the needs list of this subcommand 936 /// Removes an option from the needs list of this subcommand
1467 - bool remove_needs(Option *opt) {  
1468 - auto iterator = std::find(std::begin(need_options_), std::end(need_options_), opt);  
1469 - if(iterator == std::end(need_options_)) {  
1470 - return false;  
1471 - }  
1472 - need_options_.erase(iterator);  
1473 - return true;  
1474 - } 937 + bool remove_needs(Option *opt);
1475 938
1476 /// Removes a subcommand from the needs list of this subcommand 939 /// Removes a subcommand from the needs list of this subcommand
1477 - bool remove_needs(App *app) {  
1478 - auto iterator = std::find(std::begin(need_subcommands_), std::end(need_subcommands_), app);  
1479 - if(iterator == std::end(need_subcommands_)) {  
1480 - return false;  
1481 - }  
1482 - need_subcommands_.erase(iterator);  
1483 - return true;  
1484 - }  
1485 - 940 + bool remove_needs(App *app);
1486 ///@} 941 ///@}
1487 /// @name Help 942 /// @name Help
1488 ///@{ 943 ///@{
@@ -1505,37 +960,10 @@ class App { @@ -1505,37 +960,10 @@ class App {
1505 960
1506 /// Makes a help message, using the currently configured formatter 961 /// Makes a help message, using the currently configured formatter
1507 /// Will only do one subcommand at a time 962 /// Will only do one subcommand at a time
1508 - CLI11_NODISCARD std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const {  
1509 - if(prev.empty())  
1510 - prev = get_name();  
1511 - else  
1512 - prev += " " + get_name();  
1513 -  
1514 - // Delegate to subcommand if needed  
1515 - auto selected_subcommands = get_subcommands();  
1516 - if(!selected_subcommands.empty()) {  
1517 - return selected_subcommands.at(0)->help(prev, mode);  
1518 - }  
1519 - return formatter_->make_help(this, prev, mode);  
1520 - } 963 + CLI11_NODISCARD std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const;
1521 964
1522 /// Displays a version string 965 /// Displays a version string
1523 - CLI11_NODISCARD std::string version() const {  
1524 - std::string val;  
1525 - if(version_ptr_ != nullptr) {  
1526 - auto rv = version_ptr_->results();  
1527 - version_ptr_->clear();  
1528 - version_ptr_->add_result("true");  
1529 - try {  
1530 - version_ptr_->run_callback();  
1531 - } catch(const CLI::CallForVersion &cfv) {  
1532 - val = cfv.what();  
1533 - }  
1534 - version_ptr_->clear();  
1535 - version_ptr_->add_result(rv);  
1536 - }  
1537 - return val;  
1538 - } 966 + CLI11_NODISCARD std::string version() const;
1539 ///@} 967 ///@}
1540 /// @name Getters 968 /// @name Getters
1541 ///@{ 969 ///@{
@@ -1566,75 +994,16 @@ class App { @@ -1566,75 +994,16 @@ class App {
1566 } 994 }
1567 995
1568 /// Get the list of options (user facing function, so returns raw pointers), has optional filter function 996 /// Get the list of options (user facing function, so returns raw pointers), has optional filter function
1569 - std::vector<const Option *> get_options(const std::function<bool(const Option *)> filter = {}) const {  
1570 - std::vector<const Option *> options(options_.size());  
1571 - std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {  
1572 - return val.get();  
1573 - });  
1574 -  
1575 - if(filter) {  
1576 - options.erase(std::remove_if(std::begin(options),  
1577 - std::end(options),  
1578 - [&filter](const Option *opt) { return !filter(opt); }),  
1579 - std::end(options));  
1580 - }  
1581 -  
1582 - return options;  
1583 - } 997 + std::vector<const Option *> get_options(const std::function<bool(const Option *)> filter = {}) const;
1584 998
1585 /// Non-const version of the above 999 /// Non-const version of the above
1586 - std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {}) {  
1587 - std::vector<Option *> options(options_.size());  
1588 - std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {  
1589 - return val.get();  
1590 - });  
1591 -  
1592 - if(filter) {  
1593 - options.erase(  
1594 - std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) { return !filter(opt); }),  
1595 - std::end(options));  
1596 - }  
1597 -  
1598 - return options;  
1599 - } 1000 + std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {});
1600 1001
1601 /// Get an option by name (noexcept non-const version) 1002 /// Get an option by name (noexcept non-const version)
1602 - Option *get_option_no_throw(std::string option_name) noexcept {  
1603 - for(Option_p &opt : options_) {  
1604 - if(opt->check_name(option_name)) {  
1605 - return opt.get();  
1606 - }  
1607 - }  
1608 - for(auto &subc : subcommands_) {  
1609 - // also check down into nameless subcommands  
1610 - if(subc->get_name().empty()) {  
1611 - auto *opt = subc->get_option_no_throw(option_name);  
1612 - if(opt != nullptr) {  
1613 - return opt;  
1614 - }  
1615 - }  
1616 - }  
1617 - return nullptr;  
1618 - } 1003 + Option *get_option_no_throw(std::string option_name) noexcept;
1619 1004
1620 /// Get an option by name (noexcept const version) 1005 /// Get an option by name (noexcept const version)
1621 - CLI11_NODISCARD const Option *get_option_no_throw(std::string option_name) const noexcept {  
1622 - for(const Option_p &opt : options_) {  
1623 - if(opt->check_name(option_name)) {  
1624 - return opt.get();  
1625 - }  
1626 - }  
1627 - for(const auto &subc : subcommands_) {  
1628 - // also check down into nameless subcommands  
1629 - if(subc->get_name().empty()) {  
1630 - auto *opt = subc->get_option_no_throw(option_name);  
1631 - if(opt != nullptr) {  
1632 - return opt;  
1633 - }  
1634 - }  
1635 - }  
1636 - return nullptr;  
1637 - } 1006 + CLI11_NODISCARD const Option *get_option_no_throw(std::string option_name) const noexcept;
1638 1007
1639 /// Get an option by name 1008 /// Get an option by name
1640 CLI11_NODISCARD const Option *get_option(std::string option_name) const { 1009 CLI11_NODISCARD const Option *get_option(std::string option_name) const {
@@ -1769,116 +1138,25 @@ class App { @@ -1769,116 +1138,25 @@ class App {
1769 } 1138 }
1770 1139
1771 /// Get a display name for an app 1140 /// Get a display name for an app
1772 - CLI11_NODISCARD std::string get_display_name(bool with_aliases = false) const {  
1773 - if(name_.empty()) {  
1774 - return std::string("[Option Group: ") + get_group() + "]";  
1775 - }  
1776 - if(aliases_.empty() || !with_aliases) {  
1777 - return name_;  
1778 - }  
1779 - std::string dispname = name_;  
1780 - for(const auto &lalias : aliases_) {  
1781 - dispname.push_back(',');  
1782 - dispname.push_back(' ');  
1783 - dispname.append(lalias);  
1784 - }  
1785 - return dispname;  
1786 - } 1141 + CLI11_NODISCARD std::string get_display_name(bool with_aliases = false) const;
1787 1142
1788 /// Check the name, case insensitive and underscore insensitive if set 1143 /// Check the name, case insensitive and underscore insensitive if set
1789 - CLI11_NODISCARD bool check_name(std::string name_to_check) const {  
1790 - std::string local_name = name_;  
1791 - if(ignore_underscore_) {  
1792 - local_name = detail::remove_underscore(name_);  
1793 - name_to_check = detail::remove_underscore(name_to_check);  
1794 - }  
1795 - if(ignore_case_) {  
1796 - local_name = detail::to_lower(name_);  
1797 - name_to_check = detail::to_lower(name_to_check);  
1798 - }  
1799 -  
1800 - if(local_name == name_to_check) {  
1801 - return true;  
1802 - }  
1803 - for(auto les : aliases_) { // NOLINT(performance-for-range-copy)  
1804 - if(ignore_underscore_) {  
1805 - les = detail::remove_underscore(les);  
1806 - }  
1807 - if(ignore_case_) {  
1808 - les = detail::to_lower(les);  
1809 - }  
1810 - if(les == name_to_check) {  
1811 - return true;  
1812 - }  
1813 - }  
1814 - return false;  
1815 - } 1144 + CLI11_NODISCARD bool check_name(std::string name_to_check) const;
1816 1145
1817 /// Get the groups available directly from this option (in order) 1146 /// Get the groups available directly from this option (in order)
1818 - CLI11_NODISCARD std::vector<std::string> get_groups() const {  
1819 - std::vector<std::string> groups;  
1820 -  
1821 - for(const Option_p &opt : options_) {  
1822 - // Add group if it is not already in there  
1823 - if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {  
1824 - groups.push_back(opt->get_group());  
1825 - }  
1826 - }  
1827 -  
1828 - return groups;  
1829 - } 1147 + CLI11_NODISCARD std::vector<std::string> get_groups() const;
1830 1148
1831 /// This gets a vector of pointers with the original parse order 1149 /// This gets a vector of pointers with the original parse order
1832 CLI11_NODISCARD const std::vector<Option *> &parse_order() const { return parse_order_; } 1150 CLI11_NODISCARD const std::vector<Option *> &parse_order() const { return parse_order_; }
1833 1151
1834 /// This returns the missing options from the current subcommand 1152 /// This returns the missing options from the current subcommand
1835 - CLI11_NODISCARD std::vector<std::string> remaining(bool recurse = false) const {  
1836 - std::vector<std::string> miss_list;  
1837 - for(const std::pair<detail::Classifier, std::string> &miss : missing_) {  
1838 - miss_list.push_back(std::get<1>(miss));  
1839 - }  
1840 - // Get from a subcommand that may allow extras  
1841 - if(recurse) {  
1842 - if(!allow_extras_) {  
1843 - for(const auto &sub : subcommands_) {  
1844 - if(sub->name_.empty() && !sub->missing_.empty()) {  
1845 - for(const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {  
1846 - miss_list.push_back(std::get<1>(miss));  
1847 - }  
1848 - }  
1849 - }  
1850 - }  
1851 - // Recurse into subcommands  
1852 -  
1853 - for(const App *sub : parsed_subcommands_) {  
1854 - std::vector<std::string> output = sub->remaining(recurse);  
1855 - std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));  
1856 - }  
1857 - }  
1858 - return miss_list;  
1859 - } 1153 + CLI11_NODISCARD std::vector<std::string> remaining(bool recurse = false) const;
1860 1154
1861 /// This returns the missing options in a form ready for processing by another command line program 1155 /// This returns the missing options in a form ready for processing by another command line program
1862 - CLI11_NODISCARD std::vector<std::string> remaining_for_passthrough(bool recurse = false) const {  
1863 - std::vector<std::string> miss_list = remaining(recurse);  
1864 - std::reverse(std::begin(miss_list), std::end(miss_list));  
1865 - return miss_list;  
1866 - } 1156 + CLI11_NODISCARD std::vector<std::string> remaining_for_passthrough(bool recurse = false) const;
1867 1157
1868 /// This returns the number of remaining options, minus the -- separator 1158 /// This returns the number of remaining options, minus the -- separator
1869 - CLI11_NODISCARD std::size_t remaining_size(bool recurse = false) const {  
1870 - auto remaining_options = static_cast<std::size_t>(std::count_if(  
1871 - std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifier, std::string> &val) {  
1872 - return val.first != detail::Classifier::POSITIONAL_MARK;  
1873 - }));  
1874 -  
1875 - if(recurse) {  
1876 - for(const App_p &sub : subcommands_) {  
1877 - remaining_options += sub->remaining_size(recurse);  
1878 - }  
1879 - }  
1880 - return remaining_options;  
1881 - } 1159 + CLI11_NODISCARD std::size_t remaining_size(bool recurse = false) const;
1882 1160
1883 ///@} 1161 ///@}
1884 1162
@@ -1887,1147 +1165,118 @@ class App { @@ -1887,1147 +1165,118 @@ class App {
1887 /// 1165 ///
1888 /// Currently checks to see if multiple positionals exist with unlimited args and checks if the min and max options 1166 /// Currently checks to see if multiple positionals exist with unlimited args and checks if the min and max options
1889 /// are feasible 1167 /// are feasible
1890 - void _validate() const {  
1891 - // count the number of positional only args  
1892 - auto pcount = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {  
1893 - return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();  
1894 - });  
1895 - if(pcount > 1) {  
1896 - auto pcount_req = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {  
1897 - return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&  
1898 - opt->get_required();  
1899 - });  
1900 - if(pcount - pcount_req > 1) {  
1901 - throw InvalidError(name_);  
1902 - }  
1903 - }  
1904 -  
1905 - std::size_t nameless_subs{0};  
1906 - for(const App_p &app : subcommands_) {  
1907 - app->_validate();  
1908 - if(app->get_name().empty())  
1909 - ++nameless_subs;  
1910 - }  
1911 -  
1912 - if(require_option_min_ > 0) {  
1913 - if(require_option_max_ > 0) {  
1914 - if(require_option_max_ < require_option_min_) {  
1915 - throw(InvalidError("Required min options greater than required max options",  
1916 - ExitCodes::InvalidError));  
1917 - }  
1918 - }  
1919 - if(require_option_min_ > (options_.size() + nameless_subs)) {  
1920 - throw(InvalidError("Required min options greater than number of available options",  
1921 - ExitCodes::InvalidError));  
1922 - }  
1923 - }  
1924 - } 1168 + void _validate() const;
1925 1169
1926 /// configure subcommands to enable parsing through the current object 1170 /// configure subcommands to enable parsing through the current object
1927 /// set the correct fallthrough and prefix for nameless subcommands and manage the automatic enable or disable 1171 /// set the correct fallthrough and prefix for nameless subcommands and manage the automatic enable or disable
1928 /// makes sure parent is set correctly 1172 /// makes sure parent is set correctly
1929 - void _configure() {  
1930 - if(default_startup == startup_mode::enabled) {  
1931 - disabled_ = false;  
1932 - } else if(default_startup == startup_mode::disabled) {  
1933 - disabled_ = true;  
1934 - }  
1935 - for(const App_p &app : subcommands_) {  
1936 - if(app->has_automatic_name_) {  
1937 - app->name_.clear();  
1938 - }  
1939 - if(app->name_.empty()) {  
1940 - app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop  
1941 - app->prefix_command_ = false;  
1942 - }  
1943 - // make sure the parent is set to be this object in preparation for parse  
1944 - app->parent_ = this;  
1945 - app->_configure();  
1946 - }  
1947 - } 1173 + void _configure();
1948 1174
1949 /// Internal function to run (App) callback, bottom up 1175 /// Internal function to run (App) callback, bottom up
1950 - void run_callback(bool final_mode = false, bool suppress_final_callback = false) {  
1951 - pre_callback();  
1952 - // in the main app if immediate_callback_ is set it runs the main callback before the used subcommands  
1953 - if(!final_mode && parse_complete_callback_) {  
1954 - parse_complete_callback_();  
1955 - }  
1956 - // run the callbacks for the received subcommands  
1957 - for(App *subc : get_subcommands()) {  
1958 - if(subc->parent_ == this) {  
1959 - subc->run_callback(true, suppress_final_callback);  
1960 - }  
1961 - }  
1962 - // now run callbacks for option_groups  
1963 - for(auto &subc : subcommands_) {  
1964 - if(subc->name_.empty() && subc->count_all() > 0) {  
1965 - subc->run_callback(true, suppress_final_callback);  
1966 - }  
1967 - }  
1968 -  
1969 - // finally run the main callback  
1970 - if(final_callback_ && (parsed_ > 0) && (!suppress_final_callback)) {  
1971 - if(!name_.empty() || count_all() > 0 || parent_ == nullptr) {  
1972 - final_callback_();  
1973 - }  
1974 - }  
1975 - } 1176 + void run_callback(bool final_mode = false, bool suppress_final_callback = false);
1976 1177
1977 /// Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached. 1178 /// Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached.
1978 - CLI11_NODISCARD bool _valid_subcommand(const std::string &current, bool ignore_used = true) const {  
1979 - // Don't match if max has been reached - but still check parents  
1980 - if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {  
1981 - return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);  
1982 - }  
1983 - auto *com = _find_subcommand(current, true, ignore_used);  
1984 - if(com != nullptr) {  
1985 - return true;  
1986 - }  
1987 - // Check parent if exists, else return false  
1988 - return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);  
1989 - } 1179 + CLI11_NODISCARD bool _valid_subcommand(const std::string &current, bool ignore_used = true) const;
1990 1180
1991 /// Selects a Classifier enum based on the type of the current argument 1181 /// Selects a Classifier enum based on the type of the current argument
1992 CLI11_NODISCARD detail::Classifier _recognize(const std::string &current, 1182 CLI11_NODISCARD detail::Classifier _recognize(const std::string &current,
1993 - bool ignore_used_subcommands = true) const {  
1994 - std::string dummy1, dummy2;  
1995 -  
1996 - if(current == "--")  
1997 - return detail::Classifier::POSITIONAL_MARK;  
1998 - if(_valid_subcommand(current, ignore_used_subcommands))  
1999 - return detail::Classifier::SUBCOMMAND;  
2000 - if(detail::split_long(current, dummy1, dummy2))  
2001 - return detail::Classifier::LONG;  
2002 - if(detail::split_short(current, dummy1, dummy2)) {  
2003 - if(dummy1[0] >= '0' && dummy1[0] <= '9') {  
2004 - if(get_option_no_throw(std::string{'-', dummy1[0]}) == nullptr) {  
2005 - return detail::Classifier::NONE;  
2006 - }  
2007 - }  
2008 - return detail::Classifier::SHORT;  
2009 - }  
2010 - if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))  
2011 - return detail::Classifier::WINDOWS_STYLE;  
2012 - if((current == "++") && !name_.empty() && parent_ != nullptr)  
2013 - return detail::Classifier::SUBCOMMAND_TERMINATOR;  
2014 - return detail::Classifier::NONE;  
2015 - } 1183 + bool ignore_used_subcommands = true) const;
2016 1184
2017 // The parse function is now broken into several parts, and part of process 1185 // The parse function is now broken into several parts, and part of process
2018 1186
2019 /// Read and process a configuration file (main app only) 1187 /// Read and process a configuration file (main app only)
2020 - void _process_config_file() {  
2021 - if(config_ptr_ != nullptr) {  
2022 - bool config_required = config_ptr_->get_required();  
2023 - auto file_given = config_ptr_->count() > 0;  
2024 - auto config_files = config_ptr_->as<std::vector<std::string>>();  
2025 - if(config_files.empty() || config_files.front().empty()) {  
2026 - if(config_required) {  
2027 - throw FileError::Missing("no specified config file");  
2028 - }  
2029 - return;  
2030 - }  
2031 - for(auto rit = config_files.rbegin(); rit != config_files.rend(); ++rit) {  
2032 - const auto &config_file = *rit;  
2033 - auto path_result = detail::check_path(config_file.c_str());  
2034 - if(path_result == detail::path_type::file) {  
2035 - try {  
2036 - std::vector<ConfigItem> values = config_formatter_->from_file(config_file);  
2037 - _parse_config(values);  
2038 - if(!file_given) {  
2039 - config_ptr_->add_result(config_file);  
2040 - }  
2041 - } catch(const FileError &) {  
2042 - if(config_required || file_given)  
2043 - throw;  
2044 - }  
2045 - } else if(config_required || file_given) {  
2046 - throw FileError::Missing(config_file);  
2047 - }  
2048 - }  
2049 - }  
2050 - } 1188 + void _process_config_file();
2051 1189
2052 /// Get envname options if not yet passed. Runs on *all* subcommands. 1190 /// Get envname options if not yet passed. Runs on *all* subcommands.
2053 - void _process_env() {  
2054 - for(const Option_p &opt : options_) {  
2055 - if(opt->count() == 0 && !opt->envname_.empty()) {  
2056 - char *buffer = nullptr;  
2057 - std::string ename_string;  
2058 -  
2059 -#ifdef _MSC_VER  
2060 - // Windows version  
2061 - std::size_t sz = 0;  
2062 - if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {  
2063 - ename_string = std::string(buffer);  
2064 - free(buffer);  
2065 - }  
2066 -#else  
2067 - // This also works on Windows, but gives a warning  
2068 - buffer = std::getenv(opt->envname_.c_str());  
2069 - if(buffer != nullptr)  
2070 - ename_string = std::string(buffer);  
2071 -#endif  
2072 -  
2073 - if(!ename_string.empty()) {  
2074 - opt->add_result(ename_string);  
2075 - }  
2076 - }  
2077 - }  
2078 -  
2079 - for(App_p &sub : subcommands_) {  
2080 - if(sub->get_name().empty() || !sub->parse_complete_callback_)  
2081 - sub->_process_env();  
2082 - }  
2083 - } 1191 + void _process_env();
2084 1192
2085 /// Process callbacks. Runs on *all* subcommands. 1193 /// Process callbacks. Runs on *all* subcommands.
2086 - void _process_callbacks() {  
2087 -  
2088 - for(App_p &sub : subcommands_) {  
2089 - // process the priority option_groups first  
2090 - if(sub->get_name().empty() && sub->parse_complete_callback_) {  
2091 - if(sub->count_all() > 0) {  
2092 - sub->_process_callbacks();  
2093 - sub->run_callback();  
2094 - }  
2095 - }  
2096 - }  
2097 -  
2098 - for(const Option_p &opt : options_) {  
2099 - if((*opt) && !opt->get_callback_run()) {  
2100 - opt->run_callback();  
2101 - }  
2102 - }  
2103 - for(App_p &sub : subcommands_) {  
2104 - if(!sub->parse_complete_callback_) {  
2105 - sub->_process_callbacks();  
2106 - }  
2107 - }  
2108 - } 1194 + void _process_callbacks();
2109 1195
2110 /// Run help flag processing if any are found. 1196 /// Run help flag processing if any are found.
2111 /// 1197 ///
2112 /// The flags allow recursive calls to remember if there was a help flag on a parent. 1198 /// The flags allow recursive calls to remember if there was a help flag on a parent.
2113 - void _process_help_flags(bool trigger_help = false, bool trigger_all_help = false) const {  
2114 - const Option *help_ptr = get_help_ptr();  
2115 - const Option *help_all_ptr = get_help_all_ptr();  
2116 -  
2117 - if(help_ptr != nullptr && help_ptr->count() > 0)  
2118 - trigger_help = true;  
2119 - if(help_all_ptr != nullptr && help_all_ptr->count() > 0)  
2120 - trigger_all_help = true;  
2121 -  
2122 - // If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.  
2123 - if(!parsed_subcommands_.empty()) {  
2124 - for(const App *sub : parsed_subcommands_)  
2125 - sub->_process_help_flags(trigger_help, trigger_all_help);  
2126 -  
2127 - // Only the final subcommand should call for help. All help wins over help.  
2128 - } else if(trigger_all_help) {  
2129 - throw CallForAllHelp();  
2130 - } else if(trigger_help) {  
2131 - throw CallForHelp();  
2132 - }  
2133 - } 1199 + void _process_help_flags(bool trigger_help = false, bool trigger_all_help = false) const;
2134 1200
2135 /// Verify required options and cross requirements. Subcommands too (only if selected). 1201 /// Verify required options and cross requirements. Subcommands too (only if selected).
2136 - void _process_requirements() {  
2137 - // check excludes  
2138 - bool excluded{false};  
2139 - std::string excluder;  
2140 - for(const auto &opt : exclude_options_) {  
2141 - if(opt->count() > 0) {  
2142 - excluded = true;  
2143 - excluder = opt->get_name();  
2144 - }  
2145 - }  
2146 - for(const auto &subc : exclude_subcommands_) {  
2147 - if(subc->count_all() > 0) {  
2148 - excluded = true;  
2149 - excluder = subc->get_display_name();  
2150 - }  
2151 - }  
2152 - if(excluded) {  
2153 - if(count_all() > 0) {  
2154 - throw ExcludesError(get_display_name(), excluder);  
2155 - }  
2156 - // if we are excluded but didn't receive anything, just return  
2157 - return;  
2158 - }  
2159 -  
2160 - // check excludes  
2161 - bool missing_needed{false};  
2162 - std::string missing_need;  
2163 - for(const auto &opt : need_options_) {  
2164 - if(opt->count() == 0) {  
2165 - missing_needed = true;  
2166 - missing_need = opt->get_name();  
2167 - }  
2168 - }  
2169 - for(const auto &subc : need_subcommands_) {  
2170 - if(subc->count_all() == 0) {  
2171 - missing_needed = true;  
2172 - missing_need = subc->get_display_name();  
2173 - }  
2174 - }  
2175 - if(missing_needed) {  
2176 - if(count_all() > 0) {  
2177 - throw RequiresError(get_display_name(), missing_need);  
2178 - }  
2179 - // if we missing something but didn't have any options, just return  
2180 - return;  
2181 - }  
2182 -  
2183 - std::size_t used_options = 0;  
2184 - for(const Option_p &opt : options_) {  
2185 -  
2186 - if(opt->count() != 0) {  
2187 - ++used_options;  
2188 - }  
2189 - // Required but empty  
2190 - if(opt->get_required() && opt->count() == 0) {  
2191 - throw RequiredError(opt->get_name());  
2192 - }  
2193 - // Requires  
2194 - for(const Option *opt_req : opt->needs_)  
2195 - if(opt->count() > 0 && opt_req->count() == 0)  
2196 - throw RequiresError(opt->get_name(), opt_req->get_name());  
2197 - // Excludes  
2198 - for(const Option *opt_ex : opt->excludes_)  
2199 - if(opt->count() > 0 && opt_ex->count() != 0)  
2200 - throw ExcludesError(opt->get_name(), opt_ex->get_name());  
2201 - }  
2202 - // check for the required number of subcommands  
2203 - if(require_subcommand_min_ > 0) {  
2204 - auto selected_subcommands = get_subcommands();  
2205 - if(require_subcommand_min_ > selected_subcommands.size())  
2206 - throw RequiredError::Subcommand(require_subcommand_min_);  
2207 - }  
2208 -  
2209 - // Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.  
2210 -  
2211 - // run this loop to check how many unnamed subcommands were actually used since they are considered options  
2212 - // from the perspective of an App  
2213 - for(App_p &sub : subcommands_) {  
2214 - if(sub->disabled_)  
2215 - continue;  
2216 - if(sub->name_.empty() && sub->count_all() > 0) {  
2217 - ++used_options;  
2218 - }  
2219 - }  
2220 -  
2221 - if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {  
2222 - auto option_list = detail::join(options_, [this](const Option_p &ptr) {  
2223 - if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {  
2224 - return std::string{};  
2225 - }  
2226 - return ptr->get_name(false, true);  
2227 - });  
2228 -  
2229 - auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });  
2230 - if(!subc_list.empty()) {  
2231 - option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });  
2232 - }  
2233 - throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);  
2234 - }  
2235 -  
2236 - // now process the requirements for subcommands if needed  
2237 - for(App_p &sub : subcommands_) {  
2238 - if(sub->disabled_)  
2239 - continue;  
2240 - if(sub->name_.empty() && sub->required_ == false) {  
2241 - if(sub->count_all() == 0) {  
2242 - if(require_option_min_ > 0 && require_option_min_ <= used_options) {  
2243 - continue;  
2244 - // if we have met the requirement and there is nothing in this option group skip checking  
2245 - // requirements  
2246 - }  
2247 - if(require_option_max_ > 0 && used_options >= require_option_min_) {  
2248 - continue;  
2249 - // if we have met the requirement and there is nothing in this option group skip checking  
2250 - // requirements  
2251 - }  
2252 - }  
2253 - }  
2254 - if(sub->count() > 0 || sub->name_.empty()) {  
2255 - sub->_process_requirements();  
2256 - }  
2257 -  
2258 - if(sub->required_ && sub->count_all() == 0) {  
2259 - throw(CLI::RequiredError(sub->get_display_name()));  
2260 - }  
2261 - }  
2262 - } 1202 + void _process_requirements();
2263 1203
2264 /// Process callbacks and such. 1204 /// Process callbacks and such.
2265 - void _process() {  
2266 - try {  
2267 - // the config file might generate a FileError but that should not be processed until later in the process  
2268 - // to allow for help, version and other errors to generate first.  
2269 - _process_config_file();  
2270 -  
2271 - // process env shouldn't throw but no reason to process it if config generated an error  
2272 - _process_env();  
2273 - } catch(const CLI::FileError &) {  
2274 - // callbacks and help_flags can generate exceptions which should take priority  
2275 - // over the config file error if one exists.  
2276 - _process_callbacks();  
2277 - _process_help_flags();  
2278 - throw;  
2279 - }  
2280 -  
2281 - _process_callbacks();  
2282 - _process_help_flags();  
2283 -  
2284 - _process_requirements();  
2285 - } 1205 + void _process();
2286 1206
2287 /// Throw an error if anything is left over and should not be. 1207 /// Throw an error if anything is left over and should not be.
2288 - void _process_extras() {  
2289 - if(!(allow_extras_ || prefix_command_)) {  
2290 - std::size_t num_left_over = remaining_size();  
2291 - if(num_left_over > 0) {  
2292 - throw ExtrasError(name_, remaining(false));  
2293 - }  
2294 - }  
2295 -  
2296 - for(App_p &sub : subcommands_) {  
2297 - if(sub->count() > 0)  
2298 - sub->_process_extras();  
2299 - }  
2300 - } 1208 + void _process_extras();
2301 1209
2302 /// Throw an error if anything is left over and should not be. 1210 /// Throw an error if anything is left over and should not be.
2303 /// Modifies the args to fill in the missing items before throwing. 1211 /// Modifies the args to fill in the missing items before throwing.
2304 - void _process_extras(std::vector<std::string> &args) {  
2305 - if(!(allow_extras_ || prefix_command_)) {  
2306 - std::size_t num_left_over = remaining_size();  
2307 - if(num_left_over > 0) {  
2308 - args = remaining(false);  
2309 - throw ExtrasError(name_, args);  
2310 - }  
2311 - }  
2312 -  
2313 - for(App_p &sub : subcommands_) {  
2314 - if(sub->count() > 0)  
2315 - sub->_process_extras(args);  
2316 - }  
2317 - } 1212 + void _process_extras(std::vector<std::string> &args);
2318 1213
2319 /// Internal function to recursively increment the parsed counter on the current app as well unnamed subcommands 1214 /// Internal function to recursively increment the parsed counter on the current app as well unnamed subcommands
2320 - void increment_parsed() {  
2321 - ++parsed_;  
2322 - for(App_p &sub : subcommands_) {  
2323 - if(sub->get_name().empty())  
2324 - sub->increment_parsed();  
2325 - }  
2326 - }  
2327 - /// Internal parse function  
2328 - void _parse(std::vector<std::string> &args) {  
2329 - increment_parsed();  
2330 - _trigger_pre_parse(args.size());  
2331 - bool positional_only = false;  
2332 -  
2333 - while(!args.empty()) {  
2334 - if(!_parse_single(args, positional_only)) {  
2335 - break;  
2336 - }  
2337 - }  
2338 -  
2339 - if(parent_ == nullptr) {  
2340 - _process();  
2341 -  
2342 - // Throw error if any items are left over (depending on settings)  
2343 - _process_extras(args);  
2344 -  
2345 - // Convert missing (pairs) to extras (string only) ready for processing in another app  
2346 - args = remaining_for_passthrough(false);  
2347 - } else if(parse_complete_callback_) {  
2348 - _process_env();  
2349 - _process_callbacks();  
2350 - _process_help_flags();  
2351 - _process_requirements();  
2352 - run_callback(false, true);  
2353 - }  
2354 - } 1215 + void increment_parsed();
2355 1216
2356 /// Internal parse function 1217 /// Internal parse function
2357 - void _parse(std::vector<std::string> &&args) {  
2358 - // this can only be called by the top level in which case parent == nullptr by definition  
2359 - // operation is simplified  
2360 - increment_parsed();  
2361 - _trigger_pre_parse(args.size());  
2362 - bool positional_only = false;  
2363 -  
2364 - while(!args.empty()) {  
2365 - _parse_single(args, positional_only);  
2366 - }  
2367 - _process(); 1218 + void _parse(std::vector<std::string> &args);
2368 1219
2369 - // Throw error if any items are left over (depending on settings)  
2370 - _process_extras();  
2371 - } 1220 + /// Internal parse function
  1221 + void _parse(std::vector<std::string> &&args);
2372 1222
2373 /// Internal function to parse a stream 1223 /// Internal function to parse a stream
2374 - void _parse_stream(std::istream &input) {  
2375 - auto values = config_formatter_->from_config(input);  
2376 - _parse_config(values);  
2377 - increment_parsed();  
2378 - _trigger_pre_parse(values.size());  
2379 - _process();  
2380 -  
2381 - // Throw error if any items are left over (depending on settings)  
2382 - _process_extras();  
2383 - } 1224 + void _parse_stream(std::istream &input);
2384 1225
2385 /// Parse one config param, return false if not found in any subcommand, remove if it is 1226 /// Parse one config param, return false if not found in any subcommand, remove if it is
2386 /// 1227 ///
2387 /// If this has more than one dot.separated.name, go into the subcommand matching it 1228 /// If this has more than one dot.separated.name, go into the subcommand matching it
2388 /// Returns true if it managed to find the option, if false you'll need to remove the arg manually. 1229 /// Returns true if it managed to find the option, if false you'll need to remove the arg manually.
2389 - void _parse_config(const std::vector<ConfigItem> &args) {  
2390 - for(const ConfigItem &item : args) {  
2391 - if(!_parse_single_config(item) && allow_config_extras_ == config_extras_mode::error)  
2392 - throw ConfigError::Extras(item.fullname());  
2393 - }  
2394 - } 1230 + void _parse_config(const std::vector<ConfigItem> &args);
2395 1231
2396 /// Fill in a single config option 1232 /// Fill in a single config option
2397 - bool _parse_single_config(const ConfigItem &item, std::size_t level = 0) {  
2398 - if(level < item.parents.size()) {  
2399 - try {  
2400 - auto *subcom = get_subcommand(item.parents.at(level));  
2401 - auto result = subcom->_parse_single_config(item, level + 1);  
2402 -  
2403 - return result;  
2404 - } catch(const OptionNotFound &) {  
2405 - return false;  
2406 - }  
2407 - }  
2408 - // check for section open  
2409 - if(item.name == "++") {  
2410 - if(configurable_) {  
2411 - increment_parsed();  
2412 - _trigger_pre_parse(2);  
2413 - if(parent_ != nullptr) {  
2414 - parent_->parsed_subcommands_.push_back(this);  
2415 - }  
2416 - }  
2417 - return true;  
2418 - }  
2419 - // check for section close  
2420 - if(item.name == "--") {  
2421 - if(configurable_ && parse_complete_callback_) {  
2422 - _process_callbacks();  
2423 - _process_requirements();  
2424 - run_callback();  
2425 - }  
2426 - return true;  
2427 - }  
2428 - Option *op = get_option_no_throw("--" + item.name);  
2429 - if(op == nullptr) {  
2430 - if(item.name.size() == 1) {  
2431 - op = get_option_no_throw("-" + item.name);  
2432 - }  
2433 - }  
2434 - if(op == nullptr) {  
2435 - op = get_option_no_throw(item.name);  
2436 - }  
2437 - if(op == nullptr) {  
2438 - // If the option was not present  
2439 - if(get_allow_config_extras() == config_extras_mode::capture)  
2440 - // Should we worry about classifying the extras properly?  
2441 - missing_.emplace_back(detail::Classifier::NONE, item.fullname());  
2442 - return false;  
2443 - }  
2444 -  
2445 - if(!op->get_configurable()) {  
2446 - if(get_allow_config_extras() == config_extras_mode::ignore_all) {  
2447 - return false;  
2448 - }  
2449 - throw ConfigError::NotConfigurable(item.fullname());  
2450 - }  
2451 -  
2452 - if(op->empty()) {  
2453 -  
2454 - if(op->get_expected_min() == 0) {  
2455 - // Flag parsing  
2456 - auto res = config_formatter_->to_flag(item);  
2457 - res = op->get_flag_value(item.name, res);  
2458 -  
2459 - op->add_result(res);  
2460 -  
2461 - } else {  
2462 - op->add_result(item.inputs);  
2463 - op->run_callback();  
2464 - }  
2465 - }  
2466 -  
2467 - return true;  
2468 - } 1233 + bool _parse_single_config(const ConfigItem &item, std::size_t level = 0);
2469 1234
2470 /// Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if missing 1235 /// Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if missing
2471 /// from main return false if the parse has failed and needs to return to parent 1236 /// from main return false if the parse has failed and needs to return to parent
2472 - bool _parse_single(std::vector<std::string> &args, bool &positional_only) {  
2473 - bool retval = true;  
2474 - detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back());  
2475 - switch(classifier) {  
2476 - case detail::Classifier::POSITIONAL_MARK:  
2477 - args.pop_back();  
2478 - positional_only = true;  
2479 - if((!_has_remaining_positionals()) && (parent_ != nullptr)) {  
2480 - retval = false;  
2481 - } else {  
2482 - _move_to_missing(classifier, "--");  
2483 - }  
2484 - break;  
2485 - case detail::Classifier::SUBCOMMAND_TERMINATOR:  
2486 - // treat this like a positional mark if in the parent app  
2487 - args.pop_back();  
2488 - retval = false;  
2489 - break;  
2490 - case detail::Classifier::SUBCOMMAND:  
2491 - retval = _parse_subcommand(args);  
2492 - break;  
2493 - case detail::Classifier::LONG:  
2494 - case detail::Classifier::SHORT:  
2495 - case detail::Classifier::WINDOWS_STYLE:  
2496 - // If already parsed a subcommand, don't accept options_  
2497 - _parse_arg(args, classifier);  
2498 - break;  
2499 - case detail::Classifier::NONE:  
2500 - // Probably a positional or something for a parent (sub)command  
2501 - retval = _parse_positional(args, false);  
2502 - if(retval && positionals_at_end_) {  
2503 - positional_only = true;  
2504 - }  
2505 - break;  
2506 - // LCOV_EXCL_START  
2507 - default:  
2508 - throw HorribleError("unrecognized classifier (you should not see this!)");  
2509 - // LCOV_EXCL_STOP  
2510 - }  
2511 - return retval;  
2512 - } 1237 + bool _parse_single(std::vector<std::string> &args, bool &positional_only);
2513 1238
2514 /// Count the required remaining positional arguments 1239 /// Count the required remaining positional arguments
2515 - CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only = false) const {  
2516 - std::size_t retval = 0;  
2517 - for(const Option_p &opt : options_) {  
2518 - if(opt->get_positional() && (!required_only || opt->get_required())) {  
2519 - if(opt->get_items_expected_min() > 0 &&  
2520 - static_cast<int>(opt->count()) < opt->get_items_expected_min()) {  
2521 - retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();  
2522 - }  
2523 - }  
2524 - }  
2525 - return retval;  
2526 - } 1240 + CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only = false) const;
2527 1241
2528 /// Count the required remaining positional arguments 1242 /// Count the required remaining positional arguments
2529 - CLI11_NODISCARD bool _has_remaining_positionals() const {  
2530 - for(const Option_p &opt : options_) {  
2531 - if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {  
2532 - return true;  
2533 - }  
2534 - }  
2535 -  
2536 - return false;  
2537 - } 1243 + CLI11_NODISCARD bool _has_remaining_positionals() const;
2538 1244
2539 /// Parse a positional, go up the tree to check 1245 /// Parse a positional, go up the tree to check
2540 /// @param haltOnSubcommand if set to true the operation will not process subcommands merely return false 1246 /// @param haltOnSubcommand if set to true the operation will not process subcommands merely return false
2541 /// Return true if the positional was used false otherwise 1247 /// Return true if the positional was used false otherwise
2542 - bool _parse_positional(std::vector<std::string> &args, bool haltOnSubcommand) {  
2543 -  
2544 - const std::string &positional = args.back();  
2545 -  
2546 - if(positionals_at_end_) {  
2547 - // deal with the case of required arguments at the end which should take precedence over other arguments  
2548 - auto arg_rem = args.size();  
2549 - auto remreq = _count_remaining_positionals(true);  
2550 - if(arg_rem <= remreq) {  
2551 - for(const Option_p &opt : options_) {  
2552 - if(opt->get_positional() && opt->required_) {  
2553 - if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {  
2554 - if(validate_positionals_) {  
2555 - std::string pos = positional;  
2556 - pos = opt->_validate(pos, 0);  
2557 - if(!pos.empty()) {  
2558 - continue;  
2559 - }  
2560 - }  
2561 -  
2562 - parse_order_.push_back(opt.get());  
2563 - /// if we require a separator add it here  
2564 - if(opt->get_inject_separator()) {  
2565 - if(!opt->results().empty() && !opt->results().back().empty()) {  
2566 - opt->add_result(std::string{});  
2567 - }  
2568 - }  
2569 - if(opt->get_trigger_on_parse() &&  
2570 - opt->current_option_state_ == Option::option_state::callback_run) {  
2571 - opt->clear();  
2572 - }  
2573 - opt->add_result(positional);  
2574 - if(opt->get_trigger_on_parse()) {  
2575 - opt->run_callback();  
2576 - }  
2577 - args.pop_back();  
2578 - return true;  
2579 - }  
2580 - }  
2581 - }  
2582 - }  
2583 - }  
2584 - for(const Option_p &opt : options_) {  
2585 - // Eat options, one by one, until done  
2586 - if(opt->get_positional() &&  
2587 - (static_cast<int>(opt->count()) < opt->get_items_expected_min() || opt->get_allow_extra_args())) {  
2588 - if(validate_positionals_) {  
2589 - std::string pos = positional;  
2590 - pos = opt->_validate(pos, 0);  
2591 - if(!pos.empty()) {  
2592 - continue;  
2593 - }  
2594 - }  
2595 - if(opt->get_inject_separator()) {  
2596 - if(!opt->results().empty() && !opt->results().back().empty()) {  
2597 - opt->add_result(std::string{});  
2598 - }  
2599 - }  
2600 - if(opt->get_trigger_on_parse() && opt->current_option_state_ == Option::option_state::callback_run) {  
2601 - opt->clear();  
2602 - }  
2603 - opt->add_result(positional);  
2604 - if(opt->get_trigger_on_parse()) {  
2605 - opt->run_callback();  
2606 - }  
2607 - parse_order_.push_back(opt.get());  
2608 - args.pop_back();  
2609 - return true;  
2610 - }  
2611 - }  
2612 -  
2613 - for(auto &subc : subcommands_) {  
2614 - if((subc->name_.empty()) && (!subc->disabled_)) {  
2615 - if(subc->_parse_positional(args, false)) {  
2616 - if(!subc->pre_parse_called_) {  
2617 - subc->_trigger_pre_parse(args.size());  
2618 - }  
2619 - return true;  
2620 - }  
2621 - }  
2622 - }  
2623 - // let the parent deal with it if possible  
2624 - if(parent_ != nullptr && fallthrough_)  
2625 - return _get_fallthrough_parent()->_parse_positional(args, static_cast<bool>(parse_complete_callback_));  
2626 -  
2627 - /// Try to find a local subcommand that is repeated  
2628 - auto *com = _find_subcommand(args.back(), true, false);  
2629 - if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {  
2630 - if(haltOnSubcommand) {  
2631 - return false;  
2632 - }  
2633 - args.pop_back();  
2634 - com->_parse(args);  
2635 - return true;  
2636 - }  
2637 - /// now try one last gasp at subcommands that have been executed before, go to root app and try to find a  
2638 - /// subcommand in a broader way, if one exists let the parent deal with it  
2639 - auto *parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;  
2640 - com = parent_app->_find_subcommand(args.back(), true, false);  
2641 - if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||  
2642 - com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {  
2643 - return false;  
2644 - }  
2645 -  
2646 - if(positionals_at_end_) {  
2647 - throw CLI::ExtrasError(name_, args);  
2648 - }  
2649 - /// If this is an option group don't deal with it  
2650 - if(parent_ != nullptr && name_.empty()) {  
2651 - return false;  
2652 - }  
2653 - /// We are out of other options this goes to missing  
2654 - _move_to_missing(detail::Classifier::NONE, positional);  
2655 - args.pop_back();  
2656 - if(prefix_command_) {  
2657 - while(!args.empty()) {  
2658 - _move_to_missing(detail::Classifier::NONE, args.back());  
2659 - args.pop_back();  
2660 - }  
2661 - }  
2662 -  
2663 - return true;  
2664 - } 1248 + bool _parse_positional(std::vector<std::string> &args, bool haltOnSubcommand);
2665 1249
2666 /// Locate a subcommand by name with two conditions, should disabled subcommands be ignored, and should used 1250 /// Locate a subcommand by name with two conditions, should disabled subcommands be ignored, and should used
2667 /// subcommands be ignored 1251 /// subcommands be ignored
2668 CLI11_NODISCARD App * 1252 CLI11_NODISCARD App *
2669 - _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {  
2670 - for(const App_p &com : subcommands_) {  
2671 - if(com->disabled_ && ignore_disabled)  
2672 - continue;  
2673 - if(com->get_name().empty()) {  
2674 - auto *subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);  
2675 - if(subc != nullptr) {  
2676 - return subc;  
2677 - }  
2678 - }  
2679 - if(com->check_name(subc_name)) {  
2680 - if((!*com) || !ignore_used)  
2681 - return com.get();  
2682 - }  
2683 - }  
2684 - return nullptr;  
2685 - } 1253 + _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept;
2686 1254
2687 /// Parse a subcommand, modify args and continue 1255 /// Parse a subcommand, modify args and continue
2688 /// 1256 ///
2689 /// Unlike the others, this one will always allow fallthrough 1257 /// Unlike the others, this one will always allow fallthrough
2690 /// return true if the subcommand was processed false otherwise 1258 /// return true if the subcommand was processed false otherwise
2691 - bool _parse_subcommand(std::vector<std::string> &args) {  
2692 - if(_count_remaining_positionals(/* required */ true) > 0) {  
2693 - _parse_positional(args, false);  
2694 - return true;  
2695 - }  
2696 - auto *com = _find_subcommand(args.back(), true, true);  
2697 - if(com != nullptr) {  
2698 - args.pop_back();  
2699 - if(!com->silent_) {  
2700 - parsed_subcommands_.push_back(com);  
2701 - }  
2702 - com->_parse(args);  
2703 - auto *parent_app = com->parent_;  
2704 - while(parent_app != this) {  
2705 - parent_app->_trigger_pre_parse(args.size());  
2706 - if(!com->silent_) {  
2707 - parent_app->parsed_subcommands_.push_back(com);  
2708 - }  
2709 - parent_app = parent_app->parent_;  
2710 - }  
2711 - return true;  
2712 - }  
2713 -  
2714 - if(parent_ == nullptr)  
2715 - throw HorribleError("Subcommand " + args.back() + " missing");  
2716 - return false;  
2717 - } 1259 + bool _parse_subcommand(std::vector<std::string> &args);
2718 1260
2719 /// Parse a short (false) or long (true) argument, must be at the top of the list 1261 /// Parse a short (false) or long (true) argument, must be at the top of the list
2720 /// return true if the argument was processed or false if nothing was done 1262 /// return true if the argument was processed or false if nothing was done
2721 - bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {  
2722 -  
2723 - std::string current = args.back();  
2724 -  
2725 - std::string arg_name;  
2726 - std::string value;  
2727 - std::string rest;  
2728 -  
2729 - switch(current_type) {  
2730 - case detail::Classifier::LONG:  
2731 - if(!detail::split_long(current, arg_name, value))  
2732 - throw HorribleError("Long parsed but missing (you should not see this):" + args.back());  
2733 - break;  
2734 - case detail::Classifier::SHORT:  
2735 - if(!detail::split_short(current, arg_name, rest))  
2736 - throw HorribleError("Short parsed but missing! You should not see this");  
2737 - break;  
2738 - case detail::Classifier::WINDOWS_STYLE:  
2739 - if(!detail::split_windows_style(current, arg_name, value))  
2740 - throw HorribleError("windows option parsed but missing! You should not see this");  
2741 - break;  
2742 - case detail::Classifier::SUBCOMMAND:  
2743 - case detail::Classifier::SUBCOMMAND_TERMINATOR:  
2744 - case detail::Classifier::POSITIONAL_MARK:  
2745 - case detail::Classifier::NONE:  
2746 - default:  
2747 - throw HorribleError("parsing got called with invalid option! You should not see this");  
2748 - }  
2749 -  
2750 - auto op_ptr =  
2751 - std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {  
2752 - if(current_type == detail::Classifier::LONG)  
2753 - return opt->check_lname(arg_name);  
2754 - if(current_type == detail::Classifier::SHORT)  
2755 - return opt->check_sname(arg_name);  
2756 - // this will only get called for detail::Classifier::WINDOWS_STYLE  
2757 - return opt->check_lname(arg_name) || opt->check_sname(arg_name);  
2758 - });  
2759 -  
2760 - // Option not found  
2761 - if(op_ptr == std::end(options_)) {  
2762 - for(auto &subc : subcommands_) {  
2763 - if(subc->name_.empty() && !subc->disabled_) {  
2764 - if(subc->_parse_arg(args, current_type)) {  
2765 - if(!subc->pre_parse_called_) {  
2766 - subc->_trigger_pre_parse(args.size());  
2767 - }  
2768 - return true;  
2769 - }  
2770 - }  
2771 - }  
2772 -  
2773 - // don't capture missing if this is a nameless subcommand and nameless subcommands can't fallthrough  
2774 - if(parent_ != nullptr && name_.empty()) {  
2775 - return false;  
2776 - }  
2777 -  
2778 - // If a subcommand, try the main command  
2779 - if(parent_ != nullptr && fallthrough_)  
2780 - return _get_fallthrough_parent()->_parse_arg(args, current_type);  
2781 -  
2782 - // Otherwise, add to missing  
2783 - args.pop_back();  
2784 - _move_to_missing(current_type, current);  
2785 - return true;  
2786 - }  
2787 -  
2788 - args.pop_back();  
2789 -  
2790 - // Get a reference to the pointer to make syntax bearable  
2791 - Option_p &op = *op_ptr;  
2792 - /// if we require a separator add it here  
2793 - if(op->get_inject_separator()) {  
2794 - if(!op->results().empty() && !op->results().back().empty()) {  
2795 - op->add_result(std::string{});  
2796 - }  
2797 - }  
2798 - if(op->get_trigger_on_parse() && op->current_option_state_ == Option::option_state::callback_run) {  
2799 - op->clear();  
2800 - }  
2801 - int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());  
2802 - int max_num = op->get_items_expected_max();  
2803 - // check container like options to limit the argument size to a single type if the allow_extra_flags argument is  
2804 - // set. 16 is somewhat arbitrary (needs to be at least 4)  
2805 - if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {  
2806 - auto tmax = op->get_type_size_max();  
2807 - max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;  
2808 - }  
2809 - // Make sure we always eat the minimum for unlimited vectors  
2810 - int collected = 0; // total number of arguments collected  
2811 - int result_count = 0; // local variable for number of results in a single arg string  
2812 - // deal with purely flag like things  
2813 - if(max_num == 0) {  
2814 - auto res = op->get_flag_value(arg_name, value);  
2815 - op->add_result(res);  
2816 - parse_order_.push_back(op.get());  
2817 - } else if(!value.empty()) { // --this=value  
2818 - op->add_result(value, result_count);  
2819 - parse_order_.push_back(op.get());  
2820 - collected += result_count;  
2821 - // -Trest  
2822 - } else if(!rest.empty()) {  
2823 - op->add_result(rest, result_count);  
2824 - parse_order_.push_back(op.get());  
2825 - rest = "";  
2826 - collected += result_count;  
2827 - }  
2828 -  
2829 - // gather the minimum number of arguments  
2830 - while(min_num > collected && !args.empty()) {  
2831 - std::string current_ = args.back();  
2832 - args.pop_back();  
2833 - op->add_result(current_, result_count);  
2834 - parse_order_.push_back(op.get());  
2835 - collected += result_count;  
2836 - }  
2837 -  
2838 - if(min_num > collected) { // if we have run out of arguments and the minimum was not met  
2839 - throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());  
2840 - }  
2841 -  
2842 - // now check for optional arguments  
2843 - if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments  
2844 - auto remreqpos = _count_remaining_positionals(true);  
2845 - // we have met the minimum now optionally check up to the maximum  
2846 - while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&  
2847 - _recognize(args.back(), false) == detail::Classifier::NONE) {  
2848 - // If any required positionals remain, don't keep eating  
2849 - if(remreqpos >= args.size()) {  
2850 - break;  
2851 - }  
2852 - if(validate_optional_arguments_) {  
2853 - std::string arg = args.back();  
2854 - arg = op->_validate(arg, 0);  
2855 - if(!arg.empty()) {  
2856 - break;  
2857 - }  
2858 - }  
2859 - op->add_result(args.back(), result_count);  
2860 - parse_order_.push_back(op.get());  
2861 - args.pop_back();  
2862 - collected += result_count;  
2863 - }  
2864 -  
2865 - // Allow -- to end an unlimited list and "eat" it  
2866 - if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)  
2867 - args.pop_back();  
2868 - // optional flag that didn't receive anything now get the default value  
2869 - if(min_num == 0 && max_num > 0 && collected == 0) {  
2870 - auto res = op->get_flag_value(arg_name, std::string{});  
2871 - op->add_result(res);  
2872 - parse_order_.push_back(op.get());  
2873 - }  
2874 - }  
2875 - // if we only partially completed a type then add an empty string if allowed for later processing  
2876 - if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {  
2877 - if(op->get_type_size_max() != op->get_type_size_min()) {  
2878 - op->add_result(std::string{});  
2879 - } else {  
2880 - throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());  
2881 - }  
2882 - }  
2883 - if(op->get_trigger_on_parse()) {  
2884 - op->run_callback();  
2885 - }  
2886 - if(!rest.empty()) {  
2887 - rest = "-" + rest;  
2888 - args.push_back(rest);  
2889 - }  
2890 - return true;  
2891 - } 1263 + bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type);
2892 1264
2893 /// Trigger the pre_parse callback if needed 1265 /// Trigger the pre_parse callback if needed
2894 - void _trigger_pre_parse(std::size_t remaining_args) {  
2895 - if(!pre_parse_called_) {  
2896 - pre_parse_called_ = true;  
2897 - if(pre_parse_callback_) {  
2898 - pre_parse_callback_(remaining_args);  
2899 - }  
2900 - } else if(immediate_callback_) {  
2901 - if(!name_.empty()) {  
2902 - auto pcnt = parsed_;  
2903 - auto extras = std::move(missing_);  
2904 - clear();  
2905 - parsed_ = pcnt;  
2906 - pre_parse_called_ = true;  
2907 - missing_ = std::move(extras);  
2908 - }  
2909 - }  
2910 - } 1266 + void _trigger_pre_parse(std::size_t remaining_args);
2911 1267
2912 /// Get the appropriate parent to fallthrough to which is the first one that has a name or the main app 1268 /// Get the appropriate parent to fallthrough to which is the first one that has a name or the main app
2913 - App *_get_fallthrough_parent() {  
2914 - if(parent_ == nullptr) {  
2915 - throw(HorribleError("No Valid parent"));  
2916 - }  
2917 - auto *fallthrough_parent = parent_;  
2918 - while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {  
2919 - fallthrough_parent = fallthrough_parent->parent_;  
2920 - }  
2921 - return fallthrough_parent;  
2922 - } 1269 + App *_get_fallthrough_parent();
2923 1270
2924 /// Helper function to run through all possible comparisons of subcommand names to check there is no overlap 1271 /// Helper function to run through all possible comparisons of subcommand names to check there is no overlap
2925 - CLI11_NODISCARD const std::string &_compare_subcommand_names(const App &subcom, const App &base) const {  
2926 - static const std::string estring;  
2927 - if(subcom.disabled_) {  
2928 - return estring;  
2929 - }  
2930 - for(const auto &subc : base.subcommands_) {  
2931 - if(subc.get() != &subcom) {  
2932 - if(subc->disabled_) {  
2933 - continue;  
2934 - }  
2935 - if(!subcom.get_name().empty()) {  
2936 - if(subc->check_name(subcom.get_name())) {  
2937 - return subcom.get_name();  
2938 - }  
2939 - }  
2940 - if(!subc->get_name().empty()) {  
2941 - if(subcom.check_name(subc->get_name())) {  
2942 - return subc->get_name();  
2943 - }  
2944 - }  
2945 - for(const auto &les : subcom.aliases_) {  
2946 - if(subc->check_name(les)) {  
2947 - return les;  
2948 - }  
2949 - }  
2950 - // this loop is needed in case of ignore_underscore or ignore_case on one but not the other  
2951 - for(const auto &les : subc->aliases_) {  
2952 - if(subcom.check_name(les)) {  
2953 - return les;  
2954 - }  
2955 - }  
2956 - // if the subcommand is an option group we need to check deeper  
2957 - if(subc->get_name().empty()) {  
2958 - const auto &cmpres = _compare_subcommand_names(subcom, *subc);  
2959 - if(!cmpres.empty()) {  
2960 - return cmpres;  
2961 - }  
2962 - }  
2963 - // if the test subcommand is an option group we need to check deeper  
2964 - if(subcom.get_name().empty()) {  
2965 - const auto &cmpres = _compare_subcommand_names(*subc, subcom);  
2966 - if(!cmpres.empty()) {  
2967 - return cmpres;  
2968 - }  
2969 - }  
2970 - }  
2971 - }  
2972 - return estring;  
2973 - } 1272 + CLI11_NODISCARD const std::string &_compare_subcommand_names(const App &subcom, const App &base) const;
  1273 +
2974 /// Helper function to place extra values in the most appropriate position 1274 /// Helper function to place extra values in the most appropriate position
2975 - void _move_to_missing(detail::Classifier val_type, const std::string &val) {  
2976 - if(allow_extras_ || subcommands_.empty()) {  
2977 - missing_.emplace_back(val_type, val);  
2978 - return;  
2979 - }  
2980 - // allow extra arguments to be places in an option group if it is allowed there  
2981 - for(auto &subc : subcommands_) {  
2982 - if(subc->name_.empty() && subc->allow_extras_) {  
2983 - subc->missing_.emplace_back(val_type, val);  
2984 - return;  
2985 - }  
2986 - }  
2987 - // if we haven't found any place to put them yet put them in missing  
2988 - missing_.emplace_back(val_type, val);  
2989 - } 1275 + void _move_to_missing(detail::Classifier val_type, const std::string &val);
2990 1276
2991 public: 1277 public:
2992 /// function that could be used by subclasses of App to shift options around into subcommands 1278 /// function that could be used by subclasses of App to shift options around into subcommands
2993 - void _move_option(Option *opt, App *app) {  
2994 - if(opt == nullptr) {  
2995 - throw OptionNotFound("the option is NULL");  
2996 - }  
2997 - // verify that the give app is actually a subcommand  
2998 - bool found = false;  
2999 - for(auto &subc : subcommands_) {  
3000 - if(app == subc.get()) {  
3001 - found = true;  
3002 - }  
3003 - }  
3004 - if(!found) {  
3005 - throw OptionNotFound("The Given app is not a subcommand");  
3006 - }  
3007 -  
3008 - if((help_ptr_ == opt) || (help_all_ptr_ == opt))  
3009 - throw OptionAlreadyAdded("cannot move help options");  
3010 -  
3011 - if(config_ptr_ == opt)  
3012 - throw OptionAlreadyAdded("cannot move config file options");  
3013 -  
3014 - auto iterator =  
3015 - std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });  
3016 - if(iterator != std::end(options_)) {  
3017 - const auto &opt_p = *iterator;  
3018 - if(std::find_if(std::begin(app->options_), std::end(app->options_), [&opt_p](const Option_p &v) {  
3019 - return (*v == *opt_p);  
3020 - }) == std::end(app->options_)) {  
3021 - // only erase after the insertion was successful  
3022 - app->options_.push_back(std::move(*iterator));  
3023 - options_.erase(iterator);  
3024 - } else {  
3025 - throw OptionAlreadyAdded("option was not located: " + opt->get_name());  
3026 - }  
3027 - } else {  
3028 - throw OptionNotFound("could not locate the given Option");  
3029 - }  
3030 - } 1279 + void _move_option(Option *opt, App *app);
3031 }; // namespace CLI 1280 }; // namespace CLI
3032 1281
3033 /// Extension of App to better manage groups of options 1282 /// Extension of App to better manage groups of options
@@ -3063,62 +1312,21 @@ class Option_group : public App { @@ -3063,62 +1312,21 @@ class Option_group : public App {
3063 return subcom; 1312 return subcom;
3064 } 1313 }
3065 }; 1314 };
3066 -/// Helper function to enable one option group/subcommand when another is used  
3067 -inline void TriggerOn(App *trigger_app, App *app_to_enable) {  
3068 - app_to_enable->enabled_by_default(false);  
3069 - app_to_enable->disabled_by_default();  
3070 - trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(false); });  
3071 -}  
3072 1315
3073 /// Helper function to enable one option group/subcommand when another is used 1316 /// Helper function to enable one option group/subcommand when another is used
3074 -inline void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {  
3075 - for(auto &app : apps_to_enable) {  
3076 - app->enabled_by_default(false);  
3077 - app->disabled_by_default();  
3078 - } 1317 +CLI11_INLINE void TriggerOn(App *trigger_app, App *app_to_enable);
3079 1318
3080 - trigger_app->preparse_callback([apps_to_enable](std::size_t) {  
3081 - for(const auto &app : apps_to_enable) {  
3082 - app->disabled(false);  
3083 - }  
3084 - });  
3085 -} 1319 +/// Helper function to enable one option group/subcommand when another is used
  1320 +CLI11_INLINE void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable);
3086 1321
3087 /// Helper function to disable one option group/subcommand when another is used 1322 /// Helper function to disable one option group/subcommand when another is used
3088 -inline void TriggerOff(App *trigger_app, App *app_to_enable) {  
3089 - app_to_enable->disabled_by_default(false);  
3090 - app_to_enable->enabled_by_default();  
3091 - trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });  
3092 -} 1323 +CLI11_INLINE void TriggerOff(App *trigger_app, App *app_to_enable);
3093 1324
3094 /// Helper function to disable one option group/subcommand when another is used 1325 /// Helper function to disable one option group/subcommand when another is used
3095 -inline void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {  
3096 - for(auto &app : apps_to_enable) {  
3097 - app->disabled_by_default(false);  
3098 - app->enabled_by_default();  
3099 - }  
3100 -  
3101 - trigger_app->preparse_callback([apps_to_enable](std::size_t) {  
3102 - for(const auto &app : apps_to_enable) {  
3103 - app->disabled();  
3104 - }  
3105 - });  
3106 -} 1326 +CLI11_INLINE void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable);
3107 1327
3108 /// Helper function to mark an option as deprecated 1328 /// Helper function to mark an option as deprecated
3109 -inline void deprecate_option(Option *opt, const std::string &replacement = "") {  
3110 - Validator deprecate_warning{[opt, replacement](std::string &) {  
3111 - std::cout << opt->get_name() << " is deprecated please use '" << replacement  
3112 - << "' instead\n";  
3113 - return std::string();  
3114 - },  
3115 - "DEPRECATED"};  
3116 - deprecate_warning.application_index(0);  
3117 - opt->check(deprecate_warning);  
3118 - if(!replacement.empty()) {  
3119 - opt->description(opt->get_description() + " DEPRECATED: please use '" + replacement + "' instead");  
3120 - }  
3121 -} 1329 +CLI11_INLINE void deprecate_option(Option *opt, const std::string &replacement = "");
3122 1330
3123 /// Helper function to mark an option as deprecated 1331 /// Helper function to mark an option as deprecated
3124 inline void deprecate_option(App *app, const std::string &option_name, const std::string &replacement = "") { 1332 inline void deprecate_option(App *app, const std::string &option_name, const std::string &replacement = "") {
@@ -3133,84 +1341,24 @@ inline void deprecate_option(App &amp;app, const std::string &amp;option_name, const std @@ -3133,84 +1341,24 @@ inline void deprecate_option(App &amp;app, const std::string &amp;option_name, const std
3133 } 1341 }
3134 1342
3135 /// Helper function to mark an option as retired 1343 /// Helper function to mark an option as retired
3136 -inline void retire_option(App *app, Option *opt) {  
3137 - App temp;  
3138 - auto *option_copy = temp.add_option(opt->get_name(false, true))  
3139 - ->type_size(opt->get_type_size_min(), opt->get_type_size_max())  
3140 - ->expected(opt->get_expected_min(), opt->get_expected_max())  
3141 - ->allow_extra_args(opt->get_allow_extra_args());  
3142 -  
3143 - app->remove_option(opt);  
3144 - auto *opt2 = app->add_option(option_copy->get_name(false, true), "option has been retired and has no effect")  
3145 - ->type_name("RETIRED")  
3146 - ->default_str("RETIRED")  
3147 - ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())  
3148 - ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())  
3149 - ->allow_extra_args(option_copy->get_allow_extra_args());  
3150 -  
3151 - Validator retired_warning{[opt2](std::string &) {  
3152 - std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";  
3153 - return std::string();  
3154 - },  
3155 - ""};  
3156 - retired_warning.application_index(0);  
3157 - opt2->check(retired_warning);  
3158 -} 1344 +CLI11_INLINE void retire_option(App *app, Option *opt);
3159 1345
3160 /// Helper function to mark an option as retired 1346 /// Helper function to mark an option as retired
3161 -inline void retire_option(App &app, Option *opt) { retire_option(&app, opt); } 1347 +CLI11_INLINE void retire_option(App &app, Option *opt);
3162 1348
3163 /// Helper function to mark an option as retired 1349 /// Helper function to mark an option as retired
3164 -inline void retire_option(App *app, const std::string &option_name) {  
3165 -  
3166 - auto *opt = app->get_option_no_throw(option_name);  
3167 - if(opt != nullptr) {  
3168 - retire_option(app, opt);  
3169 - return;  
3170 - }  
3171 - auto *opt2 = app->add_option(option_name, "option has been retired and has no effect")  
3172 - ->type_name("RETIRED")  
3173 - ->expected(0, 1)  
3174 - ->default_str("RETIRED");  
3175 - Validator retired_warning{[opt2](std::string &) {  
3176 - std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";  
3177 - return std::string();  
3178 - },  
3179 - ""};  
3180 - retired_warning.application_index(0);  
3181 - opt2->check(retired_warning);  
3182 -} 1350 +CLI11_INLINE void retire_option(App *app, const std::string &option_name);
3183 1351
3184 /// Helper function to mark an option as retired 1352 /// Helper function to mark an option as retired
3185 -inline void retire_option(App &app, const std::string &option_name) { retire_option(&app, option_name); } 1353 +CLI11_INLINE void retire_option(App &app, const std::string &option_name);
3186 1354
3187 namespace FailureMessage { 1355 namespace FailureMessage {
3188 1356
3189 /// Printout a clean, simple message on error (the default in CLI11 1.5+) 1357 /// Printout a clean, simple message on error (the default in CLI11 1.5+)
3190 -inline std::string simple(const App *app, const Error &e) {  
3191 - std::string header = std::string(e.what()) + "\n";  
3192 - std::vector<std::string> names;  
3193 -  
3194 - // Collect names  
3195 - if(app->get_help_ptr() != nullptr)  
3196 - names.push_back(app->get_help_ptr()->get_name());  
3197 -  
3198 - if(app->get_help_all_ptr() != nullptr)  
3199 - names.push_back(app->get_help_all_ptr()->get_name());  
3200 -  
3201 - // If any names found, suggest those  
3202 - if(!names.empty())  
3203 - header += "Run with " + detail::join(names, " or ") + " for more information.\n";  
3204 -  
3205 - return header;  
3206 -} 1358 +CLI11_INLINE std::string simple(const App *app, const Error &e);
3207 1359
3208 /// Printout the full help string on error (if this fn is set, the old default for CLI11) 1360 /// Printout the full help string on error (if this fn is set, the old default for CLI11)
3209 -inline std::string help(const App *app, const Error &e) {  
3210 - std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";  
3211 - header += app->help();  
3212 - return header;  
3213 -} 1361 +CLI11_INLINE std::string help(const App *app, const Error &e);
3214 1362
3215 } // namespace FailureMessage 1363 } // namespace FailureMessage
3216 1364
@@ -3250,3 +1398,7 @@ struct AppFriend { @@ -3250,3 +1398,7 @@ struct AppFriend {
3250 1398
3251 // [CLI11:app_hpp:end] 1399 // [CLI11:app_hpp:end]
3252 } // namespace CLI 1400 } // namespace CLI
  1401 +
  1402 +#ifndef CLI11_COMPILE
  1403 +#include "impl/App_inl.hpp"
  1404 +#endif
include/CLI/Macros.hpp
@@ -65,4 +65,11 @@ @@ -65,4 +65,11 @@
65 #define CLI11_USE_STATIC_RTTI 1 65 #define CLI11_USE_STATIC_RTTI 1
66 #endif 66 #endif
67 #endif 67 #endif
  68 +
  69 +/** Inline macro **/
  70 +#ifdef CLI11_COMPILE
  71 +#define CLI11_INLINE
  72 +#else
  73 +#define CLI11_INLINE inline
  74 +#endif
68 // [CLI11:macros_hpp:end] 75 // [CLI11:macros_hpp:end]
include/CLI/impl/App_inl.hpp 0 → 100644
  1 +// Copyright (c) 2017-2022, 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 +// This include is only needed for IDEs to discover symbols
  10 +#include <CLI/App.hpp>
  11 +
  12 +// [CLI11:public_includes:set]
  13 +#include <algorithm>
  14 +#include <memory>
  15 +#include <string>
  16 +#include <utility>
  17 +#include <vector>
  18 +// [CLI11:public_includes:end]
  19 +
  20 +namespace CLI {
  21 +// [CLI11:app_inl_hpp:verbatim]
  22 +
  23 +CLI11_INLINE App::App(std::string app_description, std::string app_name, App *parent)
  24 + : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {
  25 + // Inherit if not from a nullptr
  26 + if(parent_ != nullptr) {
  27 + if(parent_->help_ptr_ != nullptr)
  28 + set_help_flag(parent_->help_ptr_->get_name(false, true), parent_->help_ptr_->get_description());
  29 + if(parent_->help_all_ptr_ != nullptr)
  30 + set_help_all_flag(parent_->help_all_ptr_->get_name(false, true), parent_->help_all_ptr_->get_description());
  31 +
  32 + /// OptionDefaults
  33 + option_defaults_ = parent_->option_defaults_;
  34 +
  35 + // INHERITABLE
  36 + failure_message_ = parent_->failure_message_;
  37 + allow_extras_ = parent_->allow_extras_;
  38 + allow_config_extras_ = parent_->allow_config_extras_;
  39 + prefix_command_ = parent_->prefix_command_;
  40 + immediate_callback_ = parent_->immediate_callback_;
  41 + ignore_case_ = parent_->ignore_case_;
  42 + ignore_underscore_ = parent_->ignore_underscore_;
  43 + fallthrough_ = parent_->fallthrough_;
  44 + validate_positionals_ = parent_->validate_positionals_;
  45 + validate_optional_arguments_ = parent_->validate_optional_arguments_;
  46 + configurable_ = parent_->configurable_;
  47 + allow_windows_style_options_ = parent_->allow_windows_style_options_;
  48 + group_ = parent_->group_;
  49 + footer_ = parent_->footer_;
  50 + formatter_ = parent_->formatter_;
  51 + config_formatter_ = parent_->config_formatter_;
  52 + require_subcommand_max_ = parent_->require_subcommand_max_;
  53 + }
  54 +}
  55 +
  56 +CLI11_INLINE App *App::name(std::string app_name) {
  57 +
  58 + if(parent_ != nullptr) {
  59 + auto oname = name_;
  60 + name_ = app_name;
  61 + const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
  62 + if(!res.empty()) {
  63 + name_ = oname;
  64 + throw(OptionAlreadyAdded(app_name + " conflicts with existing subcommand names"));
  65 + }
  66 + } else {
  67 + name_ = app_name;
  68 + }
  69 + has_automatic_name_ = false;
  70 + return this;
  71 +}
  72 +
  73 +CLI11_INLINE App *App::alias(std::string app_name) {
  74 + if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {
  75 + throw IncorrectConstruction("Aliases may not be empty or contain newlines or null characters");
  76 + }
  77 + if(parent_ != nullptr) {
  78 + aliases_.push_back(app_name);
  79 + const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
  80 + if(!res.empty()) {
  81 + aliases_.pop_back();
  82 + throw(OptionAlreadyAdded("alias already matches an existing subcommand: " + app_name));
  83 + }
  84 + } else {
  85 + aliases_.push_back(app_name);
  86 + }
  87 +
  88 + return this;
  89 +}
  90 +
  91 +CLI11_INLINE App *App::immediate_callback(bool immediate) {
  92 + immediate_callback_ = immediate;
  93 + if(immediate_callback_) {
  94 + if(final_callback_ && !(parse_complete_callback_)) {
  95 + std::swap(final_callback_, parse_complete_callback_);
  96 + }
  97 + } else if(!(final_callback_) && parse_complete_callback_) {
  98 + std::swap(final_callback_, parse_complete_callback_);
  99 + }
  100 + return this;
  101 +}
  102 +
  103 +CLI11_INLINE App *App::ignore_case(bool value) {
  104 + if(value && !ignore_case_) {
  105 + ignore_case_ = true;
  106 + auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
  107 + const auto &match = _compare_subcommand_names(*this, *p);
  108 + if(!match.empty()) {
  109 + ignore_case_ = false; // we are throwing so need to be exception invariant
  110 + throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);
  111 + }
  112 + }
  113 + ignore_case_ = value;
  114 + return this;
  115 +}
  116 +
  117 +CLI11_INLINE App *App::ignore_underscore(bool value) {
  118 + if(value && !ignore_underscore_) {
  119 + ignore_underscore_ = true;
  120 + auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
  121 + const auto &match = _compare_subcommand_names(*this, *p);
  122 + if(!match.empty()) {
  123 + ignore_underscore_ = false;
  124 + throw OptionAlreadyAdded("ignore underscore would cause subcommand name conflicts: " + match);
  125 + }
  126 + }
  127 + ignore_underscore_ = value;
  128 + return this;
  129 +}
  130 +
  131 +CLI11_INLINE Option *App::add_option(std::string option_name,
  132 + callback_t option_callback,
  133 + std::string option_description,
  134 + bool defaulted,
  135 + std::function<std::string()> func) {
  136 + Option myopt{option_name, option_description, option_callback, this};
  137 +
  138 + if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) { return *v == myopt; }) ==
  139 + std::end(options_)) {
  140 + options_.emplace_back();
  141 + Option_p &option = options_.back();
  142 + option.reset(new Option(option_name, option_description, option_callback, this));
  143 +
  144 + // Set the default string capture function
  145 + option->default_function(func);
  146 +
  147 + // For compatibility with CLI11 1.7 and before, capture the default string here
  148 + if(defaulted)
  149 + option->capture_default_str();
  150 +
  151 + // Transfer defaults to the new option
  152 + option_defaults_.copy_to(option.get());
  153 +
  154 + // Don't bother to capture if we already did
  155 + if(!defaulted && option->get_always_capture_default())
  156 + option->capture_default_str();
  157 +
  158 + return option.get();
  159 + }
  160 + // we know something matches now find what it is so we can produce more error information
  161 + for(auto &opt : options_) {
  162 + const auto &matchname = opt->matching_name(myopt);
  163 + if(!matchname.empty()) {
  164 + throw(OptionAlreadyAdded("added option matched existing option name: " + matchname));
  165 + }
  166 + }
  167 + // this line should not be reached the above loop should trigger the throw
  168 + throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE
  169 +}
  170 +
  171 +CLI11_INLINE Option *App::set_help_flag(std::string flag_name, const std::string &help_description) {
  172 + // take flag_description by const reference otherwise add_flag tries to assign to help_description
  173 + if(help_ptr_ != nullptr) {
  174 + remove_option(help_ptr_);
  175 + help_ptr_ = nullptr;
  176 + }
  177 +
  178 + // Empty name will simply remove the help flag
  179 + if(!flag_name.empty()) {
  180 + help_ptr_ = add_flag(flag_name, help_description);
  181 + help_ptr_->configurable(false);
  182 + }
  183 +
  184 + return help_ptr_;
  185 +}
  186 +
  187 +CLI11_INLINE Option *App::set_help_all_flag(std::string help_name, const std::string &help_description) {
  188 + // take flag_description by const reference otherwise add_flag tries to assign to flag_description
  189 + if(help_all_ptr_ != nullptr) {
  190 + remove_option(help_all_ptr_);
  191 + help_all_ptr_ = nullptr;
  192 + }
  193 +
  194 + // Empty name will simply remove the help all flag
  195 + if(!help_name.empty()) {
  196 + help_all_ptr_ = add_flag(help_name, help_description);
  197 + help_all_ptr_->configurable(false);
  198 + }
  199 +
  200 + return help_all_ptr_;
  201 +}
  202 +
  203 +CLI11_INLINE Option *
  204 +App::set_version_flag(std::string flag_name, const std::string &versionString, const std::string &version_help) {
  205 + // take flag_description by const reference otherwise add_flag tries to assign to version_description
  206 + if(version_ptr_ != nullptr) {
  207 + remove_option(version_ptr_);
  208 + version_ptr_ = nullptr;
  209 + }
  210 +
  211 + // Empty name will simply remove the version flag
  212 + if(!flag_name.empty()) {
  213 + version_ptr_ = add_flag_callback(
  214 + flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);
  215 + version_ptr_->configurable(false);
  216 + }
  217 +
  218 + return version_ptr_;
  219 +}
  220 +
  221 +CLI11_INLINE Option *
  222 +App::set_version_flag(std::string flag_name, std::function<std::string()> vfunc, const std::string &version_help) {
  223 + if(version_ptr_ != nullptr) {
  224 + remove_option(version_ptr_);
  225 + version_ptr_ = nullptr;
  226 + }
  227 +
  228 + // Empty name will simply remove the version flag
  229 + if(!flag_name.empty()) {
  230 + version_ptr_ = add_flag_callback(
  231 + flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);
  232 + version_ptr_->configurable(false);
  233 + }
  234 +
  235 + return version_ptr_;
  236 +}
  237 +
  238 +CLI11_INLINE Option *App::_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
  239 + Option *opt = nullptr;
  240 + if(detail::has_default_flag_values(flag_name)) {
  241 + // check for default values and if it has them
  242 + auto flag_defaults = detail::get_default_flag_values(flag_name);
  243 + detail::remove_default_flag_values(flag_name);
  244 + opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
  245 + for(const auto &fname : flag_defaults)
  246 + opt->fnames_.push_back(fname.first);
  247 + opt->default_flag_values_ = std::move(flag_defaults);
  248 + } else {
  249 + opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
  250 + }
  251 + // flags cannot have positional values
  252 + if(opt->get_positional()) {
  253 + auto pos_name = opt->get_name(true);
  254 + remove_option(opt);
  255 + throw IncorrectConstruction::PositionalFlag(pos_name);
  256 + }
  257 + opt->multi_option_policy(MultiOptionPolicy::TakeLast);
  258 + opt->expected(0);
  259 + opt->required(false);
  260 + return opt;
  261 +}
  262 +
  263 +CLI11_INLINE Option *App::add_flag_callback(std::string flag_name,
  264 + std::function<void(void)> function, ///< A function to call, void(void)
  265 + std::string flag_description) {
  266 +
  267 + CLI::callback_t fun = [function](const CLI::results_t &res) {
  268 + bool trigger{false};
  269 + auto result = CLI::detail::lexical_cast(res[0], trigger);
  270 + if(result && trigger) {
  271 + function();
  272 + }
  273 + return result;
  274 + };
  275 + return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
  276 +}
  277 +
  278 +CLI11_INLINE Option *
  279 +App::add_flag_function(std::string flag_name,
  280 + std::function<void(std::int64_t)> function, ///< A function to call, void(int)
  281 + std::string flag_description) {
  282 +
  283 + CLI::callback_t fun = [function](const CLI::results_t &res) {
  284 + std::int64_t flag_count{0};
  285 + CLI::detail::lexical_cast(res[0], flag_count);
  286 + function(flag_count);
  287 + return true;
  288 + };
  289 + return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
  290 + ->multi_option_policy(MultiOptionPolicy::Sum);
  291 +}
  292 +
  293 +CLI11_INLINE Option *App::set_config(std::string option_name,
  294 + std::string default_filename,
  295 + const std::string &help_message,
  296 + bool config_required) {
  297 +
  298 + // Remove existing config if present
  299 + if(config_ptr_ != nullptr) {
  300 + remove_option(config_ptr_);
  301 + config_ptr_ = nullptr; // need to remove the config_ptr completely
  302 + }
  303 +
  304 + // Only add config if option passed
  305 + if(!option_name.empty()) {
  306 + config_ptr_ = add_option(option_name, help_message);
  307 + if(config_required) {
  308 + config_ptr_->required();
  309 + }
  310 + if(!default_filename.empty()) {
  311 + config_ptr_->default_str(std::move(default_filename));
  312 + }
  313 + config_ptr_->configurable(false);
  314 + }
  315 +
  316 + return config_ptr_;
  317 +}
  318 +
  319 +CLI11_INLINE bool App::remove_option(Option *opt) {
  320 + // Make sure no links exist
  321 + for(Option_p &op : options_) {
  322 + op->remove_needs(opt);
  323 + op->remove_excludes(opt);
  324 + }
  325 +
  326 + if(help_ptr_ == opt)
  327 + help_ptr_ = nullptr;
  328 + if(help_all_ptr_ == opt)
  329 + help_all_ptr_ = nullptr;
  330 +
  331 + auto iterator =
  332 + std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
  333 + if(iterator != std::end(options_)) {
  334 + options_.erase(iterator);
  335 + return true;
  336 + }
  337 + return false;
  338 +}
  339 +
  340 +CLI11_INLINE App *App::add_subcommand(std::string subcommand_name, std::string subcommand_description) {
  341 + if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
  342 + if(!detail::valid_first_char(subcommand_name[0])) {
  343 + throw IncorrectConstruction("Subcommand name starts with invalid character, '!' and '-' are not allowed");
  344 + }
  345 + for(auto c : subcommand_name) {
  346 + if(!detail::valid_later_char(c)) {
  347 + throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
  348 + "'), all characters are allowed except"
  349 + "'=',':','{','}', and ' '");
  350 + }
  351 + }
  352 + }
  353 + CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));
  354 + return add_subcommand(std::move(subcom));
  355 +}
  356 +
  357 +CLI11_INLINE App *App::add_subcommand(CLI::App_p subcom) {
  358 + if(!subcom)
  359 + throw IncorrectConstruction("passed App is not valid");
  360 + auto *ckapp = (name_.empty() && parent_ != nullptr) ? _get_fallthrough_parent() : this;
  361 + const auto &mstrg = _compare_subcommand_names(*subcom, *ckapp);
  362 + if(!mstrg.empty()) {
  363 + throw(OptionAlreadyAdded("subcommand name or alias matches existing subcommand: " + mstrg));
  364 + }
  365 + subcom->parent_ = this;
  366 + subcommands_.push_back(std::move(subcom));
  367 + return subcommands_.back().get();
  368 +}
  369 +
  370 +CLI11_INLINE bool App::remove_subcommand(App *subcom) {
  371 + // Make sure no links exist
  372 + for(App_p &sub : subcommands_) {
  373 + sub->remove_excludes(subcom);
  374 + sub->remove_needs(subcom);
  375 + }
  376 +
  377 + auto iterator = std::find_if(
  378 + std::begin(subcommands_), std::end(subcommands_), [subcom](const App_p &v) { return v.get() == subcom; });
  379 + if(iterator != std::end(subcommands_)) {
  380 + subcommands_.erase(iterator);
  381 + return true;
  382 + }
  383 + return false;
  384 +}
  385 +
  386 +CLI11_INLINE App *App::get_subcommand(const App *subcom) const {
  387 + if(subcom == nullptr)
  388 + throw OptionNotFound("nullptr passed");
  389 + for(const App_p &subcomptr : subcommands_)
  390 + if(subcomptr.get() == subcom)
  391 + return subcomptr.get();
  392 + throw OptionNotFound(subcom->get_name());
  393 +}
  394 +
  395 +CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(std::string subcom) const {
  396 + auto *subc = _find_subcommand(subcom, false, false);
  397 + if(subc == nullptr)
  398 + throw OptionNotFound(subcom);
  399 + return subc;
  400 +}
  401 +
  402 +CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(int index) const {
  403 + if(index >= 0) {
  404 + auto uindex = static_cast<unsigned>(index);
  405 + if(uindex < subcommands_.size())
  406 + return subcommands_[uindex].get();
  407 + }
  408 + throw OptionNotFound(std::to_string(index));
  409 +}
  410 +
  411 +CLI11_INLINE CLI::App_p App::get_subcommand_ptr(App *subcom) const {
  412 + if(subcom == nullptr)
  413 + throw OptionNotFound("nullptr passed");
  414 + for(const App_p &subcomptr : subcommands_)
  415 + if(subcomptr.get() == subcom)
  416 + return subcomptr;
  417 + throw OptionNotFound(subcom->get_name());
  418 +}
  419 +
  420 +CLI11_NODISCARD CLI11_INLINE CLI::App_p App::get_subcommand_ptr(std::string subcom) const {
  421 + for(const App_p &subcomptr : subcommands_)
  422 + if(subcomptr->check_name(subcom))
  423 + return subcomptr;
  424 + throw OptionNotFound(subcom);
  425 +}
  426 +
  427 +CLI11_NODISCARD CLI11_INLINE CLI::App_p App::get_subcommand_ptr(int index) const {
  428 + if(index >= 0) {
  429 + auto uindex = static_cast<unsigned>(index);
  430 + if(uindex < subcommands_.size())
  431 + return subcommands_[uindex];
  432 + }
  433 + throw OptionNotFound(std::to_string(index));
  434 +}
  435 +
  436 +CLI11_NODISCARD CLI11_INLINE std::size_t App::count_all() const {
  437 + std::size_t cnt{0};
  438 + for(const auto &opt : options_) {
  439 + cnt += opt->count();
  440 + }
  441 + for(const auto &sub : subcommands_) {
  442 + cnt += sub->count_all();
  443 + }
  444 + if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
  445 + cnt += parsed_;
  446 + }
  447 + return cnt;
  448 +}
  449 +
  450 +CLI11_INLINE void App::clear() {
  451 +
  452 + parsed_ = 0;
  453 + pre_parse_called_ = false;
  454 +
  455 + missing_.clear();
  456 + parsed_subcommands_.clear();
  457 + for(const Option_p &opt : options_) {
  458 + opt->clear();
  459 + }
  460 + for(const App_p &subc : subcommands_) {
  461 + subc->clear();
  462 + }
  463 +}
  464 +
  465 +CLI11_INLINE void App::parse(int argc, const char *const *argv) {
  466 + // If the name is not set, read from command line
  467 + if(name_.empty() || has_automatic_name_) {
  468 + has_automatic_name_ = true;
  469 + name_ = argv[0];
  470 + }
  471 +
  472 + std::vector<std::string> args;
  473 + args.reserve(static_cast<std::size_t>(argc) - 1U);
  474 + for(auto i = static_cast<std::size_t>(argc) - 1U; i > 0U; --i)
  475 + args.emplace_back(argv[i]);
  476 + parse(std::move(args));
  477 +}
  478 +
  479 +CLI11_INLINE void App::parse(std::string commandline, bool program_name_included) {
  480 +
  481 + if(program_name_included) {
  482 + auto nstr = detail::split_program_name(commandline);
  483 + if((name_.empty()) || (has_automatic_name_)) {
  484 + has_automatic_name_ = true;
  485 + name_ = nstr.first;
  486 + }
  487 + commandline = std::move(nstr.second);
  488 + } else {
  489 + detail::trim(commandline);
  490 + }
  491 + // the next section of code is to deal with quoted arguments after an '=' or ':' for windows like operations
  492 + if(!commandline.empty()) {
  493 + commandline = detail::find_and_modify(commandline, "=", detail::escape_detect);
  494 + if(allow_windows_style_options_)
  495 + commandline = detail::find_and_modify(commandline, ":", detail::escape_detect);
  496 + }
  497 +
  498 + auto args = detail::split_up(std::move(commandline));
  499 + // remove all empty strings
  500 + args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
  501 + std::reverse(args.begin(), args.end());
  502 +
  503 + parse(std::move(args));
  504 +}
  505 +
  506 +CLI11_INLINE void App::parse(std::vector<std::string> &args) {
  507 + // Clear if parsed
  508 + if(parsed_ > 0)
  509 + clear();
  510 +
  511 + // parsed_ is incremented in commands/subcommands,
  512 + // but placed here to make sure this is cleared when
  513 + // running parse after an error is thrown, even by _validate or _configure.
  514 + parsed_ = 1;
  515 + _validate();
  516 + _configure();
  517 + // set the parent as nullptr as this object should be the top now
  518 + parent_ = nullptr;
  519 + parsed_ = 0;
  520 +
  521 + _parse(args);
  522 + run_callback();
  523 +}
  524 +
  525 +CLI11_INLINE void App::parse(std::vector<std::string> &&args) {
  526 + // Clear if parsed
  527 + if(parsed_ > 0)
  528 + clear();
  529 +
  530 + // parsed_ is incremented in commands/subcommands,
  531 + // but placed here to make sure this is cleared when
  532 + // running parse after an error is thrown, even by _validate or _configure.
  533 + parsed_ = 1;
  534 + _validate();
  535 + _configure();
  536 + // set the parent as nullptr as this object should be the top now
  537 + parent_ = nullptr;
  538 + parsed_ = 0;
  539 +
  540 + _parse(std::move(args));
  541 + run_callback();
  542 +}
  543 +
  544 +CLI11_INLINE void App::parse_from_stream(std::istream &input) {
  545 + if(parsed_ == 0) {
  546 + _validate();
  547 + _configure();
  548 + // set the parent as nullptr as this object should be the top now
  549 + }
  550 +
  551 + _parse_stream(input);
  552 + run_callback();
  553 +}
  554 +
  555 +CLI11_INLINE int App::exit(const Error &e, std::ostream &out, std::ostream &err) const {
  556 +
  557 + /// Avoid printing anything if this is a CLI::RuntimeError
  558 + if(e.get_name() == "RuntimeError")
  559 + return e.get_exit_code();
  560 +
  561 + if(e.get_name() == "CallForHelp") {
  562 + out << help();
  563 + return e.get_exit_code();
  564 + }
  565 +
  566 + if(e.get_name() == "CallForAllHelp") {
  567 + out << help("", AppFormatMode::All);
  568 + return e.get_exit_code();
  569 + }
  570 +
  571 + if(e.get_name() == "CallForVersion") {
  572 + out << e.what() << std::endl;
  573 + return e.get_exit_code();
  574 + }
  575 +
  576 + if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
  577 + if(failure_message_)
  578 + err << failure_message_(this, e) << std::flush;
  579 + }
  580 +
  581 + return e.get_exit_code();
  582 +}
  583 +
  584 +CLI11_INLINE std::vector<const App *> App::get_subcommands(const std::function<bool(const App *)> &filter) const {
  585 + std::vector<const App *> subcomms(subcommands_.size());
  586 + std::transform(
  587 + std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) { return v.get(); });
  588 +
  589 + if(filter) {
  590 + subcomms.erase(std::remove_if(std::begin(subcomms),
  591 + std::end(subcomms),
  592 + [&filter](const App *app) { return !filter(app); }),
  593 + std::end(subcomms));
  594 + }
  595 +
  596 + return subcomms;
  597 +}
  598 +
  599 +CLI11_INLINE std::vector<App *> App::get_subcommands(const std::function<bool(App *)> &filter) {
  600 + std::vector<App *> subcomms(subcommands_.size());
  601 + std::transform(
  602 + std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) { return v.get(); });
  603 +
  604 + if(filter) {
  605 + subcomms.erase(
  606 + std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *app) { return !filter(app); }),
  607 + std::end(subcomms));
  608 + }
  609 +
  610 + return subcomms;
  611 +}
  612 +
  613 +CLI11_INLINE bool App::remove_excludes(Option *opt) {
  614 + auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);
  615 + if(iterator == std::end(exclude_options_)) {
  616 + return false;
  617 + }
  618 + exclude_options_.erase(iterator);
  619 + return true;
  620 +}
  621 +
  622 +CLI11_INLINE bool App::remove_excludes(App *app) {
  623 + auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);
  624 + if(iterator == std::end(exclude_subcommands_)) {
  625 + return false;
  626 + }
  627 + auto *other_app = *iterator;
  628 + exclude_subcommands_.erase(iterator);
  629 + other_app->remove_excludes(this);
  630 + return true;
  631 +}
  632 +
  633 +CLI11_INLINE bool App::remove_needs(Option *opt) {
  634 + auto iterator = std::find(std::begin(need_options_), std::end(need_options_), opt);
  635 + if(iterator == std::end(need_options_)) {
  636 + return false;
  637 + }
  638 + need_options_.erase(iterator);
  639 + return true;
  640 +}
  641 +
  642 +CLI11_INLINE bool App::remove_needs(App *app) {
  643 + auto iterator = std::find(std::begin(need_subcommands_), std::end(need_subcommands_), app);
  644 + if(iterator == std::end(need_subcommands_)) {
  645 + return false;
  646 + }
  647 + need_subcommands_.erase(iterator);
  648 + return true;
  649 +}
  650 +
  651 +CLI11_NODISCARD CLI11_INLINE std::string App::help(std::string prev, AppFormatMode mode) const {
  652 + if(prev.empty())
  653 + prev = get_name();
  654 + else
  655 + prev += " " + get_name();
  656 +
  657 + // Delegate to subcommand if needed
  658 + auto selected_subcommands = get_subcommands();
  659 + if(!selected_subcommands.empty()) {
  660 + return selected_subcommands.at(0)->help(prev, mode);
  661 + }
  662 + return formatter_->make_help(this, prev, mode);
  663 +}
  664 +
  665 +CLI11_NODISCARD CLI11_INLINE std::string App::version() const {
  666 + std::string val;
  667 + if(version_ptr_ != nullptr) {
  668 + auto rv = version_ptr_->results();
  669 + version_ptr_->clear();
  670 + version_ptr_->add_result("true");
  671 + try {
  672 + version_ptr_->run_callback();
  673 + } catch(const CLI::CallForVersion &cfv) {
  674 + val = cfv.what();
  675 + }
  676 + version_ptr_->clear();
  677 + version_ptr_->add_result(rv);
  678 + }
  679 + return val;
  680 +}
  681 +
  682 +CLI11_INLINE std::vector<const Option *> App::get_options(const std::function<bool(const Option *)> filter) const {
  683 + std::vector<const Option *> options(options_.size());
  684 + std::transform(
  685 + std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) { return val.get(); });
  686 +
  687 + if(filter) {
  688 + options.erase(std::remove_if(std::begin(options),
  689 + std::end(options),
  690 + [&filter](const Option *opt) { return !filter(opt); }),
  691 + std::end(options));
  692 + }
  693 +
  694 + return options;
  695 +}
  696 +
  697 +CLI11_INLINE std::vector<Option *> App::get_options(const std::function<bool(Option *)> filter) {
  698 + std::vector<Option *> options(options_.size());
  699 + std::transform(
  700 + std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) { return val.get(); });
  701 +
  702 + if(filter) {
  703 + options.erase(
  704 + std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) { return !filter(opt); }),
  705 + std::end(options));
  706 + }
  707 +
  708 + return options;
  709 +}
  710 +
  711 +CLI11_INLINE Option *App::get_option_no_throw(std::string option_name) noexcept {
  712 + for(Option_p &opt : options_) {
  713 + if(opt->check_name(option_name)) {
  714 + return opt.get();
  715 + }
  716 + }
  717 + for(auto &subc : subcommands_) {
  718 + // also check down into nameless subcommands
  719 + if(subc->get_name().empty()) {
  720 + auto *opt = subc->get_option_no_throw(option_name);
  721 + if(opt != nullptr) {
  722 + return opt;
  723 + }
  724 + }
  725 + }
  726 + return nullptr;
  727 +}
  728 +
  729 +CLI11_NODISCARD CLI11_INLINE const Option *App::get_option_no_throw(std::string option_name) const noexcept {
  730 + for(const Option_p &opt : options_) {
  731 + if(opt->check_name(option_name)) {
  732 + return opt.get();
  733 + }
  734 + }
  735 + for(const auto &subc : subcommands_) {
  736 + // also check down into nameless subcommands
  737 + if(subc->get_name().empty()) {
  738 + auto *opt = subc->get_option_no_throw(option_name);
  739 + if(opt != nullptr) {
  740 + return opt;
  741 + }
  742 + }
  743 + }
  744 + return nullptr;
  745 +}
  746 +
  747 +CLI11_NODISCARD CLI11_INLINE std::string App::get_display_name(bool with_aliases) const {
  748 + if(name_.empty()) {
  749 + return std::string("[Option Group: ") + get_group() + "]";
  750 + }
  751 + if(aliases_.empty() || !with_aliases) {
  752 + return name_;
  753 + }
  754 + std::string dispname = name_;
  755 + for(const auto &lalias : aliases_) {
  756 + dispname.push_back(',');
  757 + dispname.push_back(' ');
  758 + dispname.append(lalias);
  759 + }
  760 + return dispname;
  761 +}
  762 +
  763 +CLI11_NODISCARD CLI11_INLINE bool App::check_name(std::string name_to_check) const {
  764 + std::string local_name = name_;
  765 + if(ignore_underscore_) {
  766 + local_name = detail::remove_underscore(name_);
  767 + name_to_check = detail::remove_underscore(name_to_check);
  768 + }
  769 + if(ignore_case_) {
  770 + local_name = detail::to_lower(name_);
  771 + name_to_check = detail::to_lower(name_to_check);
  772 + }
  773 +
  774 + if(local_name == name_to_check) {
  775 + return true;
  776 + }
  777 + for(auto les : aliases_) { // NOLINT(performance-for-range-copy)
  778 + if(ignore_underscore_) {
  779 + les = detail::remove_underscore(les);
  780 + }
  781 + if(ignore_case_) {
  782 + les = detail::to_lower(les);
  783 + }
  784 + if(les == name_to_check) {
  785 + return true;
  786 + }
  787 + }
  788 + return false;
  789 +}
  790 +
  791 +CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::get_groups() const {
  792 + std::vector<std::string> groups;
  793 +
  794 + for(const Option_p &opt : options_) {
  795 + // Add group if it is not already in there
  796 + if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
  797 + groups.push_back(opt->get_group());
  798 + }
  799 + }
  800 +
  801 + return groups;
  802 +}
  803 +
  804 +CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::remaining(bool recurse) const {
  805 + std::vector<std::string> miss_list;
  806 + for(const std::pair<detail::Classifier, std::string> &miss : missing_) {
  807 + miss_list.push_back(std::get<1>(miss));
  808 + }
  809 + // Get from a subcommand that may allow extras
  810 + if(recurse) {
  811 + if(!allow_extras_) {
  812 + for(const auto &sub : subcommands_) {
  813 + if(sub->name_.empty() && !sub->missing_.empty()) {
  814 + for(const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
  815 + miss_list.push_back(std::get<1>(miss));
  816 + }
  817 + }
  818 + }
  819 + }
  820 + // Recurse into subcommands
  821 +
  822 + for(const App *sub : parsed_subcommands_) {
  823 + std::vector<std::string> output = sub->remaining(recurse);
  824 + std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
  825 + }
  826 + }
  827 + return miss_list;
  828 +}
  829 +
  830 +CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::remaining_for_passthrough(bool recurse) const {
  831 + std::vector<std::string> miss_list = remaining(recurse);
  832 + std::reverse(std::begin(miss_list), std::end(miss_list));
  833 + return miss_list;
  834 +}
  835 +
  836 +CLI11_NODISCARD CLI11_INLINE std::size_t App::remaining_size(bool recurse) const {
  837 + auto remaining_options = static_cast<std::size_t>(std::count_if(
  838 + std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifier, std::string> &val) {
  839 + return val.first != detail::Classifier::POSITIONAL_MARK;
  840 + }));
  841 +
  842 + if(recurse) {
  843 + for(const App_p &sub : subcommands_) {
  844 + remaining_options += sub->remaining_size(recurse);
  845 + }
  846 + }
  847 + return remaining_options;
  848 +}
  849 +
  850 +CLI11_INLINE void App::_validate() const {
  851 + // count the number of positional only args
  852 + auto pcount = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
  853 + return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
  854 + });
  855 + if(pcount > 1) {
  856 + auto pcount_req = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
  857 + return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
  858 + opt->get_required();
  859 + });
  860 + if(pcount - pcount_req > 1) {
  861 + throw InvalidError(name_);
  862 + }
  863 + }
  864 +
  865 + std::size_t nameless_subs{0};
  866 + for(const App_p &app : subcommands_) {
  867 + app->_validate();
  868 + if(app->get_name().empty())
  869 + ++nameless_subs;
  870 + }
  871 +
  872 + if(require_option_min_ > 0) {
  873 + if(require_option_max_ > 0) {
  874 + if(require_option_max_ < require_option_min_) {
  875 + throw(InvalidError("Required min options greater than required max options", ExitCodes::InvalidError));
  876 + }
  877 + }
  878 + if(require_option_min_ > (options_.size() + nameless_subs)) {
  879 + throw(
  880 + InvalidError("Required min options greater than number of available options", ExitCodes::InvalidError));
  881 + }
  882 + }
  883 +}
  884 +
  885 +CLI11_INLINE void App::_configure() {
  886 + if(default_startup == startup_mode::enabled) {
  887 + disabled_ = false;
  888 + } else if(default_startup == startup_mode::disabled) {
  889 + disabled_ = true;
  890 + }
  891 + for(const App_p &app : subcommands_) {
  892 + if(app->has_automatic_name_) {
  893 + app->name_.clear();
  894 + }
  895 + if(app->name_.empty()) {
  896 + app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
  897 + app->prefix_command_ = false;
  898 + }
  899 + // make sure the parent is set to be this object in preparation for parse
  900 + app->parent_ = this;
  901 + app->_configure();
  902 + }
  903 +}
  904 +
  905 +CLI11_INLINE void App::run_callback(bool final_mode, bool suppress_final_callback) {
  906 + pre_callback();
  907 + // in the main app if immediate_callback_ is set it runs the main callback before the used subcommands
  908 + if(!final_mode && parse_complete_callback_) {
  909 + parse_complete_callback_();
  910 + }
  911 + // run the callbacks for the received subcommands
  912 + for(App *subc : get_subcommands()) {
  913 + if(subc->parent_ == this) {
  914 + subc->run_callback(true, suppress_final_callback);
  915 + }
  916 + }
  917 + // now run callbacks for option_groups
  918 + for(auto &subc : subcommands_) {
  919 + if(subc->name_.empty() && subc->count_all() > 0) {
  920 + subc->run_callback(true, suppress_final_callback);
  921 + }
  922 + }
  923 +
  924 + // finally run the main callback
  925 + if(final_callback_ && (parsed_ > 0) && (!suppress_final_callback)) {
  926 + if(!name_.empty() || count_all() > 0 || parent_ == nullptr) {
  927 + final_callback_();
  928 + }
  929 + }
  930 +}
  931 +
  932 +CLI11_NODISCARD CLI11_INLINE bool App::_valid_subcommand(const std::string &current, bool ignore_used) const {
  933 + // Don't match if max has been reached - but still check parents
  934 + if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
  935 + return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
  936 + }
  937 + auto *com = _find_subcommand(current, true, ignore_used);
  938 + if(com != nullptr) {
  939 + return true;
  940 + }
  941 + // Check parent if exists, else return false
  942 + return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
  943 +}
  944 +
  945 +CLI11_NODISCARD CLI11_INLINE detail::Classifier App::_recognize(const std::string &current,
  946 + bool ignore_used_subcommands) const {
  947 + std::string dummy1, dummy2;
  948 +
  949 + if(current == "--")
  950 + return detail::Classifier::POSITIONAL_MARK;
  951 + if(_valid_subcommand(current, ignore_used_subcommands))
  952 + return detail::Classifier::SUBCOMMAND;
  953 + if(detail::split_long(current, dummy1, dummy2))
  954 + return detail::Classifier::LONG;
  955 + if(detail::split_short(current, dummy1, dummy2)) {
  956 + if(dummy1[0] >= '0' && dummy1[0] <= '9') {
  957 + if(get_option_no_throw(std::string{'-', dummy1[0]}) == nullptr) {
  958 + return detail::Classifier::NONE;
  959 + }
  960 + }
  961 + return detail::Classifier::SHORT;
  962 + }
  963 + if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))
  964 + return detail::Classifier::WINDOWS_STYLE;
  965 + if((current == "++") && !name_.empty() && parent_ != nullptr)
  966 + return detail::Classifier::SUBCOMMAND_TERMINATOR;
  967 + return detail::Classifier::NONE;
  968 +}
  969 +
  970 +CLI11_INLINE void App::_process_config_file() {
  971 + if(config_ptr_ != nullptr) {
  972 + bool config_required = config_ptr_->get_required();
  973 + auto file_given = config_ptr_->count() > 0;
  974 + auto config_files = config_ptr_->as<std::vector<std::string>>();
  975 + if(config_files.empty() || config_files.front().empty()) {
  976 + if(config_required) {
  977 + throw FileError::Missing("no specified config file");
  978 + }
  979 + return;
  980 + }
  981 + for(auto rit = config_files.rbegin(); rit != config_files.rend(); ++rit) {
  982 + const auto &config_file = *rit;
  983 + auto path_result = detail::check_path(config_file.c_str());
  984 + if(path_result == detail::path_type::file) {
  985 + try {
  986 + std::vector<ConfigItem> values = config_formatter_->from_file(config_file);
  987 + _parse_config(values);
  988 + if(!file_given) {
  989 + config_ptr_->add_result(config_file);
  990 + }
  991 + } catch(const FileError &) {
  992 + if(config_required || file_given)
  993 + throw;
  994 + }
  995 + } else if(config_required || file_given) {
  996 + throw FileError::Missing(config_file);
  997 + }
  998 + }
  999 + }
  1000 +}
  1001 +
  1002 +CLI11_INLINE void App::_process_env() {
  1003 + for(const Option_p &opt : options_) {
  1004 + if(opt->count() == 0 && !opt->envname_.empty()) {
  1005 + char *buffer = nullptr;
  1006 + std::string ename_string;
  1007 +
  1008 +#ifdef _MSC_VER
  1009 + // Windows version
  1010 + std::size_t sz = 0;
  1011 + if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
  1012 + ename_string = std::string(buffer);
  1013 + free(buffer);
  1014 + }
  1015 +#else
  1016 + // This also works on Windows, but gives a warning
  1017 + buffer = std::getenv(opt->envname_.c_str());
  1018 + if(buffer != nullptr)
  1019 + ename_string = std::string(buffer);
  1020 +#endif
  1021 +
  1022 + if(!ename_string.empty()) {
  1023 + opt->add_result(ename_string);
  1024 + }
  1025 + }
  1026 + }
  1027 +
  1028 + for(App_p &sub : subcommands_) {
  1029 + if(sub->get_name().empty() || !sub->parse_complete_callback_)
  1030 + sub->_process_env();
  1031 + }
  1032 +}
  1033 +
  1034 +CLI11_INLINE void App::_process_callbacks() {
  1035 +
  1036 + for(App_p &sub : subcommands_) {
  1037 + // process the priority option_groups first
  1038 + if(sub->get_name().empty() && sub->parse_complete_callback_) {
  1039 + if(sub->count_all() > 0) {
  1040 + sub->_process_callbacks();
  1041 + sub->run_callback();
  1042 + }
  1043 + }
  1044 + }
  1045 +
  1046 + for(const Option_p &opt : options_) {
  1047 + if((*opt) && !opt->get_callback_run()) {
  1048 + opt->run_callback();
  1049 + }
  1050 + }
  1051 + for(App_p &sub : subcommands_) {
  1052 + if(!sub->parse_complete_callback_) {
  1053 + sub->_process_callbacks();
  1054 + }
  1055 + }
  1056 +}
  1057 +
  1058 +CLI11_INLINE void App::_process_help_flags(bool trigger_help, bool trigger_all_help) const {
  1059 + const Option *help_ptr = get_help_ptr();
  1060 + const Option *help_all_ptr = get_help_all_ptr();
  1061 +
  1062 + if(help_ptr != nullptr && help_ptr->count() > 0)
  1063 + trigger_help = true;
  1064 + if(help_all_ptr != nullptr && help_all_ptr->count() > 0)
  1065 + trigger_all_help = true;
  1066 +
  1067 + // If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.
  1068 + if(!parsed_subcommands_.empty()) {
  1069 + for(const App *sub : parsed_subcommands_)
  1070 + sub->_process_help_flags(trigger_help, trigger_all_help);
  1071 +
  1072 + // Only the final subcommand should call for help. All help wins over help.
  1073 + } else if(trigger_all_help) {
  1074 + throw CallForAllHelp();
  1075 + } else if(trigger_help) {
  1076 + throw CallForHelp();
  1077 + }
  1078 +}
  1079 +
  1080 +CLI11_INLINE void App::_process_requirements() {
  1081 + // check excludes
  1082 + bool excluded{false};
  1083 + std::string excluder;
  1084 + for(const auto &opt : exclude_options_) {
  1085 + if(opt->count() > 0) {
  1086 + excluded = true;
  1087 + excluder = opt->get_name();
  1088 + }
  1089 + }
  1090 + for(const auto &subc : exclude_subcommands_) {
  1091 + if(subc->count_all() > 0) {
  1092 + excluded = true;
  1093 + excluder = subc->get_display_name();
  1094 + }
  1095 + }
  1096 + if(excluded) {
  1097 + if(count_all() > 0) {
  1098 + throw ExcludesError(get_display_name(), excluder);
  1099 + }
  1100 + // if we are excluded but didn't receive anything, just return
  1101 + return;
  1102 + }
  1103 +
  1104 + // check excludes
  1105 + bool missing_needed{false};
  1106 + std::string missing_need;
  1107 + for(const auto &opt : need_options_) {
  1108 + if(opt->count() == 0) {
  1109 + missing_needed = true;
  1110 + missing_need = opt->get_name();
  1111 + }
  1112 + }
  1113 + for(const auto &subc : need_subcommands_) {
  1114 + if(subc->count_all() == 0) {
  1115 + missing_needed = true;
  1116 + missing_need = subc->get_display_name();
  1117 + }
  1118 + }
  1119 + if(missing_needed) {
  1120 + if(count_all() > 0) {
  1121 + throw RequiresError(get_display_name(), missing_need);
  1122 + }
  1123 + // if we missing something but didn't have any options, just return
  1124 + return;
  1125 + }
  1126 +
  1127 + std::size_t used_options = 0;
  1128 + for(const Option_p &opt : options_) {
  1129 +
  1130 + if(opt->count() != 0) {
  1131 + ++used_options;
  1132 + }
  1133 + // Required but empty
  1134 + if(opt->get_required() && opt->count() == 0) {
  1135 + throw RequiredError(opt->get_name());
  1136 + }
  1137 + // Requires
  1138 + for(const Option *opt_req : opt->needs_)
  1139 + if(opt->count() > 0 && opt_req->count() == 0)
  1140 + throw RequiresError(opt->get_name(), opt_req->get_name());
  1141 + // Excludes
  1142 + for(const Option *opt_ex : opt->excludes_)
  1143 + if(opt->count() > 0 && opt_ex->count() != 0)
  1144 + throw ExcludesError(opt->get_name(), opt_ex->get_name());
  1145 + }
  1146 + // check for the required number of subcommands
  1147 + if(require_subcommand_min_ > 0) {
  1148 + auto selected_subcommands = get_subcommands();
  1149 + if(require_subcommand_min_ > selected_subcommands.size())
  1150 + throw RequiredError::Subcommand(require_subcommand_min_);
  1151 + }
  1152 +
  1153 + // Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.
  1154 +
  1155 + // run this loop to check how many unnamed subcommands were actually used since they are considered options
  1156 + // from the perspective of an App
  1157 + for(App_p &sub : subcommands_) {
  1158 + if(sub->disabled_)
  1159 + continue;
  1160 + if(sub->name_.empty() && sub->count_all() > 0) {
  1161 + ++used_options;
  1162 + }
  1163 + }
  1164 +
  1165 + if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
  1166 + auto option_list = detail::join(options_, [this](const Option_p &ptr) {
  1167 + if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {
  1168 + return std::string{};
  1169 + }
  1170 + return ptr->get_name(false, true);
  1171 + });
  1172 +
  1173 + auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });
  1174 + if(!subc_list.empty()) {
  1175 + option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });
  1176 + }
  1177 + throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);
  1178 + }
  1179 +
  1180 + // now process the requirements for subcommands if needed
  1181 + for(App_p &sub : subcommands_) {
  1182 + if(sub->disabled_)
  1183 + continue;
  1184 + if(sub->name_.empty() && sub->required_ == false) {
  1185 + if(sub->count_all() == 0) {
  1186 + if(require_option_min_ > 0 && require_option_min_ <= used_options) {
  1187 + continue;
  1188 + // if we have met the requirement and there is nothing in this option group skip checking
  1189 + // requirements
  1190 + }
  1191 + if(require_option_max_ > 0 && used_options >= require_option_min_) {
  1192 + continue;
  1193 + // if we have met the requirement and there is nothing in this option group skip checking
  1194 + // requirements
  1195 + }
  1196 + }
  1197 + }
  1198 + if(sub->count() > 0 || sub->name_.empty()) {
  1199 + sub->_process_requirements();
  1200 + }
  1201 +
  1202 + if(sub->required_ && sub->count_all() == 0) {
  1203 + throw(CLI::RequiredError(sub->get_display_name()));
  1204 + }
  1205 + }
  1206 +}
  1207 +
  1208 +CLI11_INLINE void App::_process() {
  1209 + try {
  1210 + // the config file might generate a FileError but that should not be processed until later in the process
  1211 + // to allow for help, version and other errors to generate first.
  1212 + _process_config_file();
  1213 +
  1214 + // process env shouldn't throw but no reason to process it if config generated an error
  1215 + _process_env();
  1216 + } catch(const CLI::FileError &) {
  1217 + // callbacks and help_flags can generate exceptions which should take priority
  1218 + // over the config file error if one exists.
  1219 + _process_callbacks();
  1220 + _process_help_flags();
  1221 + throw;
  1222 + }
  1223 +
  1224 + _process_callbacks();
  1225 + _process_help_flags();
  1226 +
  1227 + _process_requirements();
  1228 +}
  1229 +
  1230 +CLI11_INLINE void App::_process_extras() {
  1231 + if(!(allow_extras_ || prefix_command_)) {
  1232 + std::size_t num_left_over = remaining_size();
  1233 + if(num_left_over > 0) {
  1234 + throw ExtrasError(name_, remaining(false));
  1235 + }
  1236 + }
  1237 +
  1238 + for(App_p &sub : subcommands_) {
  1239 + if(sub->count() > 0)
  1240 + sub->_process_extras();
  1241 + }
  1242 +}
  1243 +
  1244 +CLI11_INLINE void App::_process_extras(std::vector<std::string> &args) {
  1245 + if(!(allow_extras_ || prefix_command_)) {
  1246 + std::size_t num_left_over = remaining_size();
  1247 + if(num_left_over > 0) {
  1248 + args = remaining(false);
  1249 + throw ExtrasError(name_, args);
  1250 + }
  1251 + }
  1252 +
  1253 + for(App_p &sub : subcommands_) {
  1254 + if(sub->count() > 0)
  1255 + sub->_process_extras(args);
  1256 + }
  1257 +}
  1258 +
  1259 +CLI11_INLINE void App::increment_parsed() {
  1260 + ++parsed_;
  1261 + for(App_p &sub : subcommands_) {
  1262 + if(sub->get_name().empty())
  1263 + sub->increment_parsed();
  1264 + }
  1265 +}
  1266 +
  1267 +CLI11_INLINE void App::_parse(std::vector<std::string> &args) {
  1268 + increment_parsed();
  1269 + _trigger_pre_parse(args.size());
  1270 + bool positional_only = false;
  1271 +
  1272 + while(!args.empty()) {
  1273 + if(!_parse_single(args, positional_only)) {
  1274 + break;
  1275 + }
  1276 + }
  1277 +
  1278 + if(parent_ == nullptr) {
  1279 + _process();
  1280 +
  1281 + // Throw error if any items are left over (depending on settings)
  1282 + _process_extras(args);
  1283 +
  1284 + // Convert missing (pairs) to extras (string only) ready for processing in another app
  1285 + args = remaining_for_passthrough(false);
  1286 + } else if(parse_complete_callback_) {
  1287 + _process_env();
  1288 + _process_callbacks();
  1289 + _process_help_flags();
  1290 + _process_requirements();
  1291 + run_callback(false, true);
  1292 + }
  1293 +}
  1294 +
  1295 +CLI11_INLINE void App::_parse(std::vector<std::string> &&args) {
  1296 + // this can only be called by the top level in which case parent == nullptr by definition
  1297 + // operation is simplified
  1298 + increment_parsed();
  1299 + _trigger_pre_parse(args.size());
  1300 + bool positional_only = false;
  1301 +
  1302 + while(!args.empty()) {
  1303 + _parse_single(args, positional_only);
  1304 + }
  1305 + _process();
  1306 +
  1307 + // Throw error if any items are left over (depending on settings)
  1308 + _process_extras();
  1309 +}
  1310 +
  1311 +CLI11_INLINE void App::_parse_stream(std::istream &input) {
  1312 + auto values = config_formatter_->from_config(input);
  1313 + _parse_config(values);
  1314 + increment_parsed();
  1315 + _trigger_pre_parse(values.size());
  1316 + _process();
  1317 +
  1318 + // Throw error if any items are left over (depending on settings)
  1319 + _process_extras();
  1320 +}
  1321 +
  1322 +CLI11_INLINE void App::_parse_config(const std::vector<ConfigItem> &args) {
  1323 + for(const ConfigItem &item : args) {
  1324 + if(!_parse_single_config(item) && allow_config_extras_ == config_extras_mode::error)
  1325 + throw ConfigError::Extras(item.fullname());
  1326 + }
  1327 +}
  1328 +
  1329 +CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) {
  1330 + if(level < item.parents.size()) {
  1331 + try {
  1332 + auto *subcom = get_subcommand(item.parents.at(level));
  1333 + auto result = subcom->_parse_single_config(item, level + 1);
  1334 +
  1335 + return result;
  1336 + } catch(const OptionNotFound &) {
  1337 + return false;
  1338 + }
  1339 + }
  1340 + // check for section open
  1341 + if(item.name == "++") {
  1342 + if(configurable_) {
  1343 + increment_parsed();
  1344 + _trigger_pre_parse(2);
  1345 + if(parent_ != nullptr) {
  1346 + parent_->parsed_subcommands_.push_back(this);
  1347 + }
  1348 + }
  1349 + return true;
  1350 + }
  1351 + // check for section close
  1352 + if(item.name == "--") {
  1353 + if(configurable_ && parse_complete_callback_) {
  1354 + _process_callbacks();
  1355 + _process_requirements();
  1356 + run_callback();
  1357 + }
  1358 + return true;
  1359 + }
  1360 + Option *op = get_option_no_throw("--" + item.name);
  1361 + if(op == nullptr) {
  1362 + if(item.name.size() == 1) {
  1363 + op = get_option_no_throw("-" + item.name);
  1364 + }
  1365 + }
  1366 + if(op == nullptr) {
  1367 + op = get_option_no_throw(item.name);
  1368 + }
  1369 + if(op == nullptr) {
  1370 + // If the option was not present
  1371 + if(get_allow_config_extras() == config_extras_mode::capture)
  1372 + // Should we worry about classifying the extras properly?
  1373 + missing_.emplace_back(detail::Classifier::NONE, item.fullname());
  1374 + return false;
  1375 + }
  1376 +
  1377 + if(!op->get_configurable()) {
  1378 + if(get_allow_config_extras() == config_extras_mode::ignore_all) {
  1379 + return false;
  1380 + }
  1381 + throw ConfigError::NotConfigurable(item.fullname());
  1382 + }
  1383 +
  1384 + if(op->empty()) {
  1385 +
  1386 + if(op->get_expected_min() == 0) {
  1387 + // Flag parsing
  1388 + auto res = config_formatter_->to_flag(item);
  1389 + res = op->get_flag_value(item.name, res);
  1390 +
  1391 + op->add_result(res);
  1392 +
  1393 + } else {
  1394 + op->add_result(item.inputs);
  1395 + op->run_callback();
  1396 + }
  1397 + }
  1398 +
  1399 + return true;
  1400 +}
  1401 +
  1402 +CLI11_INLINE bool App::_parse_single(std::vector<std::string> &args, bool &positional_only) {
  1403 + bool retval = true;
  1404 + detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back());
  1405 + switch(classifier) {
  1406 + case detail::Classifier::POSITIONAL_MARK:
  1407 + args.pop_back();
  1408 + positional_only = true;
  1409 + if((!_has_remaining_positionals()) && (parent_ != nullptr)) {
  1410 + retval = false;
  1411 + } else {
  1412 + _move_to_missing(classifier, "--");
  1413 + }
  1414 + break;
  1415 + case detail::Classifier::SUBCOMMAND_TERMINATOR:
  1416 + // treat this like a positional mark if in the parent app
  1417 + args.pop_back();
  1418 + retval = false;
  1419 + break;
  1420 + case detail::Classifier::SUBCOMMAND:
  1421 + retval = _parse_subcommand(args);
  1422 + break;
  1423 + case detail::Classifier::LONG:
  1424 + case detail::Classifier::SHORT:
  1425 + case detail::Classifier::WINDOWS_STYLE:
  1426 + // If already parsed a subcommand, don't accept options_
  1427 + _parse_arg(args, classifier);
  1428 + break;
  1429 + case detail::Classifier::NONE:
  1430 + // Probably a positional or something for a parent (sub)command
  1431 + retval = _parse_positional(args, false);
  1432 + if(retval && positionals_at_end_) {
  1433 + positional_only = true;
  1434 + }
  1435 + break;
  1436 + // LCOV_EXCL_START
  1437 + default:
  1438 + throw HorribleError("unrecognized classifier (you should not see this!)");
  1439 + // LCOV_EXCL_STOP
  1440 + }
  1441 + return retval;
  1442 +}
  1443 +
  1444 +CLI11_NODISCARD CLI11_INLINE std::size_t App::_count_remaining_positionals(bool required_only) const {
  1445 + std::size_t retval = 0;
  1446 + for(const Option_p &opt : options_) {
  1447 + if(opt->get_positional() && (!required_only || opt->get_required())) {
  1448 + if(opt->get_items_expected_min() > 0 && static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
  1449 + retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();
  1450 + }
  1451 + }
  1452 + }
  1453 + return retval;
  1454 +}
  1455 +
  1456 +CLI11_NODISCARD CLI11_INLINE bool App::_has_remaining_positionals() const {
  1457 + for(const Option_p &opt : options_) {
  1458 + if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
  1459 + return true;
  1460 + }
  1461 + }
  1462 +
  1463 + return false;
  1464 +}
  1465 +
  1466 +CLI11_INLINE bool App::_parse_positional(std::vector<std::string> &args, bool haltOnSubcommand) {
  1467 +
  1468 + const std::string &positional = args.back();
  1469 +
  1470 + if(positionals_at_end_) {
  1471 + // deal with the case of required arguments at the end which should take precedence over other arguments
  1472 + auto arg_rem = args.size();
  1473 + auto remreq = _count_remaining_positionals(true);
  1474 + if(arg_rem <= remreq) {
  1475 + for(const Option_p &opt : options_) {
  1476 + if(opt->get_positional() && opt->required_) {
  1477 + if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
  1478 + if(validate_positionals_) {
  1479 + std::string pos = positional;
  1480 + pos = opt->_validate(pos, 0);
  1481 + if(!pos.empty()) {
  1482 + continue;
  1483 + }
  1484 + }
  1485 +
  1486 + parse_order_.push_back(opt.get());
  1487 + /// if we require a separator add it here
  1488 + if(opt->get_inject_separator()) {
  1489 + if(!opt->results().empty() && !opt->results().back().empty()) {
  1490 + opt->add_result(std::string{});
  1491 + }
  1492 + }
  1493 + if(opt->get_trigger_on_parse() &&
  1494 + opt->current_option_state_ == Option::option_state::callback_run) {
  1495 + opt->clear();
  1496 + }
  1497 + opt->add_result(positional);
  1498 + if(opt->get_trigger_on_parse()) {
  1499 + opt->run_callback();
  1500 + }
  1501 + args.pop_back();
  1502 + return true;
  1503 + }
  1504 + }
  1505 + }
  1506 + }
  1507 + }
  1508 + for(const Option_p &opt : options_) {
  1509 + // Eat options, one by one, until done
  1510 + if(opt->get_positional() &&
  1511 + (static_cast<int>(opt->count()) < opt->get_items_expected_min() || opt->get_allow_extra_args())) {
  1512 + if(validate_positionals_) {
  1513 + std::string pos = positional;
  1514 + pos = opt->_validate(pos, 0);
  1515 + if(!pos.empty()) {
  1516 + continue;
  1517 + }
  1518 + }
  1519 + if(opt->get_inject_separator()) {
  1520 + if(!opt->results().empty() && !opt->results().back().empty()) {
  1521 + opt->add_result(std::string{});
  1522 + }
  1523 + }
  1524 + if(opt->get_trigger_on_parse() && opt->current_option_state_ == Option::option_state::callback_run) {
  1525 + opt->clear();
  1526 + }
  1527 + opt->add_result(positional);
  1528 + if(opt->get_trigger_on_parse()) {
  1529 + opt->run_callback();
  1530 + }
  1531 + parse_order_.push_back(opt.get());
  1532 + args.pop_back();
  1533 + return true;
  1534 + }
  1535 + }
  1536 +
  1537 + for(auto &subc : subcommands_) {
  1538 + if((subc->name_.empty()) && (!subc->disabled_)) {
  1539 + if(subc->_parse_positional(args, false)) {
  1540 + if(!subc->pre_parse_called_) {
  1541 + subc->_trigger_pre_parse(args.size());
  1542 + }
  1543 + return true;
  1544 + }
  1545 + }
  1546 + }
  1547 + // let the parent deal with it if possible
  1548 + if(parent_ != nullptr && fallthrough_)
  1549 + return _get_fallthrough_parent()->_parse_positional(args, static_cast<bool>(parse_complete_callback_));
  1550 +
  1551 + /// Try to find a local subcommand that is repeated
  1552 + auto *com = _find_subcommand(args.back(), true, false);
  1553 + if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
  1554 + if(haltOnSubcommand) {
  1555 + return false;
  1556 + }
  1557 + args.pop_back();
  1558 + com->_parse(args);
  1559 + return true;
  1560 + }
  1561 + /// now try one last gasp at subcommands that have been executed before, go to root app and try to find a
  1562 + /// subcommand in a broader way, if one exists let the parent deal with it
  1563 + auto *parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
  1564 + com = parent_app->_find_subcommand(args.back(), true, false);
  1565 + if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||
  1566 + com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
  1567 + return false;
  1568 + }
  1569 +
  1570 + if(positionals_at_end_) {
  1571 + throw CLI::ExtrasError(name_, args);
  1572 + }
  1573 + /// If this is an option group don't deal with it
  1574 + if(parent_ != nullptr && name_.empty()) {
  1575 + return false;
  1576 + }
  1577 + /// We are out of other options this goes to missing
  1578 + _move_to_missing(detail::Classifier::NONE, positional);
  1579 + args.pop_back();
  1580 + if(prefix_command_) {
  1581 + while(!args.empty()) {
  1582 + _move_to_missing(detail::Classifier::NONE, args.back());
  1583 + args.pop_back();
  1584 + }
  1585 + }
  1586 +
  1587 + return true;
  1588 +}
  1589 +
  1590 +CLI11_NODISCARD CLI11_INLINE App *
  1591 +App::_find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {
  1592 + for(const App_p &com : subcommands_) {
  1593 + if(com->disabled_ && ignore_disabled)
  1594 + continue;
  1595 + if(com->get_name().empty()) {
  1596 + auto *subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
  1597 + if(subc != nullptr) {
  1598 + return subc;
  1599 + }
  1600 + }
  1601 + if(com->check_name(subc_name)) {
  1602 + if((!*com) || !ignore_used)
  1603 + return com.get();
  1604 + }
  1605 + }
  1606 + return nullptr;
  1607 +}
  1608 +
  1609 +CLI11_INLINE bool App::_parse_subcommand(std::vector<std::string> &args) {
  1610 + if(_count_remaining_positionals(/* required */ true) > 0) {
  1611 + _parse_positional(args, false);
  1612 + return true;
  1613 + }
  1614 + auto *com = _find_subcommand(args.back(), true, true);
  1615 + if(com != nullptr) {
  1616 + args.pop_back();
  1617 + if(!com->silent_) {
  1618 + parsed_subcommands_.push_back(com);
  1619 + }
  1620 + com->_parse(args);
  1621 + auto *parent_app = com->parent_;
  1622 + while(parent_app != this) {
  1623 + parent_app->_trigger_pre_parse(args.size());
  1624 + if(!com->silent_) {
  1625 + parent_app->parsed_subcommands_.push_back(com);
  1626 + }
  1627 + parent_app = parent_app->parent_;
  1628 + }
  1629 + return true;
  1630 + }
  1631 +
  1632 + if(parent_ == nullptr)
  1633 + throw HorribleError("Subcommand " + args.back() + " missing");
  1634 + return false;
  1635 +}
  1636 +
  1637 +CLI11_INLINE bool App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {
  1638 +
  1639 + std::string current = args.back();
  1640 +
  1641 + std::string arg_name;
  1642 + std::string value;
  1643 + std::string rest;
  1644 +
  1645 + switch(current_type) {
  1646 + case detail::Classifier::LONG:
  1647 + if(!detail::split_long(current, arg_name, value))
  1648 + throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
  1649 + break;
  1650 + case detail::Classifier::SHORT:
  1651 + if(!detail::split_short(current, arg_name, rest))
  1652 + throw HorribleError("Short parsed but missing! You should not see this");
  1653 + break;
  1654 + case detail::Classifier::WINDOWS_STYLE:
  1655 + if(!detail::split_windows_style(current, arg_name, value))
  1656 + throw HorribleError("windows option parsed but missing! You should not see this");
  1657 + break;
  1658 + case detail::Classifier::SUBCOMMAND:
  1659 + case detail::Classifier::SUBCOMMAND_TERMINATOR:
  1660 + case detail::Classifier::POSITIONAL_MARK:
  1661 + case detail::Classifier::NONE:
  1662 + default:
  1663 + throw HorribleError("parsing got called with invalid option! You should not see this");
  1664 + }
  1665 +
  1666 + auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {
  1667 + if(current_type == detail::Classifier::LONG)
  1668 + return opt->check_lname(arg_name);
  1669 + if(current_type == detail::Classifier::SHORT)
  1670 + return opt->check_sname(arg_name);
  1671 + // this will only get called for detail::Classifier::WINDOWS_STYLE
  1672 + return opt->check_lname(arg_name) || opt->check_sname(arg_name);
  1673 + });
  1674 +
  1675 + // Option not found
  1676 + if(op_ptr == std::end(options_)) {
  1677 + for(auto &subc : subcommands_) {
  1678 + if(subc->name_.empty() && !subc->disabled_) {
  1679 + if(subc->_parse_arg(args, current_type)) {
  1680 + if(!subc->pre_parse_called_) {
  1681 + subc->_trigger_pre_parse(args.size());
  1682 + }
  1683 + return true;
  1684 + }
  1685 + }
  1686 + }
  1687 +
  1688 + // don't capture missing if this is a nameless subcommand and nameless subcommands can't fallthrough
  1689 + if(parent_ != nullptr && name_.empty()) {
  1690 + return false;
  1691 + }
  1692 +
  1693 + // If a subcommand, try the main command
  1694 + if(parent_ != nullptr && fallthrough_)
  1695 + return _get_fallthrough_parent()->_parse_arg(args, current_type);
  1696 +
  1697 + // Otherwise, add to missing
  1698 + args.pop_back();
  1699 + _move_to_missing(current_type, current);
  1700 + return true;
  1701 + }
  1702 +
  1703 + args.pop_back();
  1704 +
  1705 + // Get a reference to the pointer to make syntax bearable
  1706 + Option_p &op = *op_ptr;
  1707 + /// if we require a separator add it here
  1708 + if(op->get_inject_separator()) {
  1709 + if(!op->results().empty() && !op->results().back().empty()) {
  1710 + op->add_result(std::string{});
  1711 + }
  1712 + }
  1713 + if(op->get_trigger_on_parse() && op->current_option_state_ == Option::option_state::callback_run) {
  1714 + op->clear();
  1715 + }
  1716 + int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
  1717 + int max_num = op->get_items_expected_max();
  1718 + // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
  1719 + // set. 16 is somewhat arbitrary (needs to be at least 4)
  1720 + if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
  1721 + auto tmax = op->get_type_size_max();
  1722 + max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
  1723 + }
  1724 + // Make sure we always eat the minimum for unlimited vectors
  1725 + int collected = 0; // total number of arguments collected
  1726 + int result_count = 0; // local variable for number of results in a single arg string
  1727 + // deal with purely flag like things
  1728 + if(max_num == 0) {
  1729 + auto res = op->get_flag_value(arg_name, value);
  1730 + op->add_result(res);
  1731 + parse_order_.push_back(op.get());
  1732 + } else if(!value.empty()) { // --this=value
  1733 + op->add_result(value, result_count);
  1734 + parse_order_.push_back(op.get());
  1735 + collected += result_count;
  1736 + // -Trest
  1737 + } else if(!rest.empty()) {
  1738 + op->add_result(rest, result_count);
  1739 + parse_order_.push_back(op.get());
  1740 + rest = "";
  1741 + collected += result_count;
  1742 + }
  1743 +
  1744 + // gather the minimum number of arguments
  1745 + while(min_num > collected && !args.empty()) {
  1746 + std::string current_ = args.back();
  1747 + args.pop_back();
  1748 + op->add_result(current_, result_count);
  1749 + parse_order_.push_back(op.get());
  1750 + collected += result_count;
  1751 + }
  1752 +
  1753 + if(min_num > collected) { // if we have run out of arguments and the minimum was not met
  1754 + throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
  1755 + }
  1756 +
  1757 + // now check for optional arguments
  1758 + if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
  1759 + auto remreqpos = _count_remaining_positionals(true);
  1760 + // we have met the minimum now optionally check up to the maximum
  1761 + while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
  1762 + _recognize(args.back(), false) == detail::Classifier::NONE) {
  1763 + // If any required positionals remain, don't keep eating
  1764 + if(remreqpos >= args.size()) {
  1765 + break;
  1766 + }
  1767 + if(validate_optional_arguments_) {
  1768 + std::string arg = args.back();
  1769 + arg = op->_validate(arg, 0);
  1770 + if(!arg.empty()) {
  1771 + break;
  1772 + }
  1773 + }
  1774 + op->add_result(args.back(), result_count);
  1775 + parse_order_.push_back(op.get());
  1776 + args.pop_back();
  1777 + collected += result_count;
  1778 + }
  1779 +
  1780 + // Allow -- to end an unlimited list and "eat" it
  1781 + if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
  1782 + args.pop_back();
  1783 + // optional flag that didn't receive anything now get the default value
  1784 + if(min_num == 0 && max_num > 0 && collected == 0) {
  1785 + auto res = op->get_flag_value(arg_name, std::string{});
  1786 + op->add_result(res);
  1787 + parse_order_.push_back(op.get());
  1788 + }
  1789 + }
  1790 + // if we only partially completed a type then add an empty string if allowed for later processing
  1791 + if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {
  1792 + if(op->get_type_size_max() != op->get_type_size_min()) {
  1793 + op->add_result(std::string{});
  1794 + } else {
  1795 + throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());
  1796 + }
  1797 + }
  1798 + if(op->get_trigger_on_parse()) {
  1799 + op->run_callback();
  1800 + }
  1801 + if(!rest.empty()) {
  1802 + rest = "-" + rest;
  1803 + args.push_back(rest);
  1804 + }
  1805 + return true;
  1806 +}
  1807 +
  1808 +CLI11_INLINE void App::_trigger_pre_parse(std::size_t remaining_args) {
  1809 + if(!pre_parse_called_) {
  1810 + pre_parse_called_ = true;
  1811 + if(pre_parse_callback_) {
  1812 + pre_parse_callback_(remaining_args);
  1813 + }
  1814 + } else if(immediate_callback_) {
  1815 + if(!name_.empty()) {
  1816 + auto pcnt = parsed_;
  1817 + auto extras = std::move(missing_);
  1818 + clear();
  1819 + parsed_ = pcnt;
  1820 + pre_parse_called_ = true;
  1821 + missing_ = std::move(extras);
  1822 + }
  1823 + }
  1824 +}
  1825 +
  1826 +CLI11_INLINE App *App::_get_fallthrough_parent() {
  1827 + if(parent_ == nullptr) {
  1828 + throw(HorribleError("No Valid parent"));
  1829 + }
  1830 + auto *fallthrough_parent = parent_;
  1831 + while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {
  1832 + fallthrough_parent = fallthrough_parent->parent_;
  1833 + }
  1834 + return fallthrough_parent;
  1835 +}
  1836 +
  1837 +CLI11_NODISCARD CLI11_INLINE const std::string &App::_compare_subcommand_names(const App &subcom,
  1838 + const App &base) const {
  1839 + static const std::string estring;
  1840 + if(subcom.disabled_) {
  1841 + return estring;
  1842 + }
  1843 + for(const auto &subc : base.subcommands_) {
  1844 + if(subc.get() != &subcom) {
  1845 + if(subc->disabled_) {
  1846 + continue;
  1847 + }
  1848 + if(!subcom.get_name().empty()) {
  1849 + if(subc->check_name(subcom.get_name())) {
  1850 + return subcom.get_name();
  1851 + }
  1852 + }
  1853 + if(!subc->get_name().empty()) {
  1854 + if(subcom.check_name(subc->get_name())) {
  1855 + return subc->get_name();
  1856 + }
  1857 + }
  1858 + for(const auto &les : subcom.aliases_) {
  1859 + if(subc->check_name(les)) {
  1860 + return les;
  1861 + }
  1862 + }
  1863 + // this loop is needed in case of ignore_underscore or ignore_case on one but not the other
  1864 + for(const auto &les : subc->aliases_) {
  1865 + if(subcom.check_name(les)) {
  1866 + return les;
  1867 + }
  1868 + }
  1869 + // if the subcommand is an option group we need to check deeper
  1870 + if(subc->get_name().empty()) {
  1871 + const auto &cmpres = _compare_subcommand_names(subcom, *subc);
  1872 + if(!cmpres.empty()) {
  1873 + return cmpres;
  1874 + }
  1875 + }
  1876 + // if the test subcommand is an option group we need to check deeper
  1877 + if(subcom.get_name().empty()) {
  1878 + const auto &cmpres = _compare_subcommand_names(*subc, subcom);
  1879 + if(!cmpres.empty()) {
  1880 + return cmpres;
  1881 + }
  1882 + }
  1883 + }
  1884 + }
  1885 + return estring;
  1886 +}
  1887 +
  1888 +CLI11_INLINE void App::_move_to_missing(detail::Classifier val_type, const std::string &val) {
  1889 + if(allow_extras_ || subcommands_.empty()) {
  1890 + missing_.emplace_back(val_type, val);
  1891 + return;
  1892 + }
  1893 + // allow extra arguments to be places in an option group if it is allowed there
  1894 + for(auto &subc : subcommands_) {
  1895 + if(subc->name_.empty() && subc->allow_extras_) {
  1896 + subc->missing_.emplace_back(val_type, val);
  1897 + return;
  1898 + }
  1899 + }
  1900 + // if we haven't found any place to put them yet put them in missing
  1901 + missing_.emplace_back(val_type, val);
  1902 +}
  1903 +
  1904 +CLI11_INLINE void App::_move_option(Option *opt, App *app) {
  1905 + if(opt == nullptr) {
  1906 + throw OptionNotFound("the option is NULL");
  1907 + }
  1908 + // verify that the give app is actually a subcommand
  1909 + bool found = false;
  1910 + for(auto &subc : subcommands_) {
  1911 + if(app == subc.get()) {
  1912 + found = true;
  1913 + }
  1914 + }
  1915 + if(!found) {
  1916 + throw OptionNotFound("The Given app is not a subcommand");
  1917 + }
  1918 +
  1919 + if((help_ptr_ == opt) || (help_all_ptr_ == opt))
  1920 + throw OptionAlreadyAdded("cannot move help options");
  1921 +
  1922 + if(config_ptr_ == opt)
  1923 + throw OptionAlreadyAdded("cannot move config file options");
  1924 +
  1925 + auto iterator =
  1926 + std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
  1927 + if(iterator != std::end(options_)) {
  1928 + const auto &opt_p = *iterator;
  1929 + if(std::find_if(std::begin(app->options_), std::end(app->options_), [&opt_p](const Option_p &v) {
  1930 + return (*v == *opt_p);
  1931 + }) == std::end(app->options_)) {
  1932 + // only erase after the insertion was successful
  1933 + app->options_.push_back(std::move(*iterator));
  1934 + options_.erase(iterator);
  1935 + } else {
  1936 + throw OptionAlreadyAdded("option was not located: " + opt->get_name());
  1937 + }
  1938 + } else {
  1939 + throw OptionNotFound("could not locate the given Option");
  1940 + }
  1941 +}
  1942 +
  1943 +CLI11_INLINE void TriggerOn(App *trigger_app, App *app_to_enable) {
  1944 + app_to_enable->enabled_by_default(false);
  1945 + app_to_enable->disabled_by_default();
  1946 + trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(false); });
  1947 +}
  1948 +
  1949 +CLI11_INLINE void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
  1950 + for(auto &app : apps_to_enable) {
  1951 + app->enabled_by_default(false);
  1952 + app->disabled_by_default();
  1953 + }
  1954 +
  1955 + trigger_app->preparse_callback([apps_to_enable](std::size_t) {
  1956 + for(const auto &app : apps_to_enable) {
  1957 + app->disabled(false);
  1958 + }
  1959 + });
  1960 +}
  1961 +
  1962 +CLI11_INLINE void TriggerOff(App *trigger_app, App *app_to_enable) {
  1963 + app_to_enable->disabled_by_default(false);
  1964 + app_to_enable->enabled_by_default();
  1965 + trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
  1966 +}
  1967 +
  1968 +CLI11_INLINE void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
  1969 + for(auto &app : apps_to_enable) {
  1970 + app->disabled_by_default(false);
  1971 + app->enabled_by_default();
  1972 + }
  1973 +
  1974 + trigger_app->preparse_callback([apps_to_enable](std::size_t) {
  1975 + for(const auto &app : apps_to_enable) {
  1976 + app->disabled();
  1977 + }
  1978 + });
  1979 +}
  1980 +
  1981 +CLI11_INLINE void deprecate_option(Option *opt, const std::string &replacement) {
  1982 + Validator deprecate_warning{[opt, replacement](std::string &) {
  1983 + std::cout << opt->get_name() << " is deprecated please use '" << replacement
  1984 + << "' instead\n";
  1985 + return std::string();
  1986 + },
  1987 + "DEPRECATED"};
  1988 + deprecate_warning.application_index(0);
  1989 + opt->check(deprecate_warning);
  1990 + if(!replacement.empty()) {
  1991 + opt->description(opt->get_description() + " DEPRECATED: please use '" + replacement + "' instead");
  1992 + }
  1993 +}
  1994 +
  1995 +CLI11_INLINE void retire_option(App *app, Option *opt) {
  1996 + App temp;
  1997 + auto *option_copy = temp.add_option(opt->get_name(false, true))
  1998 + ->type_size(opt->get_type_size_min(), opt->get_type_size_max())
  1999 + ->expected(opt->get_expected_min(), opt->get_expected_max())
  2000 + ->allow_extra_args(opt->get_allow_extra_args());
  2001 +
  2002 + app->remove_option(opt);
  2003 + auto *opt2 = app->add_option(option_copy->get_name(false, true), "option has been retired and has no effect")
  2004 + ->type_name("RETIRED")
  2005 + ->default_str("RETIRED")
  2006 + ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
  2007 + ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())
  2008 + ->allow_extra_args(option_copy->get_allow_extra_args());
  2009 +
  2010 + Validator retired_warning{[opt2](std::string &) {
  2011 + std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
  2012 + return std::string();
  2013 + },
  2014 + ""};
  2015 + retired_warning.application_index(0);
  2016 + opt2->check(retired_warning);
  2017 +}
  2018 +
  2019 +CLI11_INLINE void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
  2020 +
  2021 +CLI11_INLINE void retire_option(App *app, const std::string &option_name) {
  2022 +
  2023 + auto *opt = app->get_option_no_throw(option_name);
  2024 + if(opt != nullptr) {
  2025 + retire_option(app, opt);
  2026 + return;
  2027 + }
  2028 + auto *opt2 = app->add_option(option_name, "option has been retired and has no effect")
  2029 + ->type_name("RETIRED")
  2030 + ->expected(0, 1)
  2031 + ->default_str("RETIRED");
  2032 + Validator retired_warning{[opt2](std::string &) {
  2033 + std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
  2034 + return std::string();
  2035 + },
  2036 + ""};
  2037 + retired_warning.application_index(0);
  2038 + opt2->check(retired_warning);
  2039 +}
  2040 +
  2041 +CLI11_INLINE void retire_option(App &app, const std::string &option_name) { retire_option(&app, option_name); }
  2042 +
  2043 +namespace FailureMessage {
  2044 +
  2045 +CLI11_INLINE std::string simple(const App *app, const Error &e) {
  2046 + std::string header = std::string(e.what()) + "\n";
  2047 + std::vector<std::string> names;
  2048 +
  2049 + // Collect names
  2050 + if(app->get_help_ptr() != nullptr)
  2051 + names.push_back(app->get_help_ptr()->get_name());
  2052 +
  2053 + if(app->get_help_all_ptr() != nullptr)
  2054 + names.push_back(app->get_help_all_ptr()->get_name());
  2055 +
  2056 + // If any names found, suggest those
  2057 + if(!names.empty())
  2058 + header += "Run with " + detail::join(names, " or ") + " for more information.\n";
  2059 +
  2060 + return header;
  2061 +}
  2062 +
  2063 +CLI11_INLINE std::string help(const App *app, const Error &e) {
  2064 + std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
  2065 + header += app->help();
  2066 + return header;
  2067 +}
  2068 +
  2069 +} // namespace FailureMessage
  2070 +
  2071 +// [CLI11:app_inl_hpp:end]
  2072 +} // namespace CLI
src/App.cpp 0 → 100644
  1 +// Copyright (c) 2017-2022, 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 +#include <CLI/impl/App_inl.hpp>
  8 +
  9 +#include <CLI/Config.hpp>
  10 +#include <CLI/Formatter.hpp>