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

Last change on this file since 20084 was 20081, checked in by tbretz, 4 years ago
Updated where the program looks for fact++.rc: 1) current working directory, 2) executable location, 3) sysconfdir (if available)
File size: 51.8 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 fromx the global configuration-file (\b fact++.rc)
34 - (6) Environment variables
35
36The global configuration-file fact++.rc is search in 1) the current working
37directory, 2) the directory in which the executable is located, 3) the sysconfdir
38(defined during compile time).
39
40Which options are accepted is defined by the program. To get a list
41of all command-line option use \b --help. This also lists all other
42available options to list for exmaple the options available in the
43configuration files or from the databse. In addition some default options
44are available which allow to debug parsing of the options, by either printing
45the options retrieval or after parsing.
46
47Options in the configuration files must be given in the form
48
49 - key = value
50
51which is equivalent to the command-line option <B>--key=value</B>.
52
53If there are sections in the configuration file like
54
55\code
56
57 [section1]
58 key = value
59
60\endcode
61
62the key is transformed into <B>section1.key</B> (which would be equivalent
63to <B>--section1.key</B>)
64
65@attention
66In principle it is possible that an exception is thrown before options
67like \b --help are properly parsed and evaluated. In this case it is
68necessary to first resolve the problem. Usually, this mean that there
69is a design flaw in the program rather than a mistake of usage.
70
71For more details on the order in which configuration is read,
72check Configuration::Parse. For more details on the parsing itself
73see the documentation of boost::program_options.
74
75
76
77
78@section API For the programmer
79
80The Configuration class heavily uses the
81<A HREF="http://www.boost.org"><B>C++ boost library</B></A>
82and makes heavy use of the
83<A HREF="http://www.boost.org/doc/libs/release/doc/html/program_options.html">
84<B>boost::program_options</B></A>
85
86The databse access is based on the
87<A HREF="http://tangentsoft.net/mysql++/"><B>MySQL++ library</B></A>.
88
89The basic idea is to have an easy to use, but powerfull setup. The setup on
90all options is based on a special syntax of options_description. Here is an
91example:
92
93\code
94
95 int opt = 0;
96
97 po::options_description config("Section");
98 config.add_options()
99 ("option1", var<string>(), "This is option1")
100 ("option2", var<int>(22), "This is option2")
101 ("option3,o", var<double>->required(), "This option is mandatory")
102 ("option4", var<int>(&opt), "This is option 4")
103 ("option5", vars<string>(), "A list of strings")
104 ("option6", vars<string>(), "A list of strings")
105 ("option7", vars<string>, "A list of strings")
106 ("option8", var<string>()->implicit_value("val"), "Just a string")
107 ("option9", var<string>()->default_value("def"), "Just a string")
108 ("optionA", var<string>("def"), "Just a string")
109 ("bool", po_bool(), "A special switch")
110 ;
111
112\endcode
113
114This will setup, e.g., the commandline option '<B>--option1 arg</B>' (which
115is identical to '<B>--option1=arg</B>'. Option 3 can also be expressed
116in a short form as '<B>-o arg</B>' or '<B>-o=arg</B>'. Option 2 defaults
117to 22 if no explicit value is given. Option 3 is mandatory and an exceptionb
118is thrown if not specified. Option 4 will, apart from the usual access to the
119option values, also store its value in the variable opt.
120
121The used functions po_*() are defined in configuration.h and are abbreviations.
122Generally speaking also other variable types are possible.
123
124If the options are displayed, e.g. by \b --help the corresponding section will
125by titled \e Section, also untitled sections are possible.
126
127If an option can be given more than once then a std::vector<type> can be used.
128Abbreviations po_ints(), po_doubles() and po_strings() are available.
129
130There are several ways to define the behaviour of the options. In the
131example above Parse will throw an exception if the "--option3" or "-o"
132option is not given. "option9" will evaluate to "def" if it is not
133given on the command line. The syntax of "optionA" is just an
134abbreviation. "option8" will evaluate to "val" if just "--option5" but
135no argument is given. Note, that these modifiers can be concatenated.
136
137A special type po_bool() is provided which is an abbreviation of
138var<bool>()->implicit_value(true)->default_value(false). In
139contradiction to po_switch() this allows to set a true and
140false value in the setup file.
141
142In addition to options introduced by a minus or double minus, so called
143positional options can be given on the command line. To describe these
144options use
145
146\code
147
148 po::positional_options_description p;
149 p.add("option5", 2); // The first 2 positional options
150 p.add("option6", 3); // The next three positional options
151 // p.add("option7", -1); // All others, if wanted
152
153\endcode
154
155This assigns option-keys to the positional options (arguments) in the
156command-line. Note that the validity of the given commandline is checked.
157Hence, this way of defining the options makes sense.
158
159As needed options_descriptions can be grouped together
160
161\code
162
163 po::options_description config1("Section1");
164 po::options_description config2("Section2");
165
166 po::options_description configall;
167 configall.add(config1);
168 configall.add(config2);
169
170\endcode
171
172The member functions of Configurations allow to define for which option
173source these options are valid. The member functions are:
174
175\code
176
177 Configuration conf;
178
179 conf.AddOptionsCommandline(configall, true);
180 conf.AddOptionsConfigfile(config1, true);
181 conf.AddOptionsDatabase(config2, true);
182
183 // To enable the mapping of the position arguments call this
184 conf.SetArgumentPositions(p);
185
186\endcode
187
188If the second option is false, the options will not be displayed in any
189\b --help directive, but are available to the user. Each of the functions
190can be called more than once. If an option should be available from
191all kind of inputs AddOptions() can be used which will call all
192four other AddOptions() functions.
193
194A special case are the options from environment variables. Since you might
195want to use the same option-key for the command-line and the environment,
196a mapping is needed (e.g. from \b PATH to \b --path). This mapping
197can be implemented by a mapping function or by the build in mapping
198and be initialized like this:
199
200\code
201
202 conf.AddEnv("path", "PATH");
203
204\endcode
205
206or
207
208\code
209
210 const string name_mapper(const string str)
211 {
212 return str=="PATH" ? "path" : "";
213 }
214
215 conf.SetNameMapper(name_mapper);
216
217\endcode
218
219Assuming all the above is done in a function calles SetupConfiguration(),
220a simple program to demonstrate the power of the class could look like this:
221
222\code
223
224 int main(int argc, char **argv)
225 {
226 int opt;
227
228 Configuration conf(argv[0]);
229 SetupConfiguration(conf, opt);
230
231 po::variables_map vm;
232 try
233 {
234 vm = conf.Parse(argc, argv);
235 }
236 catch (std::exception &e)
237 {
238 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
239 if (MO)
240 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
241 else
242 cout << "Error: " << e.what() << endl;
243 cout << endl;
244
245 return -1;
246 }
247
248 cout << "Opt1: " << conf.GetString("option1") << endl;
249 cout << "Opt2: " << conf.GetInt("option2") << endl;
250 cout << "Opt3: " << conf.GetDouble("option3") << endl;
251 cout << "Opt4: " << opt << endl;
252
253 return 0;
254 }
255
256\endcode
257
258Another possibility to access the result is the direct approach, for example:
259
260\code
261
262 vector<int> i = vm["option2"].as<int>();
263 vector<string> vec = vm["option6"].as<vector<string>>();
264
265\endcode
266
267Note that accessing an option which was not given will throw an exception.
268Therefor its availability should first be checked in one of the following
269ways:
270
271\code
272
273 bool has_option1 = vm.count("option1");
274 bool has_option2 = conf.Has("option2");
275
276\endcode
277
278@section Extensions
279
280The configuration interpreter can be easily extended to new types, for example:
281
282\code
283
284template<class T,class S> // Just for the output
285 std::ostream &operator<<(std::ostream &out, const pair<T,S> &f)
286 {
287 out << f.first << "|" << f.second;
288 return out;
289 }
290
291template<class T, class S> // Needed to convert the option
292 std::istream &operator>>(std::istream &in, pair<T,S> &f)
293 {
294 char c;
295 in >> f.first;
296 in >> c;
297 if (c!=':')
298 return in;
299 in >> f.second;
300 return in;
301 }
302
303typedef pair<int,int> mytype; // Type definition
304
305void main(int argc, char **argv)
306{
307 po::options_description config("Configuration");
308 config.add_options()
309 ("mytype", var<mytype>(), "my new type")
310 ;
311
312 Configuration conf;
313 conf.AddOptionsCommandline(config);
314 conf.Parse(argc, argv);
315
316 cout << conf.Get<mytype>("mytype") << endl;
317}
318
319\endcode
320
321@section Examples
322
323 - An example can be found in \ref argv.cc
324
325@todo
326
327 - Maybe we should remove the necessity to propagate argv[0] in the constructor?
328 - Add an option to the constructor to switch of database/file access
329
330*/
331// **************************************************************************
332#include "Configuration.h"
333
334#include <fstream>
335#include <iostream>
336#include <iomanip>
337
338#ifdef HAVE_SQL
339#include "Database.h"
340#endif
341
342using namespace std;
343
344namespace style = boost::program_options::command_line_style;
345
346// --------------------------------------------------------------------------
347//
348//! The purpose of this function is basically to connect to the database,
349//! and retrieve all the options entries from the 'Configuration' table.
350//!
351//! @param database
352//! The URL of the database from which the configuration data is
353//! retrieved. It should be given in the form
354//! \li [user[:password]@]server.com[:port]/database[?compress=0|1]
355//!
356//! with
357//! - user: user name (default is the current user)
358//! - password: necessary if required by the database rights
359//! - server: the URL of the server (can be 'localhost')
360//! - port: the port to which to connect (usually obsolete)
361//! - database: The name of the database containing the table
362//! - compress: Force [=1] / prohibit [=0] compression
363//!
364//! The default is that connections to the SQL server are compressed
365//! whenever the server is neither '127.0.0.1' nor 'localhost'.
366//! Use '/+' to force compression and '/-' to prohibit compression.
367//!
368//! @param desc
369//! A reference to the object with the description of the options
370//! which should be retrieved.
371//!
372//! @param allow_unregistered
373//! If this is true also unregistered, i.e. options unknown to desc,
374//! are returned. Otherwise an exception is thrown if such an option
375//! was retrieved.
376//!
377//! @return
378//! Return an object of type basic_parsed_options containing all
379//! the entries retrieved from the database. Options not found in
380//! desc are flagged as unregistered.
381//!
382//! @throws
383//! Two types of exceptions are thrown
384//! - It thows an unnamed exception if the options could not be
385//! retrieved properly from the databse.
386//! - If an option is not registered within the given descriptions
387//! and \b allow_unregistered is \b false, an exception of type
388//! \b po::unknown_option is thrown.
389//!
390//! @todo
391//! - The exceptions handling should be improved.
392//! - The final database layout is missing in the description
393//! - Shell we allow options to be given more than once?
394//
395#ifdef HAVE_SQL
396po::basic_parsed_options<char>
397 Configuration::parse_database(const string &prgname, const string &database, const po::options_description& desc, bool allow_unregistered)
398{
399 Database db(database);
400
401 cerr << "Connected to '" << db.uri() << "' for " << prgname << endl;
402
403 const mysqlpp::StoreQueryResult res =
404 db.query("SELECT CONCAT(fKey1,fKey2), fValue "
405 "FROM ProgramOption "
406 "WHERE fCounter=(SELECT MAX(fCounter) FROM History) "
407 "AND NOT ISNULL(fValue) "
408 "AND (fProgram='"+prgname+"' OR fProgram='*')").store();
409
410 set<string> allowed_options;
411
412 const vector<boost::shared_ptr<po::option_description>> &options = desc.options();
413 for (unsigned i=0; i<options.size(); ++i)
414 {
415 const po::option_description &d = *options[i];
416 if (d.long_name().empty())
417 boost::throw_exception(po::error("long name required for database"));
418
419 allowed_options.insert(d.long_name());
420 }
421
422 po::parsed_options result(&desc);
423
424 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
425 {
426 const string key = (*v)[0].c_str();
427 if (key.empty()) // key == > Throw exception
428 continue;
429
430 // Check if we are allowed to accept unregistered options,
431 // i.e. options which are not in options_description &desc.
432 const bool unregistered = allowed_options.find(key)==allowed_options.end();
433 if (unregistered && allow_unregistered)
434 boost::throw_exception(po::unknown_option(key));
435
436 // Create a key/value-pair and store whether it is a
437 // registered option of not
438 po::option n;
439 n.string_key = key;
440 // This is now identical to file parsing. What if we want
441 // to concatenate options like on the command line?
442 n.value.clear(); // Fixme: composing?
443 n.value.push_back((*v)[1].c_str());
444 //n.unregistered = unregistered;
445
446 // If any parsing will be done in the future...
447 //n.value().original_tokens.clear();
448 //n.value().original_tokens.push_back(name);
449 //n.value().original_tokens.push_back(value);
450
451 result.options.push_back(n);
452 }
453
454 return result;
455}
456#else
457po::basic_parsed_options<char>
458 Configuration::parse_database(const string &, const string &, const po::options_description &desc, bool)
459{
460 return po::parsed_options(&desc);
461}
462#endif
463
464// --------------------------------------------------------------------------
465//
466//!
467//
468Configuration::Configuration(const string &prgname) : fName(UnLibToolize(prgname)),
469fNameMapper(bind1st(mem_fun(&Configuration::DefaultMapper), this)),
470fPrintUsage(bind(&Configuration::PrintUsage, this))
471{
472 if (prgname.empty())
473 return;
474
475 const boost::filesystem::path rc(fName+".rc");
476
477 po::options_description generic("Generic options");
478 generic.add_options()
479 ("version,V", "Print version information.")
480 ("help", "Print available commandline options.")
481 ("help-environment", "Print available environment variables.")
482 ("help-database", "Print available options retreived from the database.")
483 ("help-config", "Print available configuration file options.")
484 ("print-all", "Print all options as parsed from all the different sources.")
485 ("print", "Print options as parsed from the commandline.")
486 ("print-default", "Print options as parsed from default configuration file.")
487 ("print-database", "Print options as retrieved from the database.")
488 ("print-config", "Print options as parsed from the high priority configuration file.")
489 ("print-environment", "Print options as parsed from the environment.")
490 ("print-unknown", "Print unrecognized options.")
491 ("print-options", "Print options as passed to program.")
492 ("print-wildcards", "Print all options registered with wildcards.")
493 ("dont-check", "Do not check validity of options from files and database.")
494 ("dont-check-files", "Do not check validity of options from files.")
495 ("dont-check-database", "Do not check validity of options from database.")
496 ;
497
498 po::options_description config("Configuration options");
499 config.add_options()
500 ("config,C", var<string>(), "Configuration file overwriting options retrieved from the database.")
501 ("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.")
502 ("no-database", "Suppress any access to the database even if a database URL was set.")
503 ("default", var<string>(rc.filename().string()), "Name of default configuration file.")
504 ("prefix", var<string>(rc.parent_path().string()), "Path to default configuration file.")
505 ;
506
507 fOptionsCommandline[kVisible].add(generic);
508 fOptionsCommandline[kVisible].add(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//! "/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 fPrefixPath = "";
984 fDefaultFile = "";
985 fDatabase = "";
986
987 // ------------------------ (2) --------------------------
988#ifdef DEBUG
989 cout << "--2--" << endl;
990#endif
991
992 po::command_line_parser parser(argc, const_cast<char**>(argv));
993 parser.options(opt_commandline);
994 parser.positional(opt_positional);
995 parser.style(style::unix_style&~style::allow_guessing);
996 //parser.allow_unregistered();
997
998 const po::parsed_options parsed_commandline = parser.run();
999
1000 // ------------------------ (3) --------------------------
1001#ifdef DEBUG
1002 cout << "--3--" << endl;
1003#endif
1004
1005 po::variables_map getfiles;
1006 po::store(parsed_commandline, getfiles);
1007
1008 if (getfiles.count("version"))
1009 PrintVersion();
1010 if (getfiles.count("help"))
1011 {
1012 fPrintUsage();
1013 cout <<
1014 "Options:\n"
1015 "The following describes the available commandline options. "
1016 "For further details on how command line option are parsed "
1017 "and in which order which configuration sources are accessed "
1018 "please refer to the class reference of the Configuration class." << endl;
1019 cout << fOptionsCommandline[kVisible] << endl;
1020 }
1021 if (getfiles.count("help-config"))
1022 cout << fOptionsConfigfile[kVisible] << endl;
1023 if (getfiles.count("help-env"))
1024 cout << fOptionsEnvironment[kVisible] << endl;
1025 if (getfiles.count("help-database"))
1026 cout << fOptionsDatabase[kVisible] << endl;
1027
1028
1029
1030 // ------------------------ (4) --------------------------
1031#ifdef DEBUG
1032 cout << "--4--" << endl;
1033#endif
1034
1035 if (getfiles.count("print") || getfiles.count("print-all"))
1036 {
1037 cout << endl << "Parsed commandline options:" << endl;
1038 PrintParsed(parsed_commandline);
1039 cout << endl;
1040 }
1041
1042 if (getfiles.count("help") || getfiles.count("help-config") ||
1043 getfiles.count("help-env") || getfiles.count("help-database"))
1044 {
1045 if (PrintHelp)
1046 PrintHelp();
1047 }
1048
1049 // ------------------------ (5) --------------------------
1050#ifdef DEBUG
1051 cout << "--5--" << endl;
1052#endif
1053
1054 const boost::filesystem::path path(GetName());
1055 string globalfile = (boost::filesystem::current_path()/boost::filesystem::path("fact++.rc")).string();
1056 cerr << "Searching global options in '" << globalfile << "'" << endl;
1057
1058 if (!boost::filesystem::exists(globalfile) && boost::filesystem::current_path()!=path.parent_path())
1059 {
1060 globalfile = (path.parent_path()/boost::filesystem::path("fact++.rc")).string();
1061 cerr << "Searching global options in '" << globalfile << "'" << endl;
1062 }
1063
1064#ifdef PACKAGE_INSTALL_SYSCONFDIR
1065 if (!boost::filesystem::exists(globalfile))
1066 {
1067 globalfile = (boost::filesystem::path(PACKAGE_INSTALL_SYSCONFDIR)/boost::filesystem::path("fact++.rc")).string();
1068 cerr << "Searching global options in '" << globalfile << "'" << endl;
1069 }
1070#endif
1071
1072 errno = 0;
1073
1074 ifstream gfile(globalfile.c_str());
1075 cerr << "Reading global options from '" << globalfile << "' [" << strerror(errno) << "]" << endl;
1076 const po::parsed_options parsed_globalfile =
1077 !gfile ?
1078 po::parsed_options(&opt_configfile) :
1079 po::parse_config_file<char>(gfile, opt_configfile, true);
1080
1081 // ------------------------ (6) --------------------------
1082#ifdef DEBUG
1083 cout << "--6--" << endl;
1084#endif
1085
1086 po::store(parsed_globalfile, getfiles);
1087
1088 // Get default prefix path from command line
1089 if (getfiles.count("prefix"))
1090 fPrefixPath = getfiles["prefix"].as<string>();
1091
1092 // Get default file from command line
1093 if (getfiles.count("default"))
1094 fDefaultFile = getfiles["default"].as<string>();
1095
1096 const string default_file = (boost::filesystem::path(fPrefixPath)/boost::filesystem::path(fDefaultFile)).string();
1097
1098 const bool checkf = !getfiles.count("dont-check-files") && !getfiles.count("dont-check");
1099 const bool defaulted = getfiles.count("default") && getfiles["default"].defaulted();
1100 //const bool exists = boost::filesystem::exists(fDefaultFile);
1101
1102 errno = 0;
1103
1104 ifstream indef(default_file);
1105 if (!fDefaultFile.empty())
1106 cerr << "Reading default options from '" << default_file << "' [" << strerror(errno) << "]" << endl;
1107 const po::parsed_options parsed_defaultfile =
1108 !indef && defaulted ?
1109 po::parsed_options(&opt_configfile) :
1110 po::parse_config_file<char>(indef, opt_configfile, !checkf);
1111
1112 // ------------------------ (7) --------------------------
1113#ifdef DEBUG
1114 cout << "--7--" << endl;
1115#endif
1116
1117 if (getfiles.count("print-default") || getfiles.count("print-all"))
1118 {
1119 if (!indef.is_open() && defaulted)
1120 cout << "No configuration file by --default option specified." << endl;
1121 else
1122 {
1123 cout << endl << "Parsed options from '" << fDefaultFile << "':" << endl;
1124 PrintParsed(parsed_defaultfile);
1125 cout << endl;
1126 }
1127 }
1128
1129 po::store(parsed_defaultfile, getfiles);
1130
1131 // ------------------------ (8) --------------------------
1132#ifdef DEBUG
1133 cout << "--8--" << endl;
1134#endif
1135
1136 // Get priority from commandline(1), defaultfile(2)
1137 if (getfiles.count("config"))
1138 {
1139 fPriorityFile = getfiles["config"].as<string>();
1140 cerr << "Reading config options from '" << fPriorityFile << "'." << endl;
1141 }
1142
1143 ifstream inpri(fPriorityFile.c_str());
1144 if (!fPriorityFile.empty() && !inpri)
1145 throw runtime_error("Reading '"+fPriorityFile+"' failed: "+strerror(errno));
1146
1147 // ===> FIXME: Proper handling of missing file or wrong file name
1148 const po::parsed_options parsed_priorityfile =
1149 fPriorityFile.empty() ? po::parsed_options(&opt_configfile) :
1150 po::parse_config_file<char>(inpri, opt_configfile, !checkf);
1151
1152 // ------------------------ (9) --------------------------
1153#ifdef DEBUG
1154 cout << "--9--" << endl;
1155#endif
1156
1157 if (getfiles.count("print-config") || getfiles.count("print-all"))
1158 {
1159 if (fPriorityFile.empty())
1160 cout << "No configuration file by --config option specified." << endl;
1161 else
1162 {
1163 cout << endl << "Parsed options from '" << fPriorityFile << "':" << endl;
1164 PrintParsed(parsed_priorityfile);
1165 cout << endl;
1166 }
1167 }
1168
1169 // ------------------------ (10) -------------------------
1170#ifdef DEBUG
1171 cout << "--10--" << endl;
1172#endif
1173
1174 po::variables_map getdatabase;
1175 po::store(parsed_commandline, getdatabase);
1176 po::store(parsed_priorityfile, getdatabase);
1177 po::store(parsed_defaultfile, getdatabase);
1178 po::store(parsed_globalfile, getdatabase);
1179
1180 if (getdatabase.count("database") && !getdatabase.count("no-database"))
1181 {
1182 fDatabase = getdatabase["database"].as<string>();
1183 cerr << "Requesting options from database for '" << fName << "'" << endl;
1184 }
1185
1186 const bool checkdb = !getdatabase.count("dont-check-database") && !getdatabase.count("dont-check");
1187
1188 const po::parsed_options parsed_database =
1189 fDatabase.empty() ? po::parsed_options(&opt_database) :
1190#if BOOST_VERSION < 104600
1191 parse_database(path.filename(), fDatabase, opt_database, !checkdb);
1192#else
1193 parse_database(path.filename().string(), fDatabase, opt_database, !checkdb);
1194#endif
1195 // ------------------------ (11) -------------------------
1196#ifdef DEBUG
1197 cout << "--11--" << endl;
1198#endif
1199
1200 if (getfiles.count("print-database") || getfiles.count("print-all"))
1201 {
1202 if (fDatabase.empty())
1203 cout << "No database access requested." << endl;
1204 else
1205 {
1206 cout << endl << "Options received from '" << fDatabase << "':" << endl;
1207 PrintParsed(parsed_database);
1208 cout << endl;
1209 }
1210 }
1211
1212 // ------------------------ (12) -------------------------
1213#ifdef DEBUG
1214 cout << "--12--" << endl;
1215#endif
1216
1217 const po::parsed_options parsed_environment = po::parse_environment(opt_environment, fNameMapper);
1218
1219 // ------------------------ (13) -------------------------
1220#ifdef DEBUG
1221 cout << "--13--" << endl;
1222#endif
1223
1224 if (getfiles.count("print-environment"))
1225 {
1226 cout << "Parsed options from environment:" << endl;
1227 PrintParsed(parsed_environment);
1228 cout << endl;
1229 }
1230
1231 // ------------------------ (14) -------------------------
1232#ifdef DEBUG
1233 cout << "--14--" << endl;
1234#endif
1235
1236 po::variables_map result;
1237 po::store(parsed_commandline, result);
1238 po::store(parsed_priorityfile, result);
1239 po::store(parsed_database, result);
1240 po::store(parsed_defaultfile, result);
1241 po::store(parsed_globalfile, result);
1242 po::store(parsed_environment, result);
1243 po::notify(result);
1244
1245 fVariables = result;
1246
1247 // ------------------------ (15) -------------------------
1248#ifdef DEBUG
1249 cout << "--15--" << endl;
1250#endif
1251
1252 const vector<string> unknown0 = collect_unrecognized(parsed_globalfile.options, po::exclude_positional);
1253 const vector<string> unknown1 = collect_unrecognized(parsed_defaultfile.options, po::exclude_positional);
1254 const vector<string> unknown2 = collect_unrecognized(parsed_priorityfile.options, po::exclude_positional);
1255
1256 fUnknownConfigfile.clear();
1257 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown0.begin(), unknown0.end());
1258 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown1.begin(), unknown1.end());
1259 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown2.begin(), unknown2.end());
1260
1261 fUnknownCommandline = collect_unrecognized(parsed_commandline.options, po::exclude_positional);
1262 fUnknownEnvironment = collect_unrecognized(parsed_environment.options, po::exclude_positional);
1263 fUnknownDatabase = collect_unrecognized(parsed_database.options, po::exclude_positional);
1264
1265 // ------------------------ (16) -------------------------
1266#ifdef DEBUG
1267 cout << "--16--" << endl;
1268#endif
1269
1270 CreateWildcardOptions();
1271
1272 // ------------------------ (17) -------------------------
1273#ifdef DEBUG
1274 cout << "--17--" << endl;
1275#endif
1276
1277 if (result.count("print-options"))
1278 PrintOptions();
1279
1280 if (result.count("print-wildcards"))
1281 PrintWildcardOptions();
1282
1283 if (result.count("print-unknown"))
1284 PrintUnknown();
1285
1286#ifdef DEBUG
1287 cout << "------" << endl;
1288#endif
1289
1290 return fVariables;
1291}
1292
1293const po::variables_map &Configuration::ParseFile(const string &fname, const bool &checkf)
1294{
1295 // -------------------------------------------------------
1296 po::options_description opt_configfile;
1297
1298 for (int i=0; i<2; i++)
1299 opt_configfile.add(fOptionsConfigfile[i]);
1300
1301 // -------------------------------------------------------
1302
1303 ifstream file(fname.c_str());
1304 // ===> FIXME: Proper handling of missing file or wrong file name
1305 const po::parsed_options parsed_file =
1306 po::parse_config_file<char>(file, opt_configfile, !checkf);
1307
1308 // -------------------------------------------------------
1309
1310 po::variables_map result;
1311 po::store(parsed_file, result);
1312 po::notify(result);
1313
1314 fVariables = result;
1315
1316 // -------------------------------------------------------
1317
1318 const vector<string> unknown = collect_unrecognized(parsed_file.options, po::exclude_positional);
1319
1320 fUnknownConfigfile.clear();
1321 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown.begin(), unknown.end());
1322
1323 // -------------------------------------------------------
1324
1325 CreateWildcardOptions();
1326
1327 // -------------------------------------------------------
1328
1329 return fVariables;
1330}
1331
1332bool Configuration::DoParse(int argc, const char **argv, const std::function<void()> &PrintHelp)
1333{
1334 try
1335 {
1336 Parse(argc, argv, PrintHelp);
1337 }
1338#if BOOST_VERSION > 104100
1339 catch (const po::multiple_occurrences &e)
1340 {
1341 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1342 return false;
1343 }
1344#endif
1345 catch (const exception& e)
1346 {
1347 cerr << "Program options invalid due to: " << e.what() << endl;
1348 return false;
1349 }
1350
1351 return !HasVersion() && !HasPrint() && !HasHelp();
1352}
1353
1354bool Configuration::ReadFile(const string &fname, const bool &checkf)
1355{
1356 try
1357 {
1358 ParseFile(fname, checkf);
1359 }
1360#if BOOST_VERSION > 104100
1361 catch (const po::multiple_occurrences &e)
1362 {
1363 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1364 return false;
1365 }
1366#endif
1367 catch (const exception& e)
1368 {
1369 cerr << "Program options invalid due to: " << e.what() << endl;
1370 return false;
1371 }
1372
1373 return true;
1374}
1375
1376// --------------------------------------------------------------------------
1377//
1378//! Create a list of all options which were registered using wildcards
1379//!
1380void Configuration::CreateWildcardOptions()
1381{
1382 po::options_description opts;
1383
1384 for (int i=0; i<2; i++)
1385 {
1386 opts.add(fOptionsCommandline[i]);
1387 opts.add(fOptionsConfigfile[i]);
1388 opts.add(fOptionsEnvironment[i]);
1389 opts.add(fOptionsDatabase[i]);
1390 }
1391
1392 fWildcardOptions.clear();
1393
1394 typedef map<string,po::variable_value> Vars;
1395 typedef vector<boost::shared_ptr<po::option_description>> Descs;
1396
1397 const Descs &desc = opts.options();
1398
1399 for (Vars::const_iterator io=fVariables.begin(); io!=fVariables.end(); io++)
1400 {
1401 for (Descs::const_iterator id=desc.begin(); id!=desc.end(); id++)
1402#if BOOST_VERSION > 104100
1403 if ((*id)->match(io->first, false, false, false)==po::option_description::approximate_match)
1404#else
1405 if ((*id)->match(io->first, false)==po::option_description::approximate_match)
1406#endif
1407 fWildcardOptions[io->first] = (*id)->long_name();
1408 }
1409}
1410
1411// --------------------------------------------------------------------------
1412//
1413//! Print a list of all options which were registered using wildcards and
1414//! have not be registered subsequently by access.
1415//!
1416void Configuration::PrintWildcardOptions() const
1417{
1418 cout << "Options registered with wildcards and not yet accessed:" << endl;
1419
1420 size_t max = 0;
1421 for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1422 if (it->second.length()>max)
1423 max = it->second.length();
1424
1425 cout.setf(ios_base::left);
1426 for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1427 cout << setw(max+1) << it->second << " : " << it->first <<endl;
1428}
1429
1430const vector<string> Configuration::GetWildcardOptions(const std::string &opt) const
1431{
1432 vector<string> rc;
1433
1434 for (auto it=fWildcardOptions.begin(); it!=fWildcardOptions.end(); it++)
1435 {
1436 if (it->second == opt)
1437 rc.push_back(it->first);
1438 }
1439
1440 return rc;
1441}
1442
1443// --------------------------------------------------------------------------
1444//
1445//! Removes /.libs/lt- from a path or just lt- from the filename.
1446//!
1447//! @param src
1448//! input path with filename
1449//! @returns
1450//! path cleaned from libtool extensions
1451//!
1452string Configuration::UnLibToolize(const string &src) const
1453{
1454 const boost::filesystem::path path(src);
1455
1456 string pname = path.parent_path().string();
1457#if BOOST_VERSION < 104600
1458 string fname = path.filename();
1459#else
1460 string fname = path.filename().string();
1461#endif
1462
1463 // If the filename starts with "lt-" remove it from the name
1464 if (fname.substr(0, 3)=="lt-")
1465 fname = fname.substr(3);
1466
1467 string pwd;
1468 // If no directory is contained determine the current directory
1469 if (pname.empty())
1470 pname = boost::filesystem::current_path().string();
1471
1472 // If the directory is relative and just ".libs" forget about it
1473 if (pname==".libs")
1474 return fname;
1475
1476
1477 // Check if the directory is long enough to contain "/.libs"
1478 if (pname.length()>=6)
1479 {
1480 // If the directory ends with "/.libs", remove it
1481 const size_t pos = pname.length()-6;
1482 if (pname.substr(pos)=="/.libs")
1483 pname = pname.substr(0, pos);
1484 }
1485
1486 // If the path is the local path do not return the path-name
1487 if (pname==boost::filesystem::current_path().string())
1488 return fname;
1489
1490 return pname+'/'+fname;
1491}
1492
1493// --------------------------------------------------------------------------
1494//
1495//! Print version information about the program and package.
1496//!
1497//! The program name is taken from fName. If a leading "lt-" is found,
1498//! it is removed. This is useful if the program was build and run
1499//! using libtool.
1500//!
1501//! The package name is taken from the define PACKAGE_STRING. If it is
1502//! not defined (like automatically done by autoconf) no package information
1503//! is printed. The same is true for PACKAGE_URL and PACKAGE_BUGREPORT.
1504//!
1505//! From help2man:
1506//!
1507//! The first line of the --version information is assumed to be in one
1508//! of the following formats:
1509//!
1510//! \verbatim
1511//! - <version>
1512//! - <program> <version>
1513//! - {GNU,Free} <program> <version>
1514//! - <program> ({GNU,Free} <package>) <version>
1515//! - <program> - {GNU,Free} <package> <version>
1516//! \endverbatim
1517//!
1518//! and separated from any copyright/author details by a blank line.
1519//!
1520//! Handle multi-line bug reporting sections of the form:
1521//!
1522//! \verbatim
1523//! - Report <program> bugs to <addr>
1524//! - GNU <package> home page: <url>
1525//! - ...
1526//! \endverbatim
1527//!
1528//! @param name
1529//! name of the program (usually argv[0]).
1530//!
1531void Configuration::PrintVersion() const
1532{
1533#ifndef PACKAGE_STRING
1534#define PACKAGE_STRING ""
1535#endif
1536
1537#ifndef PACKAGE_URL
1538#define PACKAGE_URL ""
1539#endif
1540
1541#ifndef PACKAGE_BUGREPORT
1542#define PACKAGE_BUGREPORT ""
1543#endif
1544
1545 if (fPrintVersion)
1546 {
1547 fPrintVersion(fName);
1548 return;
1549 }
1550
1551#if BOOST_VERSION < 104600
1552 const std::string n = boost::filesystem::path(fName).filename();
1553#else
1554 const std::string n = boost::filesystem::path(fName).filename().string();
1555#endif
1556
1557 const string name = PACKAGE_STRING;
1558 const string bugs = PACKAGE_BUGREPORT;
1559 const string url = PACKAGE_URL;
1560
1561 cout << n;
1562 if (!name.empty())
1563 cout << " - " << name;
1564 cout <<
1565 "\n\n"
1566 "Written by Thomas Bretz et al.\n"
1567 "\n";
1568 if (!bugs.empty())
1569 cout << "Report bugs to <" << bugs << ">\n";
1570 if (!url.empty())
1571 cout << "Home page: " << url << "\n";
1572 cout <<
1573 "\n"
1574 "Copyright (C) 2011 by the FACT Collaboration.\n"
1575 "This is free software; see the source for copying conditions.\n"
1576 << std::endl;
1577}
1578
1579// --------------------------------------------------------------------------
1580//
1581//! Splits a given argument of the form something/somethingelse into its
1582//! two parts something and somethingelse and stores it in the pair of
1583//! Configuration::Map.
1584//!
1585std::istream &operator>>(std::istream &in, Configuration::Map &m)
1586{
1587 const istreambuf_iterator<char> eos;
1588 string txt(istreambuf_iterator<char>(in), eos);
1589
1590 const boost::regex expr("((.*)[^\\\\])/(.*)");
1591 boost::smatch match;
1592 if (!boost::regex_match(txt, match, expr))
1593 throw runtime_error("Could not evaluate map argument: "+txt);
1594
1595 m.first = match[1].str();
1596 m.second = match[3].str();
1597
1598 return in;
1599}
Note: See TracBrowser for help on using the repository browser.