From 4361647ef4d2d286500179d736b33222a7fce49e Mon Sep 17 00:00:00 2001 From: gereon Date: Sun, 9 Dec 2012 14:41:46 +0100 Subject: [PATCH] made settings callbacks work and changed names to match our conventions. it is possible to register callbacks that add custom options to the settings module. it is also possible to register callbacks that perform checks on the variable assignment afterwards. The registering is done during the static initialization phase, i.e. before main() does anything. --- src/utility/settings.cpp | 64 +++++++++++++++++++++++++++++++++++----- src/utility/settings.h | 27 ++++++++++------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/utility/settings.cpp b/src/utility/settings.cpp index 037243de4..a268ec684 100644 --- a/src/utility/settings.cpp +++ b/src/utility/settings.cpp @@ -7,7 +7,7 @@ #include "src/utility/settings.h" -//#include +#include //#include //#include "src/exceptions/InvalidSettings.h" @@ -58,26 +58,46 @@ Settings::Settings(const int argc, const char* argv[], const char* filename) { bpo::store(bpo::parse_config_file(filename, this->conf), this->vm, true); } + /* + * If a required option is missing, this will throw a bpo::required_option. + * This exception is catched below. + */ bpo::notify(this->vm); + + /* + * Call custom option checker. + */ + Callbacks* cb = mrmc::settings::Callbacks::getInstance(); + while (cb->checkerList.size() > 0) + { + CheckerCallback fptr = cb->checkerList.front(); + cb->checkerList.pop_front(); + + if (! (*fptr)(this->vm)) + { + std::cerr << "Custom option checker failed." << std::endl; + throw mrmc::exceptions::InvalidSettings(); + } + } } /* * catch errors... */ catch (bpo::reading_file e) { - std::cout << "Could not read config file " << filename << std::endl; + std::cerr << "Could not read config file " << filename << std::endl; } catch (bpo::required_option e) { if (! (this->vm.count("help") || this->vm.count("help-config"))) { - std::cout << e.what() << std::endl; + std::cerr << e.what() << std::endl; throw mrmc::exceptions::InvalidSettings(); } } catch (bpo::error e) { - std::cout << "Some error occurred: " << e.what() << std::endl; + std::cerr << "Some error occurred: " << e.what() << std::endl; } } @@ -92,7 +112,8 @@ Settings::Settings(const int argc, const char* argv[], const char* filename) * * The constructor fills the option descriptions, parses the * command line and the config file and puts the option values to - * our option mapping. + * our option mapping. It also calls all register callbacks that were + * registered via Callbacks and Register classes. * * If a configfile is set in the commandline, we load this one. * Otherwise, if filename is not NULL, we load this one. Otherwise, @@ -122,6 +143,36 @@ Settings* Settings::instance(const int argc, const char* argv[], const char* fil ; Settings::configfile.add_options() ; + + /* + * Call all custom register callbacks. + */ + Callbacks* cb = mrmc::settings::Callbacks::getInstance(); + while (cb->registerList.size() > 0) + { + CallbackType type = cb->registerList.front().first; + RegisterCallback fptr = cb->registerList.front().second; + cb->registerList.pop_front(); + + /* + * Allow modules to specify the type of an option. + */ + switch (type) + { + case CB_CONFIG: + (*fptr)(Settings::configfile); + break; + case CB_CLI: + (*fptr)(Settings::commandline); + break; + case CB_GENERIC: + (*fptr)(Settings::generic); + break; + default: + // hm. is this an error? can this actually happen with an enum? + break; + } + } /* * construct option descriptions for commandline and config file @@ -176,7 +227,6 @@ Settings* instance() { return Settings::inst; } - -} // namespace settings +} // namespace settings } // namespace mrmc diff --git a/src/utility/settings.h b/src/utility/settings.h index abcc139af..10fba3520 100644 --- a/src/utility/settings.h +++ b/src/utility/settings.h @@ -10,6 +10,7 @@ #include #include +#include #include #include "src/exceptions/InvalidSettings.h" @@ -123,13 +124,14 @@ namespace settings { /*! * @brief Function type for functions registering new options. */ - typedef void(*fptr_regOption)(bpo::options_description&); + typedef void(*RegisterCallback)(bpo::options_description&); /*! * @brief Function type for function checking constraints on settings. */ - typedef bool(*fptr_checkOption)(bpo::variables_map&); + typedef bool(*CheckerCallback)(bpo::variables_map&); + enum CallbackType { CB_CONFIG, CB_CLI, CB_GENERIC }; /*! * @brief This class handles callbacks for registering new options and @@ -144,11 +146,11 @@ namespace settings { /*! * @brief Stores register callbacks. */ - std::list reg_list; + std::list> registerList; /*! * @brief Stores check callbacks. */ - std::list check_list; + std::list checkerList; /*! * @brief Private constructor. @@ -167,16 +169,21 @@ namespace settings { * @brief Returns current instance to create singleton. * @return current instance */ - static Callbacks& getInstance() + static Callbacks* getInstance() { static Callbacks instance; - return instance; + return &instance; } /*! * @brief Register class needs access to lists. */ friend class Register; + + /*! + * @brief Settings class need access to lists. + */ + friend class Settings; }; /*! @@ -189,17 +196,17 @@ namespace settings { /*! * @brief Registers given function as register callback. */ - Register(const fptr_regOption ptr) + Register(const CallbackType type, const RegisterCallback ptr) { - mrmc::settings::Callbacks::getInstance().reg_list.push_back(ptr); + mrmc::settings::Callbacks::getInstance()->registerList.push_back(std::pair(type, ptr)); } /*! * @brief Registers given function as check callback. */ - Register(const fptr_checkOption ptr) + Register(const CheckerCallback ptr) { - mrmc::settings::Callbacks::getInstance().check_list.push_back(ptr); + mrmc::settings::Callbacks::getInstance()->checkerList.push_back(ptr); } };