diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 9ba9c22a..5d776160 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1231,7 +1231,7 @@ class App { void _process_config_file(); /// Read and process a particular configuration file - void _process_config_file(const std::string &config_file, bool throw_error); + bool _process_config_file(const std::string &config_file, bool throw_error); /// Get envname options if not yet passed. Runs on *all* subcommands. void _process_env(); diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index e33729e3..a732cbc6 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1065,18 +1065,23 @@ CLI11_NODISCARD CLI11_INLINE detail::Classifier App::_recognize(const std::strin return detail::Classifier::NONE; } -CLI11_INLINE void App::_process_config_file(const std::string &config_file, bool throw_error) { +CLI11_INLINE bool App::_process_config_file(const std::string &config_file, bool throw_error) { auto path_result = detail::check_path(config_file.c_str()); if(path_result == detail::path_type::file) { try { std::vector values = config_formatter_->from_file(config_file); _parse_config(values); + return true; } catch(const FileError &) { - if(throw_error) + if(throw_error) { throw; + } + return false; } } else if(throw_error) { throw FileError::Missing(config_file); + } else { + return false; } } @@ -1093,6 +1098,7 @@ CLI11_INLINE void App::_process_config_file() { config_ptr_->run_callback(); auto config_files = config_ptr_->as>(); + bool files_used{file_given}; if(config_files.empty() || config_files.front().empty()) { if(config_required) { throw FileError("config file is required but none was given"); @@ -1100,7 +1106,17 @@ CLI11_INLINE void App::_process_config_file() { return; } for(const auto &config_file : config_files) { - _process_config_file(config_file, config_required || file_given); + if(_process_config_file(config_file, config_required || file_given)) { + files_used = true; + } + } + if(!files_used) { + // this is done so the count shows as 0 if no callbacks were processed + config_ptr_->clear(); + bool force = config_ptr_->force_callback_; + config_ptr_->force_callback_ = false; + config_ptr_->run_callback(); + config_ptr_->force_callback_ = force; } } } diff --git a/tests/ConfigFileTest.cpp b/tests/ConfigFileTest.cpp index 708e71ee..83acd2d0 100644 --- a/tests/ConfigFileTest.cpp +++ b/tests/ConfigFileTest.cpp @@ -1049,6 +1049,16 @@ TEST_CASE_METHOD(TApp, "IniRequiredNotFound", "[config]") { CHECK_THROWS_AS(run(), CLI::FileError); } +TEST_CASE_METHOD(TApp, "IniDefaultNotExist", "[config]") { + + std::string noini = "TestIniNotExist.ini"; + auto *cfg = app.set_config("--config", noini); + + CHECK_NOTHROW(run()); + + CHECK(cfg->count() == 0); +} + TEST_CASE_METHOD(TApp, "IniNotRequiredPassedNotFound", "[config]") { std::string noini = "TestIniNotExist.ini"; @@ -1084,7 +1094,7 @@ TEST_CASE_METHOD(TApp, "IniRequired", "[config]") { TempFile tmpini{"TestIniTmp.ini"}; - app.set_config("--config", tmpini, "", true); + auto *cfg = app.set_config("--config", tmpini, "", true); { std::ofstream out{tmpini}; @@ -1109,6 +1119,7 @@ TEST_CASE_METHOD(TApp, "IniRequired", "[config]") { args = {"--one=1", "--two=2"}; CHECK_NOTHROW(run()); + CHECK(cfg->count() == 1); CHECK(1 == one); CHECK(2 == two); CHECK(3 == three);