From a5a045f091a19b9828e5406a9d1ec836ab81d5ab Mon Sep 17 00:00:00 2001 From: gereon Date: Fri, 23 Nov 2012 00:26:24 +0100 Subject: [PATCH] Changed Settings class to be singleton Changed a lot in the class structure of Settings: * Settings is now a Singleton. Obtain a new instance by Settings::instance(). * options_description objects are now static, thus a help message can be printed even if the constructor of Settings failes * As Settings has static members, a .cpp file became necessary, hence cmake should probably be run... * Help messages can be printed with new help and helpConfigfile routines --- src/mrmc-cpp.cpp | 9 +- src/utility/settings.cpp | 179 +++++++++++++++++++++++++++++++++++++++ src/utility/settings.h | 167 ++++++++++++++---------------------- 3 files changed, 248 insertions(+), 107 deletions(-) create mode 100644 src/utility/settings.cpp diff --git a/src/mrmc-cpp.cpp b/src/mrmc-cpp.cpp index 2de514550..3c063a8e5 100644 --- a/src/mrmc-cpp.cpp +++ b/src/mrmc-cpp.cpp @@ -42,22 +42,23 @@ int main(const int argc, const char* argv[]) { try { - s = new mrmc::settings::Settings(argc, argv, NULL); + s = mrmc::settings::Settings::instance(argc, argv, NULL); } catch (mrmc::exceptions::InvalidSettings) { - std::cout << "Could not recover from settings error, terminating." << std::endl; + std::cout << "Could not recover from settings error, terminating." << std::endl << std::endl; + std::cout << mrmc::settings::help << std::endl; return 1; } if (s->isSet("help")) { - std::cout << s->getHelpForCommandline() << std::endl; + std::cout << mrmc::settings::help << std::endl; return 0; } if (s->isSet("help-config")) { - std::cout << s->getHelpForConfigfile() << std::endl; + std::cout << mrmc::settings::helpConfigfile << std::endl; return 0; } diff --git a/src/utility/settings.cpp b/src/utility/settings.cpp new file mode 100644 index 000000000..daf08634b --- /dev/null +++ b/src/utility/settings.cpp @@ -0,0 +1,179 @@ +/* + * settings.cpp + * + * Created on: 22.11.2012 + * Author: Gereon Kremer + */ + +#include "src/utility/settings.h" + +//#include +//#include +//#include "src/exceptions/InvalidSettings.h" + +namespace mrmc { +namespace settings { + +namespace bpo = boost::program_options; + +bpo::options_description mrmc::settings::Settings::configfile("Config Options"); +bpo::options_description mrmc::settings::Settings::generic("Generic Options"); +bpo::options_description mrmc::settings::Settings::commandline("Commandline Options"); +bpo::positional_options_description mrmc::settings::Settings::positional; + +bpo::options_description mrmc::settings::Settings::cli; +bpo::options_description mrmc::settings::Settings::conf; + +mrmc::settings::Settings* mrmc::settings::Settings::inst = NULL; + +/*! + * The constructor fills the option descriptions, parses the + * command line and the config file and puts the option values to + * our option mapping. + * + * If a configfile is set in the commandline, we load this one. + * Otherwise, if filename is not NULL, we load this one. Otherwise, + * we load no config file. + * + * @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 + */ +Settings::Settings(const int argc, const char* argv[], const char* filename) +{ + try + { + /* + * load command line + */ + bpo::store(bpo::command_line_parser(argc, argv).options(this->cli).positional(this->positional).run(), this->vm); + /* + * load config file if specified + */ + if (this->vm.count("configfile")) + { + bpo::store(bpo::parse_config_file(this->vm["configfile"].as().c_str(), this->conf), this->vm, true); + } + else if (filename != NULL) + { + bpo::store(bpo::parse_config_file(filename, this->conf), this->vm, true); + } + bpo::notify(this->vm); + } + /* + * catch errors... + */ + catch (bpo::reading_file e) + { + std::cout << "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; + throw mrmc::exceptions::InvalidSettings(); + } + } + catch (bpo::error e) + { + std::cout << "Some error occurred: " << e.what() << std::endl; + } +} + +/*! + * Creates a new instance if necessary. When the instance is actually + * created for the first time, the internal options_description objects are + * initialized. + * + * If this function was already called and another instance is + * already present, the existing instance will be returned. In this + * case, better use the routine mrmc::settings::instance(). + * + * The constructor fills the option descriptions, parses the + * command line and the config file and puts the option values to + * our option mapping. + * + * If a configfile is set in the commandline, we load this one. + * Otherwise, if filename is not NULL, we load this one. Otherwise, + * we load no config file. + * + * @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 instance of Settings + */ +Settings* Settings::instance(const int argc, const char* argv[], const char* filename) +{ + if (Settings::inst == NULL) { + /* + * fill option descriptions + */ + Settings::commandline.add_options() + ("help", "produce help message") + ("help-config", "produce help message about config file") + ("configfile", bpo::value(), "name of config file") + ; + Settings::generic.add_options() + ("trafile", bpo::value()->required(), "name of the .tra file") + ("labfile", bpo::value()->required(), "name of the .lab file") + ; + Settings::configfile.add_options() + ; + + /* + * construct option descriptions for commandline and config file + */ + Settings::cli.add(Settings::commandline).add(generic); + Settings::conf.add(Settings::configfile).add(generic); + + /* + * Take care of positional arguments + */ + Settings::positional.add("trafile", 1); + Settings::positional.add("labfile", 1); + + /* + * Actually create new instance + */ + Settings::inst = new Settings(argc, argv, filename); + } + return Settings::inst; +} + +/*! + * Print a short general usage information consisting of the positional + * options and the list of available command line options. + * + * Use it like this: + * @code std::cout << mrmc::settings::help; @endcode + */ +std::ostream& help(std::ostream& os) +{ + os << "Usage: [options]