FACT++  1.0
Configuration Class Reference

Commandline parsing, resource file parsing and database access. More...

#include <Configuration.h>

+ Collaboration diagram for Configuration:

Public Member Functions

 Configuration (const std::string &prgname="")
 
virtual ~Configuration ()
 
void AddOptionsCommandline (const po::options_description &cl, bool visible=true)
 
void AddOptionsConfigfile (const po::options_description &cf, bool visible=true)
 
void AddOptionsEnvironment (const po::options_description &env, bool visible=true)
 
void AddOptionsDatabase (const po::options_description &db, bool visible=true)
 
void AddOptions (const po::options_description &opt, bool visible=true)
 
void SetArgumentPositions (const po::positional_options_description &desc)
 
void SetNameMapper (const std::function< std::string(std::string)> &func)
 
void SetNameMapper ()
 
void SetPrintUsage (const std::function< void(void)> &func)
 
void SetPrintUsage ()
 
void SetPrintVersion (const std::function< void(const std::string &)> &func)
 
void SetPrintVersion ()
 
void AddEnv (const std::string &conf, const std::string &env)
 
void PrintOptions () const
 
void PrintUnknown () const
 
void PrintWildcardOptions () const
 
const std::map< std::string, std::string > & GetWildcardOptions () const
 
const std::vector< std::string > GetWildcardOptions (const std::string &opt) const
 
template<class T >
const std::map< std::string, T > GetOptions (const std::string &opt)
 
std::multimap< std::string, std::string > GetOptions () const
 
