/* * settings.h * * Created on: 22.11.2012 * Author: Gereon Kremer */ #ifndef SETTINGS_H_ #define SETTINGS_H_ #include #include #include #include #include #include #include "src/exceptions/InvalidSettings.h" namespace mrmc { /*! * @brief Contains Settings class and associated methods. * * The settings namespace contains the Settings class some friend methods like instance(). */ namespace settings { namespace bpo = boost::program_options; /* * Sorry for very long comment at this point (for the class), but all * methods are private, hence there is no other place to explain the * inner workings of this class that are necessary to understand the * callback concept... */ /*! * @brief Simple wrapper around boost::program_options to handle configuration options. * * This class uses boost::program_options to read options from the * commandline and additionally load options from a file. * * It is meant to be used as a singleton. Call * @code mrmc::settings::newInstance(argc, argv, filename) @endcode * to initialize it and obtain an instance for the first time. * Afterwards, use * @code mrmc::settings::instance() @endcode * * This class can be customized by other parts of the software using * callbacks. There are three types of callbacks: register, * intermediate and checker. * * The (private) constructor will start with filling the internal * options_description object. There are a few generic options like * --help or --verbose. Then if calls all register callbacks that may * add more options. * * Then, it will start with a sloppy parsing run, allowing unregistered * options and ignoring further constraints from the options_description * objects. * * After that, it will call all intermediate callbacks. They can * inspect the options from the first run and add more options, e.g. * enable more options for a specific component that has been enabled. * * Using the new options_description objects, the constructor performs * a second run. This time, it will not allow unregistered options and * will check for required and positional arguments. * * Finally, all checker callbacks will be called. They can check the * final options for more complex requirements. If any of those checker * callbacks returns false, a InvalidSettings exception will be thrown. */ class Settings { public: /*! * @brief Get value of a generic option. */ template const T& get(const std::string &name) const { if (this->vm.count(name) == 0) throw mrmc::exceptions::InvalidSettings(); return this->vm[name].as(); } /*! * @brief Get value of string option */ const std::string& getString(const std::string &name) const { return this->get(name); } /*! * @brief Check if an option is set */ const bool isSet(const std::string &name) const { return this->vm.count(name) > 0; } /*! * @brief Register a new module * * This function implicitly defines the following interface for any SettingsModule: * @code * static std::string getModuleName(); * static std::pair< std::string, std::string > getOptionTrigger(); * static void putOptions(boost::program_options::options_description*); * @endcode */ template static void registerModule() { std::pair< std::string, std::string > trigger = T::getOptionTrigger(); std::stringstream str; str << T::getModuleName() << " (" << trigger.first << " = " << trigger.second << ")"; bpo::options_description* desc = new bpo::options_description(str.str()); T::putOptions(desc); Settings::modules[ trigger ] = desc; } friend std::ostream& help(std::ostream& os); friend std::ostream& helpConfigfile(std::ostream& os); friend Settings* instance(); friend Settings* newInstance(const int argc, const char* argv[], const char* filename); private: /*! * @brief Constructor. */ Settings(const int argc, const char* argv[], const char* filename); /*! * @brief Initialize options_description object. */ void initDescriptions(); /*! * @brief Perform first parser run */ void firstRun(const int argc, const char* argv[], const char* filename); /*! * @brief Perform second parser run. */ void secondRun(const int argc, const char* argv[], const char* filename); /*! * @brief Option description for positional arguments on command line. */ bpo::positional_options_description positional; /*! * @brief Collecting option descriptions. */ static std::unique_ptr desc; /*! * @brief Contains option descriptions for all modules. */ static std::map< std::pair< std::string, std::string >, bpo::options_description* > modules; /*! * @brief option mapping. */ bpo::variables_map vm; /*! * @brief name of binary */ static std::string binaryName; /*! * @brief actual instance of this class. */ static Settings* inst; }; /*! * @brief Print usage help. */ std::ostream& help(std::ostream& os); /*! * @brief Print help for config file options. */ std::ostream& helpConfigfile(std::ostream& os); /*! * @brief Return current instance. * * @return The current instance of Settings created by newInstance(). */ inline Settings* instance() { return Settings::inst; } /*! * @brief Create new instance. * * Creates a new Settings instance and passes the arguments to the constructor of Settings. * * @param argc should be argc passed to main function * @param argv should be argv passed to main function * @param filename either NULL or name of config file * @return The new instance of Settings. */ inline Settings* newInstance(const int argc, const char* argv[], const char* filename) { if (Settings::inst != nullptr) delete Settings::inst; Settings::inst = new Settings(argc, argv, filename); return Settings::inst; } } // namespace settings } // namespace mrmc #endif // SETTINGS_H_