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

Last change on this file since 19385 was 19385, checked in by tbretz, 6 months ago
Implemneted to set an independent prefix path in fact++.rc or from the commandline which is used to read the default configuration files. Improved output of reading files. Do not accept an invalid user specified priority file. Return a prefixed filename if filename does not contain a path.
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    po::options_description generic("Generic options");
472    generic.add_options()
473        ("version,V",           "Print version information.")
474        ("help",                "Print available commandline options.")
475        ("help-environment",    "Print available environment variables.")
476        ("help-database",       "Print available options retreived from the database.")
477        ("help-config",         "Print available configuration file options.")
478        ("print-all",           "Print all options as parsed from all the different sources.")
479        ("print",               "Print options as parsed from the commandline.")
480        ("print-default",       "Print options as parsed from default configuration file.")
481        ("print-database",      "Print options as retrieved from the database.")
482        ("print-config",        "Print options as parsed from the high priority configuration file.")
483        ("print-environment",   "Print options as parsed from the environment.")
484        ("print-unknown",       "Print unrecognized options.")
485        ("print-options",       "Print options as passed to program.")
486        ("print-wildcards",     "Print all options registered with wildcards.")
487        ("dont-check",          "Do not check validity of options from files and database.")
488        ("dont-check-files",    "Do not check validity of options from files.")
489        ("dont-check-database", "Do not check validity of options from database.")
490        ;
491
492    po::options_description config("Configuration options");
493    config.add_options()
494        ("config,C",    var<string>(), "Configuration file overwriting options retrieved from the database.")
495        ("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.")
496        ("no-database",                "Suppress any access to the database even if a database URL was set.")
497        ("default",     var<string>(fName+string(".rc")), "Default configuration file.")
498        ("prefix",      var<string>(), "Path to default configuration file.")
499        ;
500
501    fOptionsCommandline[kVisible].add(generic);
502    fOptionsCommandline[kVisible].add(config);
503    fOptionsConfigfile[kVisible].add(config);
504}
505
506// --------------------------------------------------------------------------
507//
508//!
509//
510void Configuration::PrintParsed(const po::parsed_options &parsed) const
511{
512    const vector< po::basic_option<char> >& options = parsed.options;
513
514    // .description -> Pointer to opt_commandline
515    // const std::vector< shared_ptr<option_description> >& options() const;
516
517    //const std::string& key(const std::string& option) const;
518    //const std::string& long_name() const;
519    //const std::string& description() const;
520    //shared_ptr<const value_semantic> semantic() const;
521
522    int maxlen = 0;
523    for (unsigned i=0; i<options.size(); ++i)
524    {
525        const po::basic_option<char> &opt = options[i];
526
527        if (opt.value.size()>0 && opt.string_key[0]!='-')
528            Max(maxlen, opt.string_key.length());
529    }
530
531    cout.setf(ios_base::left);
532
533    // =============> Implement printing of parsed options
534    for(unsigned i=0; i<options.size(); ++i)
535    {
536        const po::basic_option<char> &opt = options[i];
537
538        if (opt.value.size()==0 && opt.string_key[0]!='-')
539            cout << "--";
540        cout << setw(maxlen) << opt.string_key;
541        if (opt.value.size()>0)
542            cout << " = " << opt.value[0];
543
544        //for (int j=0; j<options[i].value.size(); j++)
545        //    cout << "\t = " << options[i].value[j];
546        //cout << "/" << options[i].original_tokens[0];
547
548        ostringstream com;
549
550        if (opt.position_key>=0)
551            com << " [position=" << opt.position_key << "]";
552        if (opt.unregistered)
553            com << " [unregistered]";
554
555        if (!com.str().empty())
556            cout << "  # " << com.str();
557
558        cout << endl;
559    }
560}
561
562template<class T>
563string Configuration::VecAsStr(const po::variable_value &v) const
564{
565    ostringstream str;
566
567    const vector<T> vec = v.as<vector<T>>();
568    for (typename std::vector<T>::const_iterator s=vec.begin(); s<vec.end(); s++)
569        str << " " << *s;
570
571    return str.str().substr(1);
572}
573
574string Configuration::VarAsStr(const po::variable_value &v) const
575{
576    if (v.value().type()==typeid(bool))
577        return v.as<bool>() ? "yes ": "no";
578
579    if (v.value().type()==typeid(string))
580        return v.as<string>();
581
582    if (v.value().type()==typeid(int16_t))
583        return to_string((long long int)v.as<int16_t>());
584
585    if (v.value().type()==typeid(int32_t))
586        return to_string((long long int)v.as<int32_t>());
587
588    if (v.value().type()==typeid(int64_t))
589        return to_string((long long int)v.as<int64_t>());
590
591    if (v.value().type()==typeid(uint16_t))
592        return to_string((long long unsigned int)v.as<uint16_t>());
593
594    if (v.value().type()==typeid(uint32_t))
595        return to_string((long long unsigned int)v.as<uint32_t>());
596
597    if (v.value().type()==typeid(uint64_t))
598        return to_string((long long unsigned int)v.as<uint64_t>());
599
600    if (v.value().type()==typeid(float))
601        return to_string((long double)v.as<float>());
602
603    if (v.value().type()==typeid(double))
604        return to_string((long double)v.as<double>());
605
606    if (v.value().type()==typeid(vector<string>))
607        return VecAsStr<string>(v);
608
609    if (v.value().type()==typeid(vector<int16_t>))
610        return VecAsStr<int16_t>(v);
611
612    if (v.value().type()==typeid(vector<int32_t>))
613        return VecAsStr<int32_t>(v);
614
615    if (v.value().type()==typeid(vector<int64_t>))
616        return VecAsStr<int64_t>(v);
617
618    if (v.value().type()==typeid(vector<uint16_t>))
619        return VecAsStr<uint16_t>(v);
620
621    if (v.value().type()==typeid(vector<uint32_t>))
622        return VecAsStr<uint32_t>(v);
623
624    if (v.value().type()==typeid(vector<uint64_t>))
625        return VecAsStr<uint64_t>(v);
626
627    if (v.value().type()==typeid(vector<float>))
628        return VecAsStr<float>(v);
629
630    if (v.value().type()==typeid(vector<double>))
631        return VecAsStr<double>(v);
632
633    ostringstream str;
634    str << hex << setfill('0') << "0x";
635    if (v.value().type()==typeid(Hex<uint16_t>))
636        str << setw(4) << v.as<Hex<uint16_t>>();
637
638    if (v.value().type()==typeid(Hex<uint32_t>))
639        str << setw(8) << v.as<Hex<uint32_t>>();
640
641    if (v.value().type()==typeid(Hex<uint64_t>))
642        str << setw(16) << v.as<Hex<uint64_t>>();
643
644    return str.str();
645}
646
647// --------------------------------------------------------------------------
648//
649//!
650//
651void Configuration::PrintOptions() const
652{
653    cout << "Options propagated to program:" << endl;
654
655    int maxlen = 0;
656    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
657         m!=fVariables.end(); m++)
658        Max(maxlen, m->first.length());
659
660    cout.setf(ios_base::left);
661
662    // =============> Implement prining of options in use
663    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
664         m!=fVariables.end(); m++)
665    {
666        const po::variable_value &v = m->second;
667
668        ostringstream str;
669
670        if (v.value().type()==typeid(bool))
671            str << " bool";
672        if (v.value().type()==typeid(string))
673            str << " string";
674        if (v.value().type()==typeid(int16_t))
675            str << " int16_t";
676        if (v.value().type()==typeid(int32_t))
677            str << " int32_t";
678        if (v.value().type()==typeid(int64_t))
679            str << " int64_t";
680        if (v.value().type()==typeid(uint16_t))
681            str << " uint16_t";
682        if (v.value().type()==typeid(uint32_t))
683            str << " uint32_t";
684        if (v.value().type()==typeid(uint64_t))
685            str << " uint64_t";
686        if (v.value().type()==typeid(float))
687            str << " float";
688        if (v.value().type()==typeid(double))
689            str << " double";
690        if (v.value().type()==typeid(Hex<uint16_t>))
691            str << " Hex<uint16_t>";
692        if (v.value().type()==typeid(Hex<uint32_t>))
693            str << " Hex<uint32_t>";
694        if (v.value().type()==typeid(Hex<uint64_t>))
695            str << " Hex<uint64_t>";
696        if (v.value().type()==typeid(vector<string>))
697            str << " vector<string>";
698        if (v.value().type()==typeid(vector<int16_t>))
699            str << " vector<int16_t>";
700        if (v.value().type()==typeid(vector<int32_t>))
701            str << " vector<int32_t>";
702        if (v.value().type()==typeid(vector<int64_t>))
703            str << " vector<int64_t>";
704        if (v.value().type()==typeid(vector<uint16_t>))
705            str << " vector<uint16_t>";
706        if (v.value().type()==typeid(vector<uint32_t>))
707            str << " vector<uint32_t>";
708        if (v.value().type()==typeid(vector<uint64_t>))
709            str << " vector<uint64_t>";
710        if (v.value().type()==typeid(vector<float>))
711            str << " vector<float>";
712        if (v.value().type()==typeid(vector<double>))
713            str << " vector<double>";
714
715        if (str.str().empty())
716            str << " unknown[" << v.value().type().name() << "]";
717
718        const string var = VarAsStr(v);
719        cout << setw(maxlen) << m->first;
720        if (!var.empty())
721            cout << " = ";
722        cout << var << "   #" << str.str();
723
724        if (v.defaulted())
725            cout << " [default]";
726        if (v.empty())
727            cout << " [empty]";
728
729        cout << endl;
730    }
731
732    cout << endl;
733}
734
735// --------------------------------------------------------------------------
736//
737//!
738//
739void Configuration::PrintUnknown(const vector<string> &vec, int steps) const
740{
741    for (vector<string>::const_iterator v=vec.begin(); v<vec.end(); v+=steps)
742        cout << " " << *v << endl;
743    cout << endl;
744}
745
746multimap<string, string> Configuration::GetOptions() const
747{
748    multimap<string,string> rc;
749
750    for (map<string,po::variable_value>::const_iterator m=fVariables.begin();
751         m!=fVariables.end(); m++)
752        rc.insert(make_pair(m->first, VarAsStr(m->second)));
753
754    return rc;
755}
756
757// --------------------------------------------------------------------------
758//
759//!
760//
761void Configuration::PrintUnknown() const
762{
763    if (!fUnknownCommandline.empty())
764    {
765        cout << "Unknown commandline options:" << endl;
766        PrintUnknown(fUnknownCommandline);
767    }
768
769    if (!fUnknownConfigfile.empty())
770    {
771        cout << "Unknown options in configfile:" << endl;
772        PrintUnknown(fUnknownConfigfile, 2);
773    }
774
775    if (!fUnknownEnvironment.empty())
776    {
777        cout << "Unknown environment variables:" << endl;
778        PrintUnknown(fUnknownEnvironment);
779    }
780
781    if (!fUnknownDatabase.empty())
782    {
783        cout << "Unknown database entry:" << endl;
784        PrintUnknown(fUnknownDatabase);
785    }
786}
787
788// --------------------------------------------------------------------------
789//
790//!
791//
792void Configuration::AddOptionsCommandline(const po::options_description &cl, bool visible)
793{
794    fOptionsCommandline[visible].add(cl);
795}
796
797// --------------------------------------------------------------------------
798//
799//!
800//
801void Configuration::AddOptionsConfigfile(const po::options_description &cf, bool visible)
802{
803    fOptionsConfigfile[visible].add(cf);
804}
805
806// --------------------------------------------------------------------------
807//
808//!
809//
810void Configuration::AddOptionsEnvironment(const po::options_description &env, bool visible)
811{
812    fOptionsEnvironment[visible].add(env);
813}
814
815// --------------------------------------------------------------------------
816//
817//!
818//
819void Configuration::AddOptionsDatabase(const po::options_description &db, bool visible)
820{
821    fOptionsDatabase[visible].add(db);
822}
823
824// --------------------------------------------------------------------------
825//
826//!
827//
828void Configuration::SetArgumentPositions(const po::positional_options_description &desc)
829{
830    fArgumentPositions = desc;
831}
832
833// --------------------------------------------------------------------------
834//
835//!
836//
837void Configuration::SetNameMapper(const function<string(string)> &func)
838{
839    fNameMapper = func;
840}
841
842void Configuration::SetNameMapper()
843{
844    fNameMapper = bind1st(mem_fun(&Configuration::DefaultMapper), this);
845}
846
847void Configuration::SetPrintUsage(const function<void(void)> &func)
848{
849    fPrintUsage = func;
850}
851
852void Configuration::SetPrintUsage()
853{
854    fPrintUsage = bind(&Configuration::PrintUsage, this);
855}
856
857void Configuration::SetPrintVersion(const function<void(const string&)> &func)
858{
859    fPrintVersion = func;
860}
861
862void Configuration::SetPrintVersion()
863{
864    fPrintVersion = function<void(const string&)>();
865}
866
867// --------------------------------------------------------------------------
868//
869//!
870//! The idea of the Parse() memeber-function is to parse the command-line,
871//! the configuration files, the databse and the environment and return
872//! a proper combined result.
873//!
874//! In details the following actions are performed in the given order:
875//!
876//!  - (0)  Init local variables with the list of options described by the
877//!         data members.
878//!  - (1)  Reset the data members fPriorityFile, fDefaultFile, fDatabase
879//!  - (2)  Parse the command line
880//!  - (3)  Check for \b --help* command-line options and performe
881//!         corresponding action
882//!  - (4)  Check for \b --print and \b --print-all and perform corresponding
883//!         action
884//!  - (5)  Read and parse the global configuration file, which is compiled
885//!         from the path corresponding to the argument given in the
886//!         constructor + "/fact++.rc", unrecognized options are always
887//!         allowed. Note that in contradiction to all other options
888//!         the options in this file are not checked at all. Hence,
889//!         typos might stay unnoticed.
890//!  - (6)  Read and parse the default configuration file, which is either
891//!         given by the default name or the \b --default command-line
892//!         option. The default name is compiled from the argument
893//!         given to the constructor and ".rc".  If the file-name is
894//!         identical to the default (no command-line option given)
895//!         a missing configuration file is no error. Depending on
896//!         the \b --dont-check and \b --dont-check-files options,
897//!         unrecognized options in the file throw an exception or not.
898//!  - (7)  Check for \b --print-default and \b --print-all and perform
899//!         corresponding action
900//!  - (8)  Read and parse the priority configuration file, which must be given
901//!         by the \b --config or \b -C command-line option or a
902//!         corresponding entry in the default-configuration file.
903//!         If an option on the command-line and the in the configuration
904//!         file exists, the command-line option has priority.
905//!         If none is given, no priority file is read. Depending on
906//!         the \b --dont-check and \b --dont-check-files options,
907//!         unrecognized options in the file throw an exception or not.
908//!  - (9)  Check for \b --print-config and \b --print-all and perform
909//!         corresponding action
910//!  - (10) Retrieve options from the database according to the
911//!         options \b --database and \b --no-database. Note that
912//!         options given on the command-line have highest priority.
913//!         The second priority is the priority-configuration file.
914//!         The options from the default configuration-file have
915//!         lowest priority.
916//!  - (11) Check for \b --print-database and \b --print-all and perform
917//!         corresponding action
918//!  - (12)  Parse the environment options.
919//!  - (13) Check for \b --print-environment and \b --print-all and perform
920//!         corresponding action
921//!  - (14) Compile the final result. The priority of the options is (in
922//!         decreasing order): command-line options, options from the
923//!         priority configuration file, options from the database,
924//!         options from the default configuration-file and options
925//!         from the environment.
926//!  - (15) Find all options which were found and flagged as unrecognized,
927//!         because they are not in the user-defined list of described
928//!         options, are collected and stored in the corresponding
929//!         data-members.
930//!  - (16) Find all options which where registered with wildcards and
931//!         store the list in fWildcardOptions.
932//!  - (17) Before the function returns it check for \b --print-options
933//!         and \b --print-unknown and performs the corresponding actions.
934//!
935//!
936//! @param argc,argv
937//!    arguments passed to <B>main(int argc, char **argv)</B>
938//!
939//! @returns
940//!    A reference to the list with the resulting options with their
941//!    values.
942//!
943//! @todo
944//!    - describe the exceptions
945//!    - describe what happens in a more general way
946//!    - print a waring when no default coonfig file is read
947//!    - proper handling and error messages if files not available
948//
949const po::variables_map &Configuration::Parse(int argc, const char **argv, const std::function<void()> &PrintHelp)
950{
951    const po::positional_options_description &opt_positional = fArgumentPositions;
952
953    // ------------------------ (0) --------------------------
954#ifdef DEBUG
955    cout << "--0--" << endl;
956#endif
957
958    po::options_description opt_commandline;
959    po::options_description opt_configfile;
960    po::options_description opt_environment;
961    po::options_description opt_database;
962
963    for (int i=0; i<2; i++)
964    {
965        opt_commandline.add(fOptionsCommandline[i]);
966        opt_configfile.add(fOptionsConfigfile[i]);
967        opt_environment.add(fOptionsEnvironment[i]);
968        opt_database.add(fOptionsDatabase[i]);
969    }
970
971    // ------------------------ (1) --------------------------
972#ifdef DEBUG
973    cout << "--1--" << endl;
974#endif
975
976    fPriorityFile = "";
977    fPrefixPath   = "";
978    fDefaultFile  = "";
979    fDatabase     = "";
980
981    // ------------------------ (2) --------------------------
982#ifdef DEBUG
983    cout << "--2--" << endl;
984#endif
985
986    po::command_line_parser parser(argc, const_cast<char**>(argv));
987    parser.options(opt_commandline);
988    parser.positional(opt_positional);
989    parser.style(style::unix_style&~style::allow_guessing);
990    //parser.allow_unregistered();
991
992    const po::parsed_options parsed_commandline = parser.run();
993
994    // ------------------------ (3) --------------------------
995#ifdef DEBUG
996    cout << "--3--" << endl;
997#endif
998
999    po::variables_map getfiles;
1000    po::store(parsed_commandline, getfiles);
1001
1002    if (getfiles.count("version"))
1003        PrintVersion();
1004    if (getfiles.count("help"))
1005    {
1006        fPrintUsage();
1007        cout <<
1008            "Options:\n"
1009            "The following describes the available commandline options. "
1010            "For further details on how command line option are parsed "
1011            "and in which order which configuration sources are accessed "
1012            "please refer to the class reference of the Configuration class." << endl;
1013        cout << fOptionsCommandline[kVisible] << endl;
1014    }
1015    if (getfiles.count("help-config"))
1016        cout << fOptionsConfigfile[kVisible] << endl;
1017    if (getfiles.count("help-env"))
1018        cout << fOptionsEnvironment[kVisible] << endl;
1019    if (getfiles.count("help-database"))
1020        cout << fOptionsDatabase[kVisible] << endl;
1021
1022
1023
1024    // ------------------------ (4) --------------------------
1025#ifdef DEBUG
1026    cout << "--4--" << endl;
1027#endif
1028
1029    if (getfiles.count("print") || getfiles.count("print-all"))
1030    {
1031        cout << endl << "Parsed commandline options:" << endl;
1032        PrintParsed(parsed_commandline);
1033        cout << endl;
1034    }
1035
1036    if (getfiles.count("help")     || getfiles.count("help-config") ||
1037        getfiles.count("help-env") || getfiles.count("help-database"))
1038    {
1039        if (PrintHelp)
1040            PrintHelp();
1041    }
1042
1043    // ------------------------ (5) --------------------------
1044#ifdef DEBUG
1045    cout << "--5--" << endl;
1046#endif
1047
1048    const boost::filesystem::path path(GetName());
1049    const string globalfile = (path.parent_path()/boost::filesystem::path("fact++.rc")).string();
1050
1051
1052    errno = 0;
1053
1054    ifstream gfile(globalfile.c_str());
1055    cerr << "Reading global  options from '" << globalfile << "' [" << strerror(errno) << "]" << endl;
1056    const po::parsed_options parsed_globalfile =
1057        !gfile ?
1058        po::parsed_options(&opt_configfile) :
1059        po::parse_config_file<char>(gfile, opt_configfile, true);
1060
1061    // ------------------------ (6) --------------------------
1062#ifdef DEBUG
1063    cout << "--6--" << endl;
1064#endif
1065
1066    po::store(parsed_globalfile, getfiles);
1067
1068    // Get default prefix path from command line
1069    if (getfiles.count("prefix"))
1070        fPrefixPath = getfiles["prefix"].as<string>();
1071
1072    // Get default file from command line
1073    if (getfiles.count("default"))
1074        fDefaultFile = getfiles["default"].as<string>();
1075
1076    const string default_file = (boost::filesystem::path(fPrefixPath)/boost::filesystem::path(fDefaultFile)).string();
1077
1078    const bool checkf    = !getfiles.count("dont-check-files") && !getfiles.count("dont-check");
1079    const bool defaulted = getfiles.count("default") && getfiles["default"].defaulted();
1080    //const bool exists    = boost::filesystem::exists(fDefaultFile);
1081
1082    errno = 0;
1083
1084    ifstream indef(default_file);
1085    if (!fDefaultFile.empty())
1086        cerr << "Reading default options from '" << default_file << "' [" << strerror(errno) << "]" << endl;
1087    const po::parsed_options parsed_defaultfile =
1088        !indef && defaulted ?
1089        po::parsed_options(&opt_configfile) :
1090        po::parse_config_file<char>(indef, opt_configfile, !checkf);
1091
1092    // ------------------------ (7) --------------------------
1093#ifdef DEBUG
1094    cout << "--7--" << endl;
1095#endif
1096
1097    if (getfiles.count("print-default") || getfiles.count("print-all"))
1098    {
1099        if (!indef.is_open() && defaulted)
1100            cout << "No configuration file by --default option specified." << endl;
1101        else
1102        {
1103            cout << endl << "Parsed options from '" << fDefaultFile << "':" << endl;
1104            PrintParsed(parsed_defaultfile);
1105            cout << endl;
1106        }
1107    }
1108
1109    po::store(parsed_defaultfile, getfiles);
1110
1111    // ------------------------ (8) --------------------------
1112#ifdef DEBUG
1113    cout << "--8--" << endl;
1114#endif
1115
1116    // Get priority from commandline(1), defaultfile(2)
1117    if (getfiles.count("config"))
1118    {
1119        fPriorityFile = getfiles["config"].as<string>();
1120        cerr << "Reading config  options from '" << fPriorityFile << "'." << endl;
1121    }
1122
1123    ifstream inpri(fPriorityFile.c_str());
1124    if (!fPriorityFile.empty() && !inpri)
1125        throw runtime_error("Reading '"+fPriorityFile+"' failed: "+strerror(errno));
1126
1127    // ===> FIXME: Proper handling of missing file or wrong file name
1128    const po::parsed_options parsed_priorityfile =
1129        fPriorityFile.empty() ? po::parsed_options(&opt_configfile) :
1130        po::parse_config_file<char>(inpri, opt_configfile, !checkf);
1131
1132    // ------------------------ (9) --------------------------
1133#ifdef DEBUG
1134    cout << "--9--" << endl;
1135#endif
1136
1137    if (getfiles.count("print-config") || getfiles.count("print-all"))
1138    {
1139        if (fPriorityFile.empty())
1140            cout << "No configuration file by --config option specified." << endl;
1141        else
1142        {
1143            cout << endl << "Parsed options from '" << fPriorityFile << "':" << endl;
1144            PrintParsed(parsed_priorityfile);
1145            cout << endl;
1146        }
1147    }
1148
1149    // ------------------------ (10) -------------------------
1150#ifdef DEBUG
1151    cout << "--10--" << endl;
1152#endif
1153
1154    po::variables_map getdatabase;
1155    po::store(parsed_commandline,  getdatabase);
1156    po::store(parsed_priorityfile, getdatabase);
1157    po::store(parsed_defaultfile,  getdatabase);
1158    po::store(parsed_globalfile,   getdatabase);
1159
1160    if (getdatabase.count("database") && !getdatabase.count("no-database"))
1161    {
1162        fDatabase = getdatabase["database"].as<string>();
1163        cerr << "Requesting options from database for '" << fName << "'" << endl;
1164    }
1165
1166    const bool checkdb = !getdatabase.count("dont-check-database") && !getdatabase.count("dont-check");
1167
1168    const po::parsed_options parsed_database =
1169        fDatabase.empty() ? po::parsed_options(&opt_database) :
1170#if BOOST_VERSION < 104600
1171        parse_database(path.filename(), fDatabase, opt_database, !checkdb);
1172#else
1173        parse_database(path.filename().string(), fDatabase, opt_database, !checkdb);
1174#endif
1175    // ------------------------ (11) -------------------------
1176#ifdef DEBUG
1177    cout << "--11--" << endl;
1178#endif
1179
1180    if (getfiles.count("print-database") || getfiles.count("print-all"))
1181    {
1182        if (fDatabase.empty())
1183            cout << "No database access requested." << endl;
1184        else
1185        {
1186            cout << endl << "Options received from '" << fDatabase << "':" << endl;
1187            PrintParsed(parsed_database);
1188            cout << endl;
1189        }
1190    }
1191
1192    // ------------------------ (12) -------------------------
1193#ifdef DEBUG
1194    cout << "--12--" << endl;
1195#endif
1196
1197    const po::parsed_options parsed_environment = po::parse_environment(opt_environment, fNameMapper);
1198
1199    // ------------------------ (13) -------------------------
1200#ifdef DEBUG
1201    cout << "--13--" << endl;
1202#endif
1203
1204    if (getfiles.count("print-environment"))
1205    {
1206        cout << "Parsed options from environment:" << endl;
1207        PrintParsed(parsed_environment);
1208        cout << endl;
1209    }
1210
1211    // ------------------------ (14) -------------------------
1212#ifdef DEBUG
1213    cout << "--14--" << endl;
1214#endif
1215
1216    po::variables_map result;
1217    po::store(parsed_commandline,  result);
1218    po::store(parsed_priorityfile, result);
1219    po::store(parsed_database,     result);
1220    po::store(parsed_defaultfile,  result);
1221    po::store(parsed_globalfile,   result);
1222    po::store(parsed_environment,  result);
1223    po::notify(result);
1224
1225    fVariables = result;
1226
1227    // ------------------------ (15) -------------------------
1228#ifdef DEBUG
1229    cout << "--15--" << endl;
1230#endif
1231
1232    const vector<string> unknown0 = collect_unrecognized(parsed_globalfile.options,   po::exclude_positional);
1233    const vector<string> unknown1 = collect_unrecognized(parsed_defaultfile.options,  po::exclude_positional);
1234    const vector<string> unknown2 = collect_unrecognized(parsed_priorityfile.options, po::exclude_positional);
1235
1236    fUnknownConfigfile.clear();
1237    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown0.begin(), unknown0.end());
1238    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown1.begin(), unknown1.end());
1239    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown2.begin(), unknown2.end());
1240
1241    fUnknownCommandline = collect_unrecognized(parsed_commandline.options, po::exclude_positional);
1242    fUnknownEnvironment = collect_unrecognized(parsed_environment.options, po::exclude_positional);
1243    fUnknownDatabase    = collect_unrecognized(parsed_database.options, po::exclude_positional);
1244
1245    // ------------------------ (16) -------------------------
1246#ifdef DEBUG
1247    cout << "--16--" << endl;
1248#endif
1249
1250    CreateWildcardOptions();
1251
1252    // ------------------------ (17) -------------------------
1253#ifdef DEBUG
1254    cout << "--17--" << endl;
1255#endif
1256
1257    if (result.count("print-options"))
1258        PrintOptions();
1259
1260    if (result.count("print-wildcards"))
1261        PrintWildcardOptions();
1262
1263    if (result.count("print-unknown"))
1264        PrintUnknown();
1265
1266#ifdef DEBUG
1267    cout << "------" << endl;
1268#endif
1269
1270    return fVariables;
1271}
1272
1273const po::variables_map &Configuration::ParseFile(const string &fname, const bool &checkf)
1274{
1275    // -------------------------------------------------------
1276    po::options_description opt_configfile;
1277
1278    for (int i=0; i<2; i++)
1279        opt_configfile.add(fOptionsConfigfile[i]);
1280
1281    // -------------------------------------------------------
1282
1283    ifstream file(fname.c_str());
1284    // ===> FIXME: Proper handling of missing file or wrong file name
1285    const po::parsed_options parsed_file =
1286        po::parse_config_file<char>(file, opt_configfile, !checkf);
1287
1288    // -------------------------------------------------------
1289
1290    po::variables_map result;
1291    po::store(parsed_file, result);
1292    po::notify(result);
1293
1294    fVariables = result;
1295
1296    // -------------------------------------------------------
1297
1298    const vector<string> unknown = collect_unrecognized(parsed_file.options, po::exclude_positional);
1299
1300    fUnknownConfigfile.clear();
1301    fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown.begin(), unknown.end());
1302
1303    // -------------------------------------------------------
1304
1305    CreateWildcardOptions();
1306
1307    // -------------------------------------------------------
1308
1309    return fVariables;
1310}
1311
1312bool Configuration::DoParse(int argc, const char **argv, const std::function<void()> &PrintHelp)
1313{
1314    try
1315    {
1316        Parse(argc, argv, PrintHelp);
1317    }
1318#if BOOST_VERSION > 104100
1319    catch (const po::multiple_occurrences &e)
1320    {
1321        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1322        return false;
1323    }
1324#endif
1325    catch (const exception& e)
1326    {
1327        cerr << "Program options invalid due to: " << e.what() << endl;
1328        return false;
1329    }
1330
1331    return !HasVersion() && !HasPrint() && !HasHelp();
1332}
1333
1334bool Configuration::ReadFile(const string &fname, const bool &checkf)
1335{
1336    try
1337    {
1338        ParseFile(fname, checkf);
1339    }
1340#if BOOST_VERSION > 104100
1341    catch (const po::multiple_occurrences &e)
1342    {
1343        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1344        return false;
1345    }
1346#endif
1347    catch (const exception& e)
1348    {
1349        cerr << "Program options invalid due to: " << e.what() << endl;
1350        return false;
1351    }
1352
1353    return true;
1354}
1355
1356// --------------------------------------------------------------------------
1357//
1358//! Create a list of all options which were registered using wildcards
1359//!
1360void Configuration::CreateWildcardOptions()
1361{
1362    po::options_description opts;
1363
1364    for (int i=0; i<2; i++)
1365    {
1366        opts.add(fOptionsCommandline[i]);
1367        opts.add(fOptionsConfigfile[i]);
1368        opts.add(fOptionsEnvironment[i]);
1369        opts.add(fOptionsDatabase[i]);
1370    }
1371
1372    fWildcardOptions.clear();
1373
1374    typedef map<string,po::variable_value> Vars;
1375    typedef vector<boost::shared_ptr<po::option_description>> Descs;
1376
1377    const Descs &desc = opts.options();
1378
1379    for (Vars::const_iterator io=fVariables.begin(); io!=fVariables.end(); io++)
1380    {
1381        for (Descs::const_iterator id=desc.begin(); id!=desc.end(); id++)
1382#if BOOST_VERSION > 104100
1383            if ((*id)->match(io->first, false, false, false)==po::option_description::approximate_match)
1384#else
1385            if ((*id)->match(io->first, false)==po::option_description::approximate_match)
1386#endif
1387                fWildcardOptions[io->first] = (*id)->long_name();
1388    }
1389}
1390
1391// --------------------------------------------------------------------------
1392//
1393//! Print a list of all options which were registered using wildcards and
1394//! have not be registered subsequently by access.
1395//!
1396void Configuration::PrintWildcardOptions() const
1397{
1398    cout << "Options registered with wildcards and not yet accessed:" << endl;
1399
1400    size_t max = 0;
1401    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1402        if (it->second.length()>max)
1403            max = it->second.length();
1404
1405    cout.setf(ios_base::left);
1406    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1407        cout << setw(max+1) << it->second << " : " << it->first <<endl;
1408}
1409
1410const vector<string> Configuration::GetWildcardOptions(const std::string &opt) const
1411{
1412    vector<string> rc;
1413
1414    for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1415    {
1416        if (it->second == opt)
1417            rc.push_back(it->first);
1418    }
1419
1420    return rc;
1421}
1422
1423// --------------------------------------------------------------------------
1424//
1425//! Removes /.libs/lt- from a path or just lt- from the filename.
1426//!
1427//! @param src
1428//!    input path with filename
1429//! @returns
1430//!    path cleaned from libtool extensions
1431//!
1432string Configuration::UnLibToolize(const string &src) const
1433{
1434    const boost::filesystem::path path(src);
1435
1436    string pname = path.parent_path().string();
1437#if BOOST_VERSION < 104600
1438    string fname = path.filename();
1439#else
1440    string fname = path.filename().string();
1441#endif
1442
1443    // If the filename starts with "lt-" remove it from the name
1444    if (fname.substr(0, 3)=="lt-")
1445        fname = fname.substr(3);
1446
1447    string pwd;
1448    // If no directory is contained determine the current directory
1449    if (pname.empty())
1450        pname = boost::filesystem::current_path().string();
1451
1452    // If the directory is relative and just ".libs" forget about it
1453    if (pname==".libs")
1454        return fname;
1455
1456
1457    // Check if the directory is long enough to contain "/.libs"
1458    if (pname.length()>=6)
1459    {
1460        // If the directory ends with "/.libs", remove it
1461        const size_t pos = pname.length()-6;
1462        if (pname.substr(pos)=="/.libs")
1463            pname = pname.substr(0, pos);
1464    }
1465
1466    // If the path is the local path do not return the path-name
1467    if (pname==boost::filesystem::current_path().string())
1468        return fname;
1469
1470    return pname+'/'+fname;
1471}
1472
1473// --------------------------------------------------------------------------
1474//
1475//! Print version information about the program and package.
1476//!
1477//! The program name is taken from fName. If a leading "lt-" is found,
1478//! it is removed. This is useful if the program was build and run
1479//! using libtool.
1480//!
1481//! The package name is taken from the define PACKAGE_STRING. If it is
1482//! not defined (like automatically done by autoconf) no package information
1483//! is printed. The same is true for PACKAGE_URL and PACKAGE_BUGREPORT.
1484//!
1485//! From help2man:
1486//!
1487//! The first line of the --version information is assumed to be in one
1488//! of the following formats:
1489//!
1490//! \verbatim
1491//!  - <version>
1492//!  - <program> <version>
1493//!  - {GNU,Free} <program> <version>
1494//!  - <program> ({GNU,Free} <package>) <version>
1495//!  - <program> - {GNU,Free} <package> <version>
1496//! \endverbatim
1497//!
1498//!  and separated from any copyright/author details by a blank line.
1499//!
1500//! Handle multi-line bug reporting sections of the form:
1501//!
1502//! \verbatim
1503//!  - Report <program> bugs to <addr>
1504//!  - GNU <package> home page: <url>
1505//!  - ...
1506//! \endverbatim
1507//!
1508//! @param name
1509//!     name of the program (usually argv[0]).
1510//!
1511void Configuration::PrintVersion() const
1512{
1513#ifndef PACKAGE_STRING
1514#define PACKAGE_STRING ""
1515#endif
1516
1517#ifndef PACKAGE_URL
1518#define PACKAGE_URL ""
1519#endif
1520
1521#ifndef PACKAGE_BUGREPORT
1522#define PACKAGE_BUGREPORT ""
1523#endif
1524
1525    if (fPrintVersion)
1526    {
1527        fPrintVersion(fName);
1528        return;
1529    }
1530
1531#if BOOST_VERSION < 104600
1532    const std::string n = boost::filesystem::path(fName).filename();
1533#else
1534    const std::string n = boost::filesystem::path(fName).filename().string();
1535#endif
1536
1537    const string name = PACKAGE_STRING;
1538    const string bugs = PACKAGE_BUGREPORT;
1539    const string url  = PACKAGE_URL;
1540
1541    cout << n;
1542    if (!name.empty())
1543        cout << " - " << name;
1544    cout <<
1545        "\n\n"
1546        "Written by Thomas Bretz et al.\n"
1547        "\n";
1548    if (!bugs.empty())
1549        cout << "Report bugs to <" << bugs << ">\n";
1550    if (!url.empty())
1551        cout << "Home page: " << url << "\n";
1552    cout <<
1553        "\n"
1554        "Copyright (C) 2011 by the FACT Collaboration.\n"
1555        "This is free software; see the source for copying conditions.\n"
1556        << std::endl;
1557}
Note: See TracBrowser for help on using the repository browser.