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

Last change on this file since 19435 was 19385, checked in by tbretz, 6 years 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.