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

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