Browse Source

completed work on intermediate callbacks and restructured settings class

tempestpy_adaptions
gereon 12 years ago
parent
commit
cd4463116e
  1. 2
      src/mrmc.cpp
  2. 316
      src/utility/settings.cpp
  3. 82
      src/utility/settings.h

2
src/mrmc.cpp

@ -74,7 +74,7 @@ int main(const int argc, const char* argv[]) {
LOG4CPLUS_INFO(logger, "MRMC command invoked " << commandStream.str());
try {
s = mrmc::settings::Settings::instance(argc, argv, nullptr);
s = mrmc::settings::newInstance(argc, argv, nullptr);
} catch (mrmc::exceptions::InvalidSettings&) {
LOG4CPLUS_FATAL(logger, "Could not recover from settings error, terminating.");
std::cout << std::endl << mrmc::settings::help << std::endl;

316
src/utility/settings.cpp

@ -7,24 +7,17 @@
#include "src/utility/settings.h"
#include <iostream>
//#include <boost/program_options.hpp>
//#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;
/*
* static initializers
*/
bpo::options_description* mrmc::settings::Settings::cli = nullptr;
bpo::options_description* mrmc::settings::Settings::conf = nullptr;
mrmc::settings::Settings* mrmc::settings::Settings::inst = nullptr;
/*!
* The constructor fills the option descriptions, parses the
@ -37,163 +30,220 @@ mrmc::settings::Settings* mrmc::settings::Settings::inst = NULL;
*
* @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
* @param filename either nullptr or name of config file
*/
Settings::Settings(const int argc, const char* argv[], const char* filename)
: configfile("Config Options"), generic("Generic Options"), commandline("Commandline Options")
{
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<char>(this->vm["configfile"].as<std::string>().c_str(), this->conf), this->vm, true);
}
else if (filename != NULL)
//! Initially fill description objects and call register callbacks
this->initDescriptions();
//! Take care of positional arguments
Settings::positional.add("trafile", 1);
Settings::positional.add("labfile", 1);
//! Create and fill collecting options descriptions
Settings::cli = new bpo::options_description();
Settings::cli->add(Settings::commandline).add(generic);
Settings::conf = new bpo::options_description();
Settings::conf->add(Settings::configfile).add(generic);
//! Perform first parse run and call intermediate callbacks
this->firstRun(argc, argv, filename);
//! Rebuild collecting options descriptions
delete Settings::cli;
Settings::cli = new bpo::options_description();
Settings::cli->add(Settings::commandline).add(generic);
delete Settings::conf;
Settings::conf = new bpo::options_description();
Settings::conf->add(Settings::configfile).add(generic);
//! Stop if help is set
if ((this->vm.count("help") > 0) || (this->vm.count("help-config") > 0))
{
bpo::store(bpo::parse_config_file<char>(filename, this->conf), this->vm, true);
return;
}
/*
* 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();
//! Perform second run and call checker callbacks
this->secondRun(argc, argv, filename);
if (! (*fptr)(this->vm))
{
std::cerr << "Custom option checker failed." << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
}
//! Finalize parsed options, check for specified requirements
bpo::notify(this->vm);
}
/*
* catch errors...
*/
catch (bpo::reading_file e)
{
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::cerr << e.what() << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
std::cerr << "required option: " << e.what() << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
catch (bpo::validation_error e)
{
std::cerr << "Validation failed: " << e.what() << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
catch (bpo::invalid_command_line_syntax e)
{
std::cerr << "Invalid command line syntax: " << e.what() << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
catch (bpo::error e)
{
std::cerr << "Some error occurred: " << e.what() << std::endl;
std::cerr << e.what() << std::endl;
throw mrmc::exceptions::InvalidSettings();
}
}
/*!
* 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. 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,
* 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
* Initially fill options_description objects.
* First puts some generic options, then calls all register Callbacks.
*/
Settings* Settings::instance(const int argc, const char* argv[], const char* filename)
void Settings::initDescriptions()
{
if (Settings::inst == NULL) {
/*
* fill option descriptions
*/
Settings::commandline.add_options()
("help,h", "produce help message")
("verbose,v", "be verbose")
("help-config", "produce help message about config file")
("configfile,c", bpo::value<std::string>(), "name of config file")
("test-prctl", bpo::value<std::string>(), "name of prctl file")
;
Settings::generic.add_options()
("trafile", bpo::value<std::string>()->required(), "name of the .tra file")
("labfile", bpo::value<std::string>()->required(), "name of the .lab file")
;
Settings::configfile.add_options()
;
/*
* Call all custom register callbacks.
*/
Callbacks* cb = mrmc::settings::Callbacks::getInstance();
while (cb->registerList.size() > 0)
this->commandline.add_options()
("help,h", "produce help message")
("verbose,v", "be verbose")
("help-config", "produce help message about config file")
("configfile,c", bpo::value<std::string>(), "name of config file")
("test-prctl", bpo::value<std::string>(), "name of prctl file")
;
this->generic.add_options()
("trafile", bpo::value<std::string>()->required(), "name of the .tra file")
("labfile", bpo::value<std::string>()->required(), "name of the .lab file")
;
this->configfile.add_options()
;
/*
* Get Callbacks object, then iterate over and call all 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();
switch (type)
{
CallbackType type = cb->registerList.front().first;
RegisterCallback fptr = cb->registerList.front().second;
cb->registerList.pop_front();
case CB_CONFIG:
(*fptr)(this->configfile);
break;
case CB_CLI:
(*fptr)(this->commandline);
break;
case CB_GENERIC:
(*fptr)(this->generic);
break;
}
}
}
/*!
* Perform a sloppy parsing run: parse command line and config file (if
* given), but allow for unregistered options, do not check requirements
* from options_description objects, do not check positional arguments.
*
* Call all intermediate callbacks afterwards.
*/
void Settings::firstRun(const int argc, const char* argv[], const char* filename)
{
//! parse command line
bpo::store(bpo::command_line_parser(argc, argv).options(*(Settings::cli)).allow_unregistered().run(), this->vm);
/*
* load config file if specified
*/
if (this->vm.count("configfile"))
{
bpo::store(bpo::parse_config_file<char>(this->vm["configfile"].as<std::string>().c_str(), *(Settings::conf)), this->vm, true);
}
else if (filename != NULL)
{
bpo::store(bpo::parse_config_file<char>(filename, *(Settings::conf)), this->vm, true);
}
/*
* Allow modules to specify the type of an option.
*/
/*
* Call intermediate callbacks.
*/
Callbacks* cb = mrmc::settings::Callbacks::getInstance();
while (cb->intermediateList.size() > 0)
{
CallbackType type = cb->intermediateList.front().first;
IntermediateCallback fptr = cb->intermediateList.front().second;
cb->intermediateList.pop_front();
try
{
switch (type)
{
case CB_CONFIG:
(*fptr)(Settings::configfile);
(*fptr)(&this->configfile, this->vm);
break;
case CB_CLI:
(*fptr)(Settings::commandline);
(*fptr)(&this->commandline, this->vm);
break;
case CB_GENERIC:
(*fptr)(Settings::generic);
break;
default:
// hm. is this an error? can this actually happen with an enum?
(*fptr)(&this->generic, this->vm);
break;
}
}
catch (boost::bad_any_cast e)
{
std::cerr << "An intermediate callback failed." << std::endl;
std::cerr << e.what() << std::endl;
}
}
}
/*
* construct option descriptions for commandline and config file
*/
Settings::cli.add(Settings::commandline).add(generic);
Settings::conf.add(Settings::configfile).add(generic);
/*!
* Perform the second parser run: parse command line and config file (if
* given) and check for unregistered options, requirements from
* options_description objects and positional arguments.
*
* Call all checker callbacks afterwards.
*/
void Settings::secondRun(const int argc, const char* argv[], const char* filename)
{
//! Parse command line
bpo::store(bpo::command_line_parser(argc, argv).options(*(Settings::cli)).positional(this->positional).run(), this->vm);
/*
* load config file if specified
*/
if (this->vm.count("configfile"))
{
bpo::store(bpo::parse_config_file<char>(this->vm["configfile"].as<std::string>().c_str(), *(Settings::conf)), this->vm, true);
}
else if (filename != NULL)
{
bpo::store(bpo::parse_config_file<char>(filename, *(Settings::conf)), this->vm, true);
}
/*
* 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);
/*
* Call checker callbacks.
*/
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();
}
}
return Settings::inst;
}
/*!
* Print a short general usage information consisting of the positional
* options and the list of available command line options.
@ -204,7 +254,7 @@ Settings* Settings::instance(const int argc, const char* argv[], const char* fil
std::ostream& help(std::ostream& os)
{
os << "Usage: <binary> [options] <transition file> <label file>" << std::endl;
os << Settings::cli << std::endl;;
os << *(mrmc::settings::Settings::cli) << std::endl;;
return os;
}
@ -216,17 +266,9 @@ std::ostream& help(std::ostream& os)
*/
std::ostream& helpConfigfile(std::ostream& os)
{
os << Settings::conf << std::endl;;
os << *(mrmc::settings::Settings::conf) << std::endl;;
return os;
}
/*!
* @return current instance.
*/
Settings* instance()
{
return Settings::inst;
}
} // namespace settings
} // namespace mrmc

82
src/utility/settings.h

@ -45,6 +45,8 @@ namespace settings {
*/
template <typename T>
const T& get(const std::string &name) const {
std::cerr << "get(" << name << ")" << std::endl;
if (this->vm.count(name) == 0) throw mrmc::exceptions::InvalidSettings();
return this->vm[name].as<T>();
}
@ -65,11 +67,7 @@ namespace settings {
friend std::ostream& help(std::ostream& os);
friend std::ostream& helpConfigfile(std::ostream& os);
friend Settings* instance();
/*!
* @brief Creates a new instance.
*/
static Settings* instance(const int argc, const char* argv[], const char* filename);
friend Settings* newInstance(const int argc, const char* argv[], const char* filename);
private:
/*!
@ -78,21 +76,45 @@ namespace settings {
Settings(const int argc, const char* argv[], const char* filename);
/*!
* @brief Option descriptions.
* @brief Initialize options_description object.
*/
static bpo::options_description configfile;
static bpo::options_description generic;
static bpo::options_description commandline;
static bpo::positional_options_description positional;
void initDescriptions();
/*!
* @brief Collecting option descriptions.
*
* The options for command line and config file are collected
* here.
* @brief Perform first parser run
*/
static bpo::options_description cli;
static bpo::options_description conf;
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 descriptions for config file.
*/
bpo::options_description configfile;
/*!
* @brief Option descriptions for config file and command line.
*/
bpo::options_description generic;
/*!
* @brief Option descriptions for command line.
*/
bpo::options_description commandline;
/*!
* @brief Option description for positional arguments on command line.
*/
bpo::positional_options_description positional;
/*!
* @brief Collecting option descriptions for command line.
*/
static bpo::options_description* cli;
/*!
* @brief Collecting option descriptions for config file.
*/
static bpo::options_description* conf;
/*!
* @brief option mapping.
@ -117,8 +139,30 @@ namespace settings {
/*!
* @brief Return current instance.
*
* @return The current instance of Settings created by newInstance().
*/
Settings* instance();
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;
}
/*!
@ -130,7 +174,7 @@ namespace settings {
* @brief Function type for functions changing the parser state
* between the first and second run.
*/
typedef void(*IntermediateCallback)(bpo::options_description&, bpo::variables_map&);
typedef void(*IntermediateCallback)(bpo::options_description*, bpo::variables_map&);
/*!
* @brief Function type for function checking constraints on settings.
@ -194,7 +238,7 @@ namespace settings {
* @brief Returns current instance to create singleton.
* @return current instance
*/
static Callbacks* getInstance()
inline static Callbacks* getInstance()
{
static Callbacks instance;
return &instance;

Loading…
Cancel
Save