source: trunk/FACT++/src/Configuration.cc @ 19454

Last change on this file since 19454 was 19454, checked in by tbretz, 8 weeks ago
I directly split now filename and default path into the two resources, this is more transparent for the user.
File size: 50.3 KB
Line 
1// **************************************************************************
2/** @class Configuration
3
4@brief Commandline parsing, resource file parsing and database access
5
6
7@section User For the user
8
9The Configuration class will process the following steps:
10
11Check the command-line for <B> --default=default.rc </B> (If no configuration
12filename is given on the command-line use \e program_name.rc instead. (Note
13that the name is retrieved from \b argv[0] and might change if you start
14the program through a symbolic link with a different name)
15
16Read the "<B>database=user:password@database:port/database</B>" entry from the file.
17(For details about the syntax see Configuration::parse_database)
18The retrieved entry can be overwritten by
19"<B>--database=user:passwd@server:port/database</B>" from the command line. If
20neither option is given no configuration data will be read from the
21database. To suppress any database access use \b --no-database.
22
23Check the command-line for <B> -C priority.rc </B>
24
25The configuration data is now evaluated from the following sources in
26the following order. Note that options from earlier source have
27priority.
28
29   - (1) Commandline options
30   - (2) Options from the high priority configuration-file (given by \b -C or \b --config)
31   - (3) Database entries
32   - (4) Options from the default configuration-file (given by \b --default, defaults to \b program_name.rc)
33   - (5) Options from the global configuration-file (constructor path + \b fact++.rc)
34   - (6) Environment variables
35
36Which options are accepted is defined by the program. To get a list
37of all command-line option use \b --help. This also lists all other
38available options to list for exmaple the options available in the
39configuration files or from the databse. In addition some default options
40are available which allow to debug parsing of the options, by either printing
41the options retrieval or after parsing.
42
43Options in the configuration files must be given in the form
44
45   - key = value
46
47which is equivalent to the command-line option <B>--key=value</B>.
48
49If there are sections in the configuration file like
50
51\code
52
53   [section1]
54   key = value
55
56\endcode
57
58the key is transformed into <B>section1.key</B> (which would be equivalent
59to <B>--section1.key</B>)
60
61@attention
62In principle it is possible that an exception is thrown before options
63like \b --help are properly parsed and evaluated. In this case it is
64necessary to first resolve the problem. Usually, this mean that there
65is a design flaw in the program rather than a mistake of usage.
66
67For more details on the order in which configuration is read,
68check Configuration::Parse. For more details on the parsing itself
69see the documentation of boost::program_options.
70
71
72
73
74@section API For the programmer
75
76The Configuration class heavily uses the
77<A HREF="http://www.boost.org"><B>C++ boost library</B></A>
78and makes heavy use of the
79<A HREF="http://www.boost.org/doc/libs/release/doc/html/program_options.html">
80<B>boost::program_options</B></A>
81
82The databse access is based on the
83<A HREF="http://tangentsoft.net/mysql++/"><B>MySQL++ library</B></A>.
84
85The basic idea is to have an easy to use, but powerfull setup. The setup on
86all options is based on a special syntax of options_description. Here is an
87example:
88
89\code
90
91    int opt = 0;
92
93    po::options_description config("Section");
94    config.add_options()
95        ("option1",    var<string>(),                        "This is option1")
96        ("option2",    var<int>(22),                         "This is option2")
97        ("option3,o",  var<double>->required(),              "This option is mandatory")
98        ("option4",    var<int>(&opt),                       "This is option 4")
99        ("option5",    vars<string>(),                       "A list of strings")
100        ("option6",    vars<string>(),                       "A list of strings")
101        ("option7",    vars<string>,                         "A list of strings")
102        ("option8",    var<string>()->implicit_value("val"), "Just a string")
103        ("option9",    var<string>()->default_value("def"),  "Just a string")
104        ("optionA",    var<string>("def"),                   "Just a string")
105        ("bool",       po_bool(),                            "A special switch")
106        ;
107
108\endcode
109
110This will setup, e.g.,  the commandline option '<B>--option1 arg</B>' (which
111is identical to '<B>--option1=arg</B>'. Option 3 can also be expressed
112in a short form as '<B>-o arg</B>' or '<B>-o=arg</B>'. Option 2 defaults
113to 22 if no explicit value is given. Option 3 is mandatory and an exceptionb
114is thrown if not specified. Option 4 will, apart from the usual access to the
115option values, also store its value in the variable opt.
116
117The used functions po_*() are defined in configuration.h and are abbreviations.
118Generally speaking also other variable types are possible.
119
120If the options are displayed, e.g. by \b --help the corresponding section will
121by titled \e Section, also untitled sections are possible.
122
123If an option can be given more than once then a std::vector<type> can be used.
124Abbreviations po_ints(), po_doubles() and po_strings() are available.
125
126There are several ways to define the behaviour of the options. In the
127example above Parse will throw an exception if the "--option3" or "-o"
128option is not given. "option9" will evaluate to "def" if it is not
129given on the command line. The syntax of "optionA" is just an
130abbreviation. "option8" will evaluate to "val" if just "--option5" but
131no argument is given. Note, that these modifiers can be concatenated.
132
133A special type po_bool() is provided which is an abbreviation of
134var<bool>()->implicit_value(true)->default_value(false). In
135contradiction to po_switch() this allows to set a true and
136false value in the setup file.
137
138In addition to options introduced by a minus or double minus, so called
139positional options can be given on the command line. To describe these
140options use
141
142\code
143
144    po::positional_options_description p;
145    p.add("option5", 2); // The first 2 positional options
146    p.add("option6", 3); // The next three positional options
147    // p.add("option7", -1); // All others, if wanted
148
149\endcode
150
151This assigns option-keys to the positional options (arguments) in the
152command-line. Note that the validity of the given commandline is checked.
153Hence, this way of defining the options makes sense.
154
155As needed options_descriptions can be grouped together
156
157\code
158
159    po::options_description config1("Section1");
160    po::options_description config2("Section2");
161
162    po::options_description configall;
163    configall.add(config1);
164    configall.add(config2);
165
166\endcode
167
168The member functions of Configurations allow to define for which option
169source these options are valid. The member functions are:
170
171\code
172
173    Configuration conf;
174
175    conf.AddOptionsCommandline(configall, true);
176    conf.AddOptionsConfigfile(config1, true);
177    conf.AddOptionsDatabase(config2, true);
178
179    // To enable the mapping of the position arguments call this
180    conf.SetArgumentPositions(p);
181
182\endcode
183
184If the second option is false, the options will not be displayed in any
185\b --help directive, but are available to the user. Each of the functions
186can be called more than once. If an option should be available from
187all kind of inputs AddOptions() can be used which will call all
188four other AddOptions() functions.
189
190A special case are the options from environment variables. Since you might
191want to use the same option-key for the command-line and the environment,
192a mapping is needed (e.g. from \b PATH to \b --path). This mapping
193can be implemented by a mapping function or by the build in mapping
194and be initialized like this:
195
196\code
197
198   conf.AddEnv("path", "PATH");
199
200\endcode
201
202or
203
204\code
205
206   const string name_mapper(const string str)
207   {
208      return str=="PATH" ? "path" : "";
209   }
210
211   conf.SetNameMapper(name_mapper);
212
213\endcode
214
215Assuming all the above is done in a function calles SetupConfiguration(),
216a simple program to demonstrate the power of the class could look like this:
217
218\code
219
220   int main(int argc, char **argv)
221   {
222       int opt;
223
224       Configuration conf(argv[0]);
225       SetupConfiguration(conf, opt);
226
227       po::variables_map vm;
228       try
229       {
230          vm = conf.Parse(argc, argv);
231       }
232       catch (std::exception &e)
233       {
234           po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
235           if (MO)
236               cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
237           else
238               cout << "Error: " << e.what() << endl;
239           cout << endl;
240
241           return -1;
242       }
243
244       cout << "Opt1: " << conf.GetString("option1") << endl;
245       cout << "Opt2: " << conf.GetInt("option2") << endl;
246       cout << "Opt3: " << conf.GetDouble("option3") << endl;
247       cout << "Opt4: " << opt << endl;
248
249       return 0;
250   }
251
252\endcode
253
254Another possibility to access the result is the direct approach, for example:
255
256\code
257
258   vector<int>    i   = vm["option2"].as<int>();
259   vector<string> vec = vm["option6"].as<vector<string>>();
260
261\endcode
262
263Note that accessing an option which was not given will throw an exception.
264Therefor its availability should first be checked in one of the following
265ways:
266
267\code
268
269   bool has_option1 = vm.count("option1");
270   bool has_option2 = conf.Has("option2");
271
272\endcode
273
274@section Extensions
275
276The configuration interpreter can be easily extended to new types, for example:
277
278\code
279
280template<class T,class S> // Just for the output
281   std::ostream &operator<<(std::ostream &out, const pair<T,S> &f)
282   {
283       out << f.first << "|" << f.second;
284       return out;
285   }
286
287template<class T, class S> // Needed to convert the option
288   std::istream &operator>>(std::istream &in,  pair<T,S> &f)
289   {
290       char c;
291       in >> f.first;
292       in >> c;
293       if (c!=':')
294           return in;
295       in >> f.second;
296       return in;
297   }
298
299typedef pair<int,int> mytype; // Type definition
300
301void main(int argc, char **argv)
302{
303   po::options_description config("Configuration");
304   config.add_options()
305        ("mytype", var<mytype>(), "my new type")
306        ;
307
308   Configuration conf;
309   conf.AddOptionsCommandline(config);
310   conf.Parse(argc, argv);
311
312   cout << conf.Get<mytype>("mytype") << endl;
313}
314
315\endcode
316
317@section Examples
318
319 - An example can be found in \ref argv.cc
320
321@todo
322
323 - Maybe we should remove the necessity to propagate argv[0] in the constructor?
324 - Add an option to the constructor to switch of database/file access
325
326*/
327// **************************************************************************
328#include "Configuration.h"
329
330#include <fstream>
331#include <iostream>
332#include <iomanip>
333
334#ifdef HAVE_SQL
335#include "Database.h"
336#endif
337
338using namespace std;
339
340namespace style = boost::program_options::command_line_style;
341
342// --------------------------------------------------------------------------
343//
344//!  The purpose of this function is basically to connect to the database,
345//!  and retrieve all the options entries from the 'Configuration' table.
346//!
347//!  @param database
348//!      The URL of the database from which the configuration data is
349//!      retrieved. It should be given in the form
350//!          \li [user[:password]@]server.com[:port]/database[?compress=0|1]
351//!
352//!      with
353//!          - user:     user name (default is the current user)
354//!          - password: necessary if required by the database rights
355//!          - server:   the URL of the server (can be 'localhost')
356//!          - port:     the port to which to connect (usually obsolete)
357//!          - database: The name of the database containing the table
358//!          - compress: Force [=1] / prohibit [=0] compression
359//!
360//!  The default is that connections to the SQL server are compressed
361//!  whenever the server is neither '127.0.0.1' nor 'localhost'.
362//!  Use '/+' to force compression and '/-' to prohibit compression.
363//!
364//!  @param desc
365//!     A reference to the object with the description of the options
366//!     which should be retrieved.
367//!
368//!  @param allow_unregistered
369//!     If this is true also unregistered, i.e. options unknown to desc,
370//!     are returned. Otherwise an exception is thrown if such an option
371//!     was retrieved.
372//!
373//!  @return
374//!     Return an object of type basic_parsed_options containing all
375//!     the entries retrieved from the database. Options not found in
376//!     desc are flagged as unregistered.
377//!
378//!  @throws
379//!     Two types of exceptions are thrown
380//!        - It thows an unnamed exception if the options could not be
381//!          retrieved properly from the databse.
382//!        - If an option is not registered within the given descriptions
383//!          and \b allow_unregistered is \b false, an exception of type
384//!          \b  po::unknown_option is thrown.
385//!
386//!  @todo
387//!     - The exceptions handling should be improved.
388//!     - The final database layout is missing in the description
389//!     - Shell we allow options to be given more than once?
390//
391#ifdef HAVE_SQL
392po::basic_parsed_options<char>
393    Configuration::parse_database(const string &prgname, const string &database, const po::options_description& desc, bool allow_unregistered)
394{
395    Database db(database);
396
397    cerr << "Connected to '" << db.uri() << "' for " << prgname << endl;
398
399    const mysqlpp::StoreQueryResult res =
400        db.query("SELECT CONCAT(fKey1,fKey2), fValue "
401                 "FROM ProgramOption "
402                 "WHERE fCounter=(SELECT MAX(fCounter) FROM History) "
403                 "AND NOT ISNULL(fValue) "
404                 "AND (fProgram='"+prgname+"' OR fProgram='*')").store();
405
406    set<string> allowed_options;
407
408    const vector<boost::shared_ptr<po::option_description>> &options = desc.options();
409    for (unsigned i=0; i<options.size(); ++i)
410    {
411        const po::option_description &d = *options[i];
412        if (d.long_name().empty())
413            boost::throw_exception(po::error("long name required for database"));
414
415        allowed_options.insert(d.long_name());
416    }
417
418    po::parsed_options result(&desc);
419
420    for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
421    {
422        const string key = (*v)[0].c_str();
423        if (key.empty())  // key  == > Throw exception
424            continue;
425
426        // Check if we are allowed to accept unregistered options,
427        // i.e. options which are not in options_description &desc.
428        const bool unregistered = allowed_options.find(key)==allowed_options.end();
429        if (unregistered && allow_unregistered)
430            boost::throw_exception(po::unknown_option(key));
431
432        // Create a key/value-pair and store whether it is a
433        // registered option of not
434        po::option n;
435        n.string_key = key;
436        // This is now identical to file parsing. What if we want
437        // to concatenate options like on the command line?
438        n.value.clear();          // Fixme: composing?
439        n.value.push_back((*v)[1].c_str());
440        //n.unregistered = unregistered;
441
442        // If any parsing will be done in the future...
443        //n.value().original_tokens.clear();
444        //n.value().original_tokens.push_back(name);
445        //n.value().original_tokens.push_back(value);
446
447        result.options.push_back(n);
448    }
449
450    return result;
451}
452#else
453po::basic_parsed_options<char>
454    Configuration::parse_database(const string &, const string &, const po::options_description &desc, bool)
455{
456    return po::parsed_options(&desc);
457}
458#endif
459
460// --------------------------------------------------------------------------
461//
462//!
463//
464Configuration::Configuration(const string &prgname) : fName(UnLibToolize(prgname)),
465fNameMapper(bind1st(mem_fun(&Configuration::DefaultMapper), this)),
466fPrintUsage(bind(&Configuration::PrintUsage, this))
467{
468    if (prgname.empty())
469        return;
470
471    const boost::filesystem::path rc(fName+".rc");
472
473    po::options_description generic("Generic options");
474    generic.add_options()
475        ("version,V",           "Print version information.")
476        ("help",                "Print available commandline options.")
477        ("help-environment",    "Print available environment variables.")
478        ("help-database",       "Print available options retreived from the database.")
479        ("help-config",         "Print available configuration file options.")
480        ("print-all",           "Print all options as parsed from all the different sources.")
481        ("print",               "Print options as parsed from the commandline.")
482        ("print-default",       "Print options as parsed from default configuration file.")
483        ("print-database",      "Print options as retrieved from the database.")
484        ("print-config",        "Print options as parsed from the high priority configuration file.")
485        ("print-environment",   "Print options as parsed from the environment.")
486        ("print-unknown",       "Print unrecognized options.")
487        ("print-options",       "Print options as passed to program.")
488        ("print-wildcards",     "Print all options registered with wildcards.")
489        ("dont-check",          "Do not check validity of options from files and database.")
490        ("dont-check-files",    "Do not check validity of options from files.")
491        ("dont-check-database", "Do not check validity of options from database.")
492        ;
493
494    po::options_description config("Configuration options");
495    config.add_options()
496        ("config,C",    var<string>(), "Configuration file overwriting options retrieved from the database.")
497        ("database",    var<string>(), "Database link as in\n\t[user[:password]@]server.com[:port]/database[?compress=0|1]\nOverwrites options from the default configuration file.")
498        ("no-database",                "Suppress any access to the database even if a database URL was set.")
499        ("default",     var<string>(rc.filename().string()), "Name of default configuration file.")
500        ("prefix",      var<string>(rc.parent_path().string()), "Path to default configuration file.")
501        ;
502
503    fOptionsCommandline[kVisible].add(generic);
504    fOptionsCommandline[kVisible].add(config);
505    fOptionsConfigfile[kVisible].add(config);
506}
507
508// --------------------------------------------------------------------------
509//
510//!
511//
512void Configuration::PrintParsed(const po::parsed_options &parsed) const
513{
514    const vector< po::basic_option<char> >& options = parsed.options;
515
516    // .description -> Pointer to opt_commandline
517    // const std::vector< shared_ptr<option_description> >& options() const;
518
519    //const std::string& key(const std::string& option) const;
520    //const std::string& long_name() const;
521    //const std::string& description() const;
522    //shared_ptr<const value_semantic> semantic() const;
523
524    int maxlen = 0;
525    for (unsigned i=0; i<options.size(); ++i)
526    {
527        const po::basic_option<char> &opt = options[i];
528
529        if (opt.value.size()>0 && opt.string_key[0]!='-')
530            Max(maxlen, opt.string_key.length());
531    }
532
533    cout.setf(ios_base::left);
534
535    // =============> Implement printing of parsed options
536    for(unsigned i=0; i<options.size(); ++i)
537    {
538        const po::basic_option<char> &opt = options[i];
539
540        if (opt.value.size()==0 && opt.string_key[0]!='-')
541            cout << "--";
542        cout << setw(maxlen) << opt.string_key;
543        if (opt.value.size()>0)
544            cout << " = " << opt.value[0];
545
546        //for (int j=0; j<options[i].value.size(); j++)
547        //    cout << "\t = " << options[i].value[j];
548        //cout << "/" << options[i].original_tokens[0];
549
550        ostringstream com;
551
552        if (opt.position_key>=0)
553            com << " [position=" << opt.position_key << "]";
554        if (opt.unregistered)
555            com << " [unregistered]";
556
557        if (!com.str().empty())
558            cout << "  # " << com.str();
559
560        cout << endl;
561    }
562}
563
564template<class T>
565string Configuration::VecAsStr(const po::variable_value &v) const
566{
567    ostringstream str;
568
569    const vector<T> vec = v.as<vector<T>>();
570    for (typename std::vector<T>::const_iterator s=vec.begin(); s<vec.end(); s++)
571        str << " " << *s;
572
573    return str.str().substr(1);
574}
575
576string Configuration::VarAsStr(const po::variable_value &v) const
577{
578    if (v.value().type()==typeid(bool))
579        return v.as<bool>() ? "yes ": "no";
580
581    if (v.value().type()==typeid(string))
582        return v.as<string>();
583
584    if (v.value().type()==typeid(int16_t))
585        return to_string((long long int)v.as<int16_t>());
586
587    if (v.value().type()==typeid(int32_t))
588        return to_string((long long int)v.as<int32_t>());
589
590    if (v.value().type()==typeid(int64_t))
591        return to_string((long long int)v.as<int64_t>());
592
593    if (v.value().type()==typeid(uint16_t))
594        return to_string((long long unsigned int)v.as<uint16_t>());
595
596    if (v.value().type()==typeid(uint32_t))
597        return to_string((long long unsigned int)v.as<uint32_t>());
598
599    if (v.value().type()==typeid(uint64_t))
600        return to_string((long long unsigned int)v.as<uint64_t>());
601
602    if (v.value().type()==typeid(float))
603        return to_string((long double)v.as<float>());
604
605    if (v.value().type()==typeid(double))
606        return to_string((long double)v.as<double>());
607
608    if (v.value().type()==typeid(vector<string>))
609        return VecAsStr<string>(v);
610
611    if (v.value().type()==typeid(vector<int16_t>))
612        return VecAsStr<int16_t>(v);
613
614    if (v.value().type()==typeid(vector<int32_t>))
615        return VecAsStr<int32_t>(v);
616
617    if (v.value().type()==typeid(vector<int64_t>))
618        return VecAsStr<int64_t>(v);
619
620    if (v.value().type()==typeid(vector<uint16_t>))
621        return VecAsStr<uint16_t>(v);
622
623    if (v.value().type()==typeid(vector<uint32_t>))
624        return VecAsStr<uint32_t>(v);
625
626    if (v.value().type()==typeid(vector<uint64_t>))
627        return VecAsStr<uint64_t>(v);
628
629    if (v.value().type()==typeid(vector<float>))
630        return VecAsStr<float>(v);
631
632    if (v.value().type()==typeid(vector<double>))
633        return VecAsStr<double>(v);
634
635    ostringstream str;
636    str << hex << setfill('0') << "0x";
637    if (v.value().type()==typeid(Hex<uint16_t>))
638        str << setw(4) << v.as<Hex<uint16_t>>();
639
640    if (v.value().type()==typeid(Hex<uint32_t>))
641        str << setw(8) << v.as<Hex<uint32_t>>();
642
643    if (v.value().type()==typeid(Hex<uint64_t>))
644        str << setw(16) << v.as<Hex<uint64_t>>();
645
646    return str.str();
647}
648
649// --------------------------------------------------------------------------
650//
651//!
652//
653void Configuration::PrintOptions() const
654{
655    cout << "Options propagated to program:" << endl;
656
657    int maxlen = 0;
658    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
659         m!=fVariables.end(); m++)
660        Max(maxlen, m->first.length());
661
662    cout.setf(ios_base::left);
663
664    // =============> Implement prining of options in use
665    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
666         m!=fVariables.end(); m++)
667    {
668        const po::variable_value &v = m->second;
669
670        ostringstream str;
671
672        if (v.value().type()==typeid(bool))
673            str << " bool";
674        if (v.value().type()==typeid(string))
675            str << " string";
676        if (v.value().type()==typeid(int16_t))
677            str << " int16_t";
678        if (v.value().type()==typeid(int32_t))
679            str << " int32_t";
680        if (v.value().type()==typeid(int64_t))
681            str << " int64_t";
682        if (v.value().type()==typeid(uint16_t))
683            str << " uint16_t";
684        if (v.value().type()==typeid(uint32_t))
685            str << " uint32_t";
686        if (v.value().type()==typeid(uint64_t))
687            str << " uint64_t";
688        if (v.value().type()==typeid(float))
689            str << " float";
690        if (v.value().type()==typeid(double))
691            str << " double";
692        if (v.value().type()==typeid(Hex<uint16_t>))
693            str << " Hex<uint16_t>";
694        if (v.value().type()==typeid(Hex<uint32_t>))
695            str << " Hex<uint32_t>";
696        if (v.value().type()==typeid(Hex<uint64_t>))
697            str << " Hex<uint64_t>";
698        if (v.value().type()==typeid(vector<string>))
699            str << " vector<string>";
700        if (v.value().type()==typeid(vector<int16_t>))
701            str << " vector<int16_t>";
702        if (v.value().type()==typeid(vector<int32_t>))
703            str << " vector<int32_t>";
704        if (v.value().type()==typeid(vector<int64_t>))
705            str << " vector<int64_t>";
706        if (v.value().type()==typeid(vector<uint16_t>))
707            str << " vector<uint16_t>";
708        if (v.value().type()==typeid(vector<uint32_t>))
709            str << " vector<uint32_t>";
710        if (v.value().type()==typeid(vector<uint64_t>))
711            str << " vector<uint64_t>";
712        if (v.value().type()==typeid(vector<float>))
713            str << " vector<float>";
714        if (v.value().type()==typeid(vector<double>))
715            str << " vector<double>";
716
717        if (str.str().empty())
718            str << " unknown[" << v.value().type().name() << "]";
719
720        const string var = VarAsStr(v);
721        cout << setw(maxlen) << m->first;
722        if (!var.empty())
723            cout << " = ";
724        cout << var << "   #" << str.str();
725
726        if (v.defaulted())
727            cout << " [default]";
728        if (v.empty())
729            cout << " [empty]";
730
731        cout << endl;
732    }
733
734    cout << endl;
735}
736
737// --------------------------------------------------------------------------
738//
739//!
740//
741void Configuration::PrintUnknown(const vector<string> &vec, int steps) const
742{
743    for (vector<string>::const_iterator v=vec.begin(); v<vec.end(); v+=steps)
744        cout << " " << *v << endl;
745    cout << endl;
746}
747
748multimap<string, string> Configuration::GetOptions() const
749{
750    multimap<string,string> rc;
751
752    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
753         m!=fVariables.end(); m++)
754        rc.insert(make_pair(m->first, VarAsStr(m->second)));
755
756    return rc;
757}
758
759// --------------------------------------------------------------------------
760//
761//!
762//
763void Configuration::PrintUnknown() const
764{
765    if (!fUnknownCommandline.empty())
766    {
767        cout << "Unknown commandline options:" << endl;
768        PrintUnknown(fUnknownCommandline);
769    }
770
771    if (!fUnknownConfigfile.empty())
772    {
773        cout << "Unknown options in configfile:" << endl;
774        PrintUnknown(fUnknownConfigfile, 2);
775    }
776
777    if (!fUnknownEnvironment.empty())
778    {
779        cout << "Unknown environment variables:" << endl;
780        PrintUnknown(fUnknownEnvironment);
781    }
782
783    if (!fUnknownDatabase.empty())
784    {
785        cout << "Unknown database entry:" << endl;
786        PrintUnknown(fUnknownDatabase);
787    }
788}
789
790// --------------------------------------------------------------------------
791//
792//!
793//
794void Configuration::AddOptionsCommandline(const po::options_description &cl, bool visible)
795{
796    fOptionsCommandline[visible].add(cl);
797}
798
799// --------------------------------------------------------------------------
800//
801//!
802//
803void Configuration::AddOptionsConfigfile(const po::options_description &cf, bool visible)
804{
805    fOptionsConfigfile[visible].add(cf);
806}
807
808// --------------------------------------------------------------------------
809//
810//!
811//
812void Configuration::AddOptionsEnvironment(const po::options_description &env, bool visible)
813{
814    fOptionsEnvironment[visible].add(env);
815}
816
817// --------------------------------------------------------------------------
818//
819//!
820//
821void Configuration::AddOptionsDatabase(const po::options_description &db, bool visible)
822{
823    fOptionsDatabase[visible].add(db);
824}
825
826// --------------------------------------------------------------------------
827//
828//!
829//
830void Configuration::SetArgumentPositions(const po::positional_options_description &desc)
831{
832    fArgumentPositions = desc;
833}
834
835// --------------------------------------------------------------------------
836//
837//!
838//
839void Configuration::SetNameMapper(const function<string(string)> &func)
840{
841    fNameMapper = func;
842}
843
844void Configuration::SetNameMapper()
845{
846    fNameMapper = bind1st(mem_fun(&Configuration::DefaultMapper), this);
847}
848
849void Configuration::SetPrintUsage(const function<void(void)> &func)
850{
851    fPrintUsage = func;
852}
853
854void Configuration::SetPrintUsage()
855{
856    fPrintUsage = bind(&Configuration::PrintUsage, this);
857}
858
859void Configuration::SetPrintVersion(const function<void(const string&)> &func)
860{
861    fPrintVersion = func;
862}
863
864void Configuration::SetPrintVersion()
865{
866    fPrintVersion = function<void(const string&)>();
867}
868
869// --------------------------------------------------------------------------
870//
871//!
872//! The idea of the Parse() memeber-function is to parse the command-line,
873//! the configuration files, the databse and the environment and return
874//! a proper combined result.
875//!
876//! In details the following actions are performed in the given order:
877//!
878//!  - (0)  Init local variables with the list of options described by the
879//!         data members.
880//!  - (1)  Reset the data members fPriorityFile, fDefaultFile, fDatabase
881//!  - (2)  Parse the command line
882//!  - (3)  Check for \b --help* command-line options and performe
883//!         corresponding action
884//!  - (4)  Check for \b --print and \b --print-all and perform corresponding
885//!         action
886//!  - (5)  Read and parse the global configuration file, which is compiled
887//!         from the path corresponding to the argument given in the
888//!         constructor + "/fact++.rc", unrecognized options are always
889//!         allowed. Note that in contradiction to all other options
890//!         the options in this file are not checked at all. Hence,
891//!         typos might stay unnoticed.
892//!  - (6)  Read and parse the default configuration file, which is either
893//!         given by the default name or the \b --default command-line
894//!         option. The default name is compiled from the argument
895//!         given to the constructor and ".rc".  If the file-name is
896//!         identical to the default (no command-line option given)
897//!         a missing configuration file is no error. Depending on
898//!         the \b --dont-check and \b --dont-check-files options,
899//!         unrecognized options in the file throw an exception or not.
900//!  - (7)  Check for \b --print-default and \b --print-all and perform
901//!         corresponding action
902//!  - (8)  Read and parse the priority configuration file, which must be given
903//!         by the \b --config or \b -C command-line option or a
904//!         corresponding entry in the default-configuration file.
905//!         If an option on the command-line and the in the configuration
906//!         file exists, the command-line option has priority.
907//!         If none is given, no priority file is read. Depending on
908//!         the \b --dont-check and \b --dont-check-files options,
909//!         unrecognized options in the file throw an exception or not.
910//!  - (9)  Check for \b --print-config and \b --print-all and perform
911//!         corresponding action
912//!  - (10) Retrieve options from the database according to the
913//!         options \b --database and \b --no-database. Note that
914//!         options given on the command-line have highest priority.
915//!         The second priority is the priority-configuration file.
916//!         The options from the default configuration-file have
917//!         lowest priority.
918//!  - (11) Check for \b --print-database and \b --print-all and perform
919//!         corresponding action
920//!  - (12)  Parse the environment options.
921//!  - (13) Check for \b --print-environment and \b --print-all and perform
922//!         corresponding action
923//!  - (14) Compile the final result. The priority of the options is (in
924//!         decreasing order): command-line options, options from the
925//!         priority configuration file, options from the database,
926//!         options from the default configuration-file and options
927//!         from the environment.
928//!  - (15) Find all options which were found and flagged as unrecognized,
929//!         because they are not in the user-defined list of described
930//!         options, are collected and stored in the corresponding
931//!         data-members.
932//!  - (16) Find all options which where registered with wildcards and
933//!         store the list in fWildcardOptions.
934//!  - (17) Before the function returns it check for \b --print-options
935//!         and \b --print-unknown and performs the corresponding actions.
936//!
937//!
938//! @param argc,argv
939//!    arguments passed to <B>main(int argc, char **argv)</B>
940//!
941//! @returns
942//!    A reference to the list with the resulting options with their
943//!    values.
944//!
945//! @todo
946//!    - describe the exceptions
947//!    - describe what happens in a more general way
948//!    - print a waring when no default coonfig file is read
949//!    - proper handling and error messages if files not available
950//
951const po::variables_map &Configuration::Parse(int argc, const char **argv, const std::function<void()> &PrintHelp)
952{
953    const po::positional_options_description &opt_positional = fArgumentPositions;
954
955    // ------------------------ (0) --------------------------
956#ifdef DEBUG
957    cout << "--0--" << endl;
958#endif
959
960    po::options_description opt_commandline;
961    po::options_description opt_configfile;
962    po::options_description opt_environment;
963    po::options_description opt_database;
964
965    for (int i=0; i<2; i++)
966    {
967        opt_commandline.add(fOptionsCommandline[i]);
968        opt_configfile.add(fOptionsConfigfile[i]);
969        opt_environment.add(fOptionsEnvironment[i]);
970        opt_database.add(fOptionsDatabase[i]);
971    }
972
973    // ------------------------ (1) --------------------------
974#ifdef DEBUG
975    cout << "--1--" << endl;
976#endif
977
978    fPriorityFile = "";
979    fPrefixPath   = "";
980    fDefaultFile  = "";
981    fDatabase     = "";
982
983    // ------------------------ (2) --------------------------
984#ifdef DEBUG
985    cout << "--2--" << endl;
986#endif
987
988    po::command_line_parser parser(argc, const_cast<char**>(argv));
989    parser.options(opt_commandline);
990    parser.positional(opt_positional);
991    parser.style(style::unix_style&~style::allow_guessing);
992    //parser.allow_unregistered();
993
994    const po::parsed_options parsed_commandline = parser.run();
995
996    // ------------------------ (3) --------------------------
997#ifdef DEBUG
998    cout << "--3--" << endl;
999#endif
1000
1001    po::variables_map getfiles;
1002    po::store(parsed_commandline, getfiles);
1003
1004    if (getfiles.count("version"))
1005        PrintVersion();
1006    if (getfiles.count("help"))
1007    {
1008        fPrintUsage();
1009        cout <<
1010            "Options:\n"
1011            "The following describes the available commandline options. "
1012            "For further details on how command line option are parsed "
1013            "and in which order which configuration sources are accessed "
1014            "please refer to the class reference of the Configuration class." << endl;
1015        cout << fOptionsCommandline[kVisible] << endl;
1016    }
1017    if (getfiles.count("help-config"))
1018        cout << fOptionsConfigfile[kVisible] << endl;
1019    if (getfiles.count("help-env"))
1020        cout << fOptionsEnvironment[kVisible] << endl;
1021    if (getfiles.count("help-database"))
1022        cout << fOptionsDatabase[kVisible] << endl;
1023
1024
1025
1026    // ------------------------ (4) --------------------------
1027#ifdef DEBUG
1028    cout << "--4--" << endl;
1029#endif
1030
1031    if (getfiles.count("print") || getfiles.count("print-all"))
1032    {
1033        cout << endl << "Parsed commandline options:" << endl;
1034        PrintParsed(parsed_commandline);
1035        cout << endl;
1036    }
1037
1038    if (getfiles.count("help")     || getfiles.count("help-config") ||
1039        getfiles.count("help-env") || getfiles.count("help-database"))
1040    {
1041        if (PrintHelp)
1042            PrintHelp();
1043    }
1044
1045    // ------------------------ (5) --------------------------
1046#ifdef DEBUG
1047    cout << "--5--" << endl;
1048#endif
1049
1050    const boost::filesystem::path path(GetName());
1051    const string globalfile = (path.parent_path()/boost::filesystem::path("fact++.rc")).string();
1052
1053
1054    errno = 0;
1055
1056    ifstream gfile(globalfile.c_str());
1057    cerr << "Reading global  options from '" << globalfile << "' [" << strerror(errno) << "]" << endl;
1058    const po::parsed_options parsed_globalfile =
1059        !gfile ?
1060        po::parsed_options(&opt_configfile) :
1061        po::parse_config_file<char>(gfile, opt_configfile, true);
1062
1063    // ------------------------ (6) --------------------------
1064#ifdef DEBUG
1065    cout << "--6--" << endl;
1066#endif
1067
1068    po::store(parsed_globalfile, getfiles);
1069
1070    // Get default prefix path from command line
1071    if (getfiles.count("prefix"))
1072        fPrefixPath = getfiles["prefix"].as<string>();
1073
1074    // Get default file from command line
1075    if (getfiles.count("default"))
1076        fDefaultFile = getfiles["default"].as<string>();
1077
1078    const string default_file = (boost::filesystem::path(fPrefixPath)/boost::filesystem::path(fDefaultFile)).string();
1079
1080    const bool checkf    = !getfiles.count("dont-check-files") && !getfiles.count("dont-check");
1081    const bool defaulted = getfiles.count("default") && getfiles["default"].defaulted();
1082    //const bool exists    = boost::filesystem::exists(fDefaultFile);
1083
1084    errno = 0;
1085
1086    ifstream indef(default_file);
1087    if (!fDefaultFile.empty())
1088        cerr << "Reading default options from '" << default_file << "' [" << strerror(errno) << "]" << endl;
1089    const po::parsed_options parsed_defaultfile =
1090        !indef && defaulted ?
1091        po::parsed_options(&opt_configfile) :
1092        po::parse_config_file<char>(indef, opt_configfile, !checkf);
1093
1094    // ------------------------ (7) --------------------------
1095#ifdef DEBUG
1096    cout << "--7--" << endl;
1097#endif
1098
1099    if (getfiles.count("print-default") || getfiles.count("print-all"))
1100    {
1101        if (!indef.is_open() && defaulted)
1102            cout << "No configuration file by --default option specified." << endl;
1103        else
1104        {
1105            cout << endl << "Parsed options from '" << fDefaultFile << "':" << endl;
1106            PrintParsed(parsed_defaultfile);
1107            cout << endl;
1108        }
1109    }
1110
1111    po::store(parsed_defaultfile, getfiles);
1112
1113    // ------------------------ (8) --------------------------
1114#ifdef DEBUG
1115    cout << "--8--" << endl;
1116#endif
1117
1118    // Get priority from commandline(1), defaultfile(2)
1119    if (getfiles.count("config"))
1120    {
1121        fPriorityFile = getfiles["config"].as<string>();
1122        cerr << "Reading config  options from '" << fPriorityFile << "'." << endl;
1123    }
1124
1125    ifstream inpri(fPriorityFile.c_str());
1126    if (!fPriorityFile.empty() && !inpri)
1127        throw runtime_error("Reading '"+fPriorityFile+"' failed: "+strerror(errno));
1128
1129    // ===> FIXME: Proper handling of missing file or wrong file name
1130    const po::parsed_options parsed_priorityfile =
1131        fPriorityFile.empty() ? po::parsed_options(&opt_configfile) :
1132        po::parse_config_file<char>(inpri, opt_configfile, !checkf);
1133
1134    // ------------------------ (9) --------------------------
1135#ifdef DEBUG
1136    cout << "--9--" << endl;
1137#endif
1138
1139    if (getfiles.count("print-config") || getfiles.count("print-all"))
1140    {
1141        if (fPriorityFile.empty())
1142            cout << "No configuration file by --config option specified." << endl;
1143        else
1144        {
1145            cout << endl << "Parsed options from '" << fPriorityFile << "':" << endl;
1146            PrintParsed(parsed_priorityfile);
1147            cout << endl;
1148        }
1149    }
1150
1151    // ------------------------ (10) -------------------------
1152#ifdef DEBUG
1153    cout << "--10--" << endl;
1154#endif
1155
1156    po::variables_map getdatabase;
1157    po::store(parsed_commandline,  getdatabase);
1158    po::store(parsed_priorityfile, getdatabase);
1159    po::store(parsed_defaultfile,  getdatabase);
1160    po::store(parsed_globalfile,   getdatabase);
1161
1162    if (getdatabase.count("database") && !getdatabase.count("no-database"))
1163    {
1164        fDatabase = getdatabase["database"].as<string>();
1165        cerr << "Requesting options from database for '" << fName << "'" << endl;
1166    }
1167
1168    const bool checkdb = !getdatabase.count("dont-check-database") && !getdatabase.count("dont-check");
1169
1170    const po::parsed_options parsed_database =
1171        fDatabase.empty() ? po::parsed_options(&opt_database) :
1172#if BOOST_VERSION < 104600
1173        parse_database(path.filename(), fDatabase, opt_database, !checkdb);
1174#else
1175        parse_database(path.filename().string(), fDatabase, opt_database, !checkdb);
1176#endif
1177    // ------------------------ (11) -------------------------
1178#ifdef DEBUG
1179    cout << "--11--" << endl;
1180#endif
1181
1182    if (getfiles.count("print-database") || getfiles.count("print-all"))
1183    {
1184        if (fDatabase.empty())
1185            cout << "No database access requested." << endl;
1186        else
1187        {
1188            cout << endl << "Options received from '" << fDatabase << "':" << endl;
1189            PrintParsed(parsed_database);
1190            cout << endl;
1191        }
1192    }
1193
1194    // ------------------------ (12) -------------------------
1195#ifdef DEBUG
1196    cout << "--12--" << endl;
1197#endif
1198
1199    const po::parsed_options parsed_environment = po::parse_environment(opt_environment, fNameMapper);
1200
1201    // ------------------------ (13) -------------------------
1202#ifdef DEBUG
1203    cout << "--13--" << endl;
1204#endif
1205
1206    if (getfiles.count("print-environment"))
1207    {
1208        cout << "Parsed options from environment:" << endl;
1209        PrintParsed(parsed_environment);
1210        cout << endl;
1211    }
1212
1213    // ------------------------ (14) -------------------------
1214#ifdef DEBUG
1215    cout << "--14--" << endl;
1216#endif
1217
1218    po::variables_map result;
1219    po::store(parsed_commandline,  result);
1220    po::store(parsed_priorityfile, result);
1221    po::store(parsed_database,     result);
1222    po::store(parsed_defaultfile,  result);
1223    po::store(parsed_globalfile,   result);
1224    po::store(parsed_environment,  result);
1225    po::notify(result);
1226
1227    fVariables = result;
1228
1229    // ------------------------ (15) -------------------------
1230#ifdef DEBUG
1231    cout << "--15--" << endl;
1232#endif
1233
1234    const vector<string> unknown0 = collect_unrecognized(parsed_globalfile.options,   po::exclude_positional);
1235    const vector<string> unknown1 = collect_unrecognized(parsed_defaultfile.options,  po::exclude_positional);
1236    const vector<string> unknown2 = collect_unrecognized(parsed_priorityfile.options, po::exclude_positional);
1237
1238    fUnknownConfigfile.clear();
1239    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown0.begin(), unknown0.end());
1240    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown1.begin(), unknown1.end());
1241    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown2.begin(), unknown2.end());
1242
1243    fUnknownCommandline = collect_unrecognized(parsed_commandline.options, po::exclude_positional);
1244    fUnknownEnvironment = collect_unrecognized(parsed_environment.options, po::exclude_positional);
1245    fUnknownDatabase    = collect_unrecognized(parsed_database.options, po::exclude_positional);
1246
1247    // ------------------------ (16) -------------------------
1248#ifdef DEBUG
1249    cout << "--16--" << endl;
1250#endif
1251
1252    CreateWildcardOptions();
1253
1254    // ------------------------ (17) -------------------------
1255#ifdef DEBUG
1256    cout << "--17--" << endl;
1257#endif
1258
1259    if (result.count("print-options"))
1260        PrintOptions();
1261
1262    if (result.count("print-wildcards"))
1263        PrintWildcardOptions();
1264
1265    if (result.count("print-unknown"))
1266        PrintUnknown();
1267
1268#ifdef DEBUG
1269    cout << "------" << endl;
1270#endif
1271
1272    return fVariables;
1273}
1274
1275const po::variables_map &Configuration::ParseFile(const string &fname, const bool &checkf)
1276{
1277    // -------------------------------------------------------
1278    po::options_description opt_configfile;
1279
1280    for (int i=0; i<2; i++)
1281        opt_configfile.add(fOptionsConfigfile[i]);
1282
1283    // -------------------------------------------------------
1284
1285    ifstream file(fname.c_str());
1286    // ===> FIXME: Proper handling of missing file or wrong file name
1287    const po::parsed_options parsed_file =
1288        po::parse_config_file<char>(file, opt_configfile, !checkf);
1289
1290    // -------------------------------------------------------
1291
1292    po::variables_map result;
1293    po::store(parsed_file, result);
1294    po::notify(result);
1295
1296    fVariables = result;
1297
1298    // -------------------------------------------------------
1299
1300    const vector<string> unknown = collect_unrecognized(parsed_file.options, po::exclude_positional);
1301
1302    fUnknownConfigfile.clear();
1303    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown.begin(), unknown.end());
1304
1305    // -------------------------------------------------------
1306
1307    CreateWildcardOptions();
1308
1309    // -------------------------------------------------------
1310
1311    return fVariables;
1312}
1313
1314bool Configuration::DoParse(int argc, const char **argv, const std::function<void()> &PrintHelp)
1315{
1316    try
1317    {
1318        Parse(argc, argv, PrintHelp);
1319    }
1320#if BOOST_VERSION > 104100
1321    catch (const po::multiple_occurrences &e)
1322    {
1323        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1324        return false;
1325    }
1326#endif
1327    catch (const exception& e)
1328    {
1329        cerr << "Program options invalid due to: " << e.what() << endl;
1330        return false;
1331    }
1332
1333    return !HasVersion() && !HasPrint() && !HasHelp();
1334}
1335
1336bool Configuration::ReadFile(const string &fname, const bool &checkf)
1337{
1338    try
1339    {
1340        ParseFile(fname, checkf);
1341    }
1342#if BOOST_VERSION > 104100
1343    catch (const po::multiple_occurrences &e)
1344    {
1345        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1346        return false;
1347    }
1348#endif
1349    catch (const exception& e)
1350    {
1351        cerr << "Program options invalid due to: " << e.what() << endl;
1352        return false;
1353    }
1354
1355    return true;
1356}
1357
1358// --------------------------------------------------------------------------
1359//
1360//! Create a list of all options which were registered using wildcards
1361//!
1362void Configuration::CreateWildcardOptions()
1363{
1364    po::options_description opts;
1365
1366    for (int i=0; i<2; i++)
1367    {
1368        opts.add(fOptionsCommandline[i]);
1369        opts.add(fOptionsConfigfile[i]);
1370        opts.add(fOptionsEnvironment[i]);
1371        opts.add(fOptionsDatabase[i]);
1372    }
1373
1374    fWildcardOptions.clear();
1375
1376    typedef map<string,po::variable_value> Vars;
1377    typedef vector<boost::shared_ptr<po::option_description>> Descs;
1378
1379    const Descs &desc = opts.options();
1380
1381    for (Vars::const_iterator io=fVariables.begin(); io!=fVariables.end(); io++)
1382    {
1383        for (Descs::const_iterator id=desc.begin(); id!=desc.end(); id++)
1384#if BOOST_VERSION > 104100
1385            if ((*id)->match(io->first, false, false, false)==po::option_description::approximate_match)
1386#else
1387            if ((*id)->match(io->first, false)==po::option_description::approximate_match)
1388#endif
1389                fWildcardOptions[io->first] = (*id)->long_name();
1390    }
1391}
1392
1393// --------------------------------------------------------------------------
1394//
1395//! Print a list of all options which were registered using wildcards and
1396//! have not be registered subsequently by access.
1397//!
1398void Configuration::PrintWildcardOptions() const
1399{
1400    cout << "Options registered with wildcards and not yet accessed:" << endl;
1401
1402    size_t max = 0;
1403    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1404        if (it->second.length()>max)
1405            max = it->second.length();
1406
1407    cout.setf(ios_base::left);
1408    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1409        cout << setw(max+1) << it->second << " : " << it->first <<endl;
1410}
1411
1412const vector<string> Configuration::GetWildcardOptions(const std::string &opt) const
1413{
1414    vector<string> rc;
1415
1416    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1417    {
1418        if (it->second == opt)
1419            rc.push_back(it->first);
1420    }
1421
1422    return rc;
1423}
1424
1425// --------------------------------------------------------------------------
1426//
1427//! Removes /.libs/lt- from a path or just lt- from the filename.
1428//!
1429//! @param src
1430//!    input path with filename
1431//! @returns
1432//!    path cleaned from libtool extensions
1433//!
1434string Configuration::UnLibToolize(const string &src) const
1435{
1436    const boost::filesystem::path path(src);
1437
1438    string pname = path.parent_path().string();
1439#if BOOST_VERSION < 104600
1440    string fname = path.filename();
1441#else
1442    string fname = path.filename().string();
1443#endif
1444
1445    // If the filename starts with "lt-" remove it from the name
1446    if (fname.substr(0, 3)=="lt-")
1447        fname = fname.substr(3);
1448
1449    string pwd;
1450    // If no directory is contained determine the current directory
1451    if (pname.empty())
1452        pname = boost::filesystem::current_path().string();
1453
1454    // If the directory is relative and just ".libs" forget about it
1455    if (pname==".libs")
1456        return fname;
1457
1458
1459    // Check if the directory is long enough to contain "/.libs"
1460    if (pname.length()>=6)
1461    {
1462        // If the directory ends with "/.libs", remove it
1463        const size_t pos = pname.length()-6;
1464        if (pname.substr(pos)=="/.libs")
1465            pname = pname.substr(0, pos);
1466    }
1467
1468    // If the path is the local path do not return the path-name
1469    if (pname==boost::filesystem::current_path().string())
1470        return fname;
1471
1472    return pname+'/'+fname;
1473}
1474
1475// --------------------------------------------------------------------------
1476//
1477//! Print version information about the program and package.
1478//!
1479//! The program name is taken from fName. If a leading "lt-" is found,
1480//! it is removed. This is useful if the program was build and run
1481//! using libtool.
1482//!
1483//! The package name is taken from the define PACKAGE_STRING. If it is
1484//! not defined (like automatically done by autoconf) no package information
1485//! is printed. The same is true for PACKAGE_URL and PACKAGE_BUGREPORT.
1486//!
1487//! From help2man:
1488//!
1489//! The first line of the --version information is assumed to be in one
1490//! of the following formats:
1491//!
1492//! \verbatim
1493//!  - <version>
1494//!  - <program> <version>
1495//!  - {GNU,Free} <program> <version>
1496//!  - <program> ({GNU,Free} <package>) <version>
1497//!  - <program> - {GNU,Free} <package> <version>
1498//! \endverbatim
1499//!
1500//!  and separated from any copyright/author details by a blank line.
1501//!
1502//! Handle multi-line bug reporting sections of the form:
1503//!
1504//! \verbatim
1505//!  - Report <program> bugs to <addr>
1506//!  - GNU <package> home page: <url>
1507//!  - ...
1508//! \endverbatim
1509//!
1510//! @param name
1511//!     name of the program (usually argv[0]).
1512//!
1513void Configuration::PrintVersion() const
1514{
1515#ifndef PACKAGE_STRING
1516#define PACKAGE_STRING ""
1517#endif
1518
1519#ifndef PACKAGE_URL
1520#define PACKAGE_URL ""
1521#endif
1522
1523#ifndef PACKAGE_BUGREPORT
1524#define PACKAGE_BUGREPORT ""
1525#endif
1526
1527    if (fPrintVersion)
1528    {
1529        fPrintVersion(fName);
1530        return;
1531    }
1532
1533#if BOOST_VERSION < 104600
1534    const std::string n = boost::filesystem::path(fName).filename();
1535#else
1536    const std::string n = boost::filesystem::path(fName).filename().string();
1537#endif
1538
1539    const string name = PACKAGE_STRING;
1540    const string bugs = PACKAGE_BUGREPORT;
1541    const string url  = PACKAGE_URL;
1542
1543    cout << n;
1544    if (!name.empty())
1545        cout << " - " << name;
1546    cout <<
1547        "\n\n"
1548        "Written by Thomas Bretz et al.\n"
1549        "\n";
1550    if (!bugs.empty())
1551        cout << "Report bugs to <" << bugs << ">\n";
1552    if (!url.empty())
1553        cout << "Home page: " << url << "\n";
1554    cout <<
1555        "\n"
1556        "Copyright (C) 2011 by the FACT Collaboration.\n"
1557        "This is free software; see the source for copying conditions.\n"
1558        << std::endl;
1559}
Note: See TracBrowser for help on using the repository browser.