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

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