const po::variables_map & Parse (int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
 
bool DoParse (int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
 
bool HasVersion ()
 
bool HasHelp ()
 
bool HasPrint ()
 
template<class T >
Get (const std::string &var)
 
bool Has (const std::string &var)
 
template<class T >
std::vector< T > Vec (const std::string &var)
 
template<class T , class S >
Get (const std::string &var, const S &val)
 
template<class T >
bool Has (const std::string &var, const T &val)
 
template<class T , class S >
GetDef (const std::string &var, const S &val)
 
template<class T >
bool HasDef (const std::string &var, const T &val)
 
void Remove (const std::string &var)
 
const std::string & GetName () const
 
template<class T >
string VecAsStr (const po::variable_value &v) const
 

Static Public Member Functions

static po::basic_parsed_options< char > parse_database (const std::string &prgname, const std::string &database, const po::options_description &desc, bool allow_unregistered=false)
 Retrieve data from a database and return them as options. More...
 

Public Attributes

bool fDwrite
 
bool fDenable
 
bool fContinousTrigger
 
uint16_t fTriggerRate
 
uint16_t fRoi [FAD::kNumChannelsPerChip]
 
uint16_t fDac [FAD::kNumDac]
 

Private Types

enum  { kHidden = 0, kVisible = 1 }
 Convienience enum to access the fOption* data memebers more verbosely. More...
 

Private Member Functions

std::string DefaultMapper (const std::string env)
 Variables as compiled by the Parse-function, which will be passed to the program. More...
 
void CreateWildcardOptions ()
 Helper for Parse to create list of used wildcard options. More...
 
template<class T >
std::string VecAsStr (const po::variable_value &v) const
 
std::string VarAsStr (const po::variable_value &v) const
 
void PrintParsed (const po::parsed_options &parsed) const
 Print all options from a list of already parsed options. More...
 
void PrintUnknown (const std::vector< std::string > &vec, int steps=1) const
 Print a list of all unkown options within the given vector. More...
 
virtual void PrintUsage () const
 
virtual void PrintVersion () const
 
std::string UnLibToolize (const std::string &src) const
 

Static Private Member Functions

static void Max (int &val, const int &comp)
 Helper function which return the max of the two arguments in the first argument. More...
 

Private Attributes

const std::string fName
 
std::map< std::string, std::string > fEnvMap
 argv[0] More...
 
po::options_description fOptionsCommandline [2]
 
po::options_description fOptionsConfigfile [2]
 Description of the command-line options. More...
 
po::options_description fOptionsDatabase [2]
 Description of the options in the configuration file. More...
 
po::options_description fOptionsEnvironment [2]
 Description of options from the database. More...
 
po::positional_options_description fArgumentPositions
 Description of options from the environment. More...
 
std::vector< std::string > fUnknownCommandline
 Description of positional command-line options (arguments) More...
 
std::vector< std::string > fUnknownConfigfile
 Storage container for unrecognized commandline options. More...
 
std::vector< std::string > fUnknownEnvironment
 Storage container for unrecognized options from configuration files. More...
 
std::vector< std::string > fUnknownDatabase
 Storage container for unrecognized options from the environment. More...
 
std::map< std::string, std::string > fWildcardOptions
 Storage container for unrecognized options retrieved from the database. More...
 
std::string fPriorityFile
 Options which were registered using wildcards. More...
 
std::string fDefaultFile
 File name of the priority configuration file (overwrites option from the databse) More...
 
std::string fDatabase
 File name of the default configuration file (usually {program}.rc) More...
 
po::variables_map fVariables
 URL for database connection (see Configuration::parse_database) More...
 
std::function< std::string(std::string)> fNameMapper
 Pointer to the mapper function for environment variables. More...
 
std::function< void()> fPrintUsage
 
std::function< void(const std::string &)> fPrintVersion
 

Detailed Description

Commandline parsing, resource file parsing and database access.

For the user

The Configuration class will process the following steps:

Check the command-line for –default=default.rc (If no configuration filename is given on the command-line use program_name.rc instead. (Note that the name is retrieved from argv[0] and might change if you start the program through a symbolic link with a different name)

Read the "<B>database=user:password@database:port/database</B>" entry from the file. (For details about the syntax see Configuration::parse_database) The retrieved entry can be overwritten by "<B>--database=user:passwd@server:port/database</B>" from the command line. If neither option is given no configuration data will be read from the database. To suppress any database access use –no-database.

Check the command-line for -C priority.rc

The configuration data is now evaluated from the following sources in the following order. Note that options from earlier source have priority.

  • (1) Commandline options
  • (2) Options from the high prioroty configuration-file (given by -C or –config)
  • (3) Database entries
  • (4) Options from the default configuration-file (given by –default, defaults to program_name.rc)
  • (5) Options from the global configuration-file (constrctor path + fact++.rc)
  • (6) Environment variables

Which options are accepted is defined by the program. To get a list of all command-line option use –help. This also lists all other available options to list for exmaple the options available in the configuration files or from the databse. In addition some default options are available which allow to debug parsing of the options, by either printing the options retrieval or after parsing.

Options in the configuration files must be given in the form

  • key = value

which is equivalent to the command-line option –key=value.

If there are sections in the configuration file like

[section1]
key = value

the key is transformed into section1.key (which would be equivalent to –section1.key)

Attention
In principle it is possible that an exception is thrown before options like –help are properly parsed and evaluated. In this case it is necessary to first resolve the problem. Usually, this mean that there is a design flaw in the program rather than a mistake of usage.

For more details on the order in which configuration is read, check Configuration::Parse. For more details on the parsing itself see the documentation of boost::program_options.

For the programmer

The Configuration class heavily uses the C++ boost library and makes heavy use of the boost::program_options

The databse access is based on the MySQL++ library.

The basic idea is to have an easy to use, but powerfull setup. The setup on all options is based on a special syntax of options_description. Here is an example:

int opt = 0;
po::options_description config("Section");
config.add_options()
("option1", var<string>(), "This is option1")
("option2", var<int>(22), "This is option2")
("option3,o", var<double>->required(), "This option is mandatory")
("option4", var<int>(&opt), "This is option 4")
("option5", vars<string>(), "A list of strings")
("option6", vars<string>(), "A list of strings")
("option7", vars<string>, "A list of strings")
("option8", var<string>()->implicit_value("val"), "Just a string")
("option9", var<string>()->default_value("def"), "Just a string")
("optionA", var<string>("def"), "Just a string")
("bool", po_bool(), "A special switch")
;

This will setup, e.g., the commandline option '–option1 arg' (which is identical to '–option1=arg'. Option 3 can also be expressed in a short form as '-o arg' or '-o=arg'. Option 2 defaults to 22 if no explicit value is given. Option 3 is mandatory and an exceptionb is thrown if not specified. Option 4 will, apart from the usual access to the option values, also store its value in the variable opt.

The used functions po_*() are defined in configuration.h and are abbreviations. Generally speaking also other variable types are possible.

If the options are displayed, e.g. by –help the corresponding section will by titled Section, also untitled sections are possible.

If an option can be given more than once then a std::vector<type> can be used. Abbreviations po_ints(), po_doubles() and po_strings() are available.

There are several ways to define the behaviour of the options. In the example above Parse will throw an exception if the "--option3" or "-o" option is not given. "option9" will evaluate to "def" if it is not given on the command line. The syntax of "optionA" is just an abbreviation. "option8" will evaluate to "val" if just "--option5" but no argument is given. Note, that these modifiers can be concatenated.

A special type po_bool() is provided which is an abbreviation of var<bool>()->implicit_value(true)->default_value(false). In contradiction to po_switch() this allows to set a true and false value in the setup file.

In addition to options introduced by a minus or double minus, so called positional options can be given on the command line. To describe these options use

po::positional_options_description p;
p.add("option5", 2); // The first 2 positional options
p.add("option6", 3); // The next three positional options
// p.add("option7", -1); // All others, if wanted

This assigns option-keys to the positional options (arguments) in the command-line. Note that the validity of the given commandline is checked. Hence, this way of defining the options makes sense.

As needed options_descriptions can be grouped together

po::options_description config1("Section1");
po::options_description config2("Section2");
po::options_description configall;
configall.add(config1);
configall.add(config2);

The member functions of Configurations allow to define for which option source these options are valid. The member functions are:

conf.AddOptionsCommandline(configall, true);
conf.AddOptionsConfigfile(config1, true);
conf.AddOptionsDatabase(config2, true);
// To enable the mapping of the position arguments call this

If the second option is false, the options will not be displayed in any –help directive, but are available to the user. Each of the functions can be called more than once. If an option should be available from all kind of inputs AddOptions() can be used which will call all four other AddOptions() functions.

A special case are the options from environment variables. Since you might want to use the same option-key for the command-line and the environment, a mapping is needed (e.g. from PATH to –path). This mapping can be implemented by a mapping function or by the build in mapping and be initialized like this:

conf.AddEnv("path", "PATH");

or

const string name_mapper(const string str)
{
return str=="PATH" ? "path" : "";
}
conf.SetNameMapper(name_mapper);

Assuming all the above is done in a function calles SetupConfiguration(), a simple program to demonstrate the power of the class could look like this:

int main(int argc, char **argv)
{
int opt;
Configuration conf(argv[0]);
SetupConfiguration(conf, opt);
po::variables_map vm;
try
{
vm = conf.Parse(argc, argv);
}
catch (std::exception &e)
{
po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
if (MO)
cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
else
cout << "Error: " << e.what() << endl;
cout << endl;
return -1;
}
cout << "Opt1: " << conf.GetString("option1") << endl;
cout << "Opt2: " << conf.GetInt("option2") << endl;
cout << "Opt3: " << conf.GetDouble("option3") << endl;
cout << "Opt4: " << opt << endl;
return 0;
}

Another possibility to access the result is the direct approach, for example:

vector<int> i = vm["option2"].as<int>();
vector<string> vec = vm["option6"].as<vector<string>>();

Note that accessing an option which was not given will throw an exception. Therefor its availability should first be checked in one of the following ways:

bool has_option1 = vm.count("option1");
bool has_option2 = conf.Has("option2");

Extensions

The configuration interpreter can be easily extended to new types, for example:

template<class T,class S> // Just for the output
std::ostream &operator<<(std::ostream &out, const pair<T,S> &f)
{
out << f.first << "|" << f.second;
return out;
}
template<class T, class S> // Needed to convert the option
std::istream &operator>>(std::istream &in, pair<T,S> &f)
{
char c;
in >> f.first;
in >> c;
if (c!=':')
return in;
in >> f.second;
return in;
}
typedef pair<int,int> mytype; // Type definition
void main(int argc, char **argv)
{
po::options_description config("Configuration");
config.add_options()
("mytype", var<mytype>(), "my new type")
;
conf.AddOptionsCommandline(config);
conf.Parse(argc, argv);
cout << conf.Get<mytype>("mytype") << endl;
}

Examples

  • An example can be found in argv.cc
Todo:
  • Maybe we should remove the necessity to propagate argv[0] in the constructor?
  • Add an option to the constructor to switch of database/file access
Examples:
argv.cc, and chatserv.cc.

Definition at line 9 of file Configuration.h.


The documentation for this class was generated from the following files: