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

Last change on this file since 10211 was 10198, checked in by tbretz, 14 years ago
Some minor updates to the comments
File size: 32.3 KB
Line 
1// **************************************************************************
2/** @class Configuration
3
4@brief Commandline parsing, resource file parsing and database access
5
6
7@section User For the user
8
9The Configuration class will process the following steps:
10
11Check the command-line for <B> --default=default.rc </B> (If no configuration
12filename is given on the command-line use \e program_name.rc instead. (Note
13that the name is retrieved from \b argv[0] and might change if you start
14the program through a symbolic link with a different name)
15
16Read the "<B>database=user:password@database:port/database</B>" entry from the file.
17(For details about the syntax see Configuration::parse_database)
18The retrieved entry can be overwritten by
19"<B>--database=user:passwd@server:port/database</B>" from the command line. If
20neither option is given no configuration data will be read from the
21database. To suppress any database access use \b --no-database.
22
23Check the command-line for <B> -C priority.rc </B>
24
25The configuration data is now evaluated from the following sources in
26the following order. Note that options from earlier source have
27priority.
28
29 - (1) Commandline options
30 - (2) Options from the high 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) Environment variables
34
35Which options are accepted is defined by the program. To get a list
36of all command-line option use \b --help. This also lists all other
37available options to list for exmaple the options available in the
38configuration files or from the databse. In addition some default options
39are available which allow to debug parsing of the options, by either printing
40the options retrieval or after parsing.
41
42Options in the configuration files must be given in the form
43
44 - key = value
45
46which is equivalent to the command-line option <B>--key=value</B>.
47
48If there are sections in the configuration file like
49
50\code
51
52 [section1]
53 key = value
54
55\endcode
56
57the key is transformed into <B>section1.key</B> (which would be equivalent
58to <B>--section1.key</B>)
59
60@attention
61In principle it is possible that an exception is thrown before options
62like \b --help are properly parsed and evaluated. In this case it is
63necessary to first resolve the problem. Usually, this mean that there
64is a design flaw in the program rather than a mistake of usage.
65
66For more details on the order in which configuration is read,
67check Configuration::Parse. For more details on the parsing itself
68see the documentation of boost::program_options.
69
70
71
72
73@section API For the programmer
74
75The Configuration class heavily uses the
76<A HREF="http://www.boost.org"><B>C++ boost library</B></A>
77and makes heavy use of the
78<A HREF="http://www.boost.org/doc/libs/release/doc/html/program_options.html">
79<B>boost::program_options</B></A>
80
81The databse access is based on the
82<A HREF="http://tangentsoft.net/mysql++/"><B>MySQL++ library</B></A>.
83
84The basic idea is to have an easy to use, but powerfull setup. The setup on
85all options is based on a special syntax of options_description. Here is an
86example:
87
88\code
89
90 int opt = 0;
91
92 po::options_description config("Section");
93 config.add_options()
94 ("option1", po_string(), "This is option1")
95 ("option2", po_int(22), "This is option2")
96 ("option3,o", po_double()->required(), "This option is mandatory")
97 ("option4", po_int(&opt), "This is option 4")
98 ("option5", po_strings(), "A list of strings")
99 ("option6", po_strings(), "A list of strings")
100 ("option7", po_strings(), "A list of strings")
101 ;
102
103\endcode
104
105This will setup, e.g., the commandline option '<B>--option1 arg</B>' (which
106is identical to '<B>--option1=arg</B>'. Option 3 can also be expressed
107in a short form as '<B>-o arg</B>' or '<B>-o=arg</B>'. Option 2 defaults
108to 22 if no explicit value is given. Option 3 is mandatory and an exceptionb
109is thrown if not specified. Option 4 will, apart from the usual access to the
110option values, also store its value in the variable opt.
111
112The used functions po_*() are defined in configuration.h and are abbreviations.
113Generally speaking also other variable types are possible.
114
115If the options are displayed, e.g. by \b --help the corresponding section will
116by titled \e Section, also untitled sections are possible.
117
118If an option can be given more than once then a std::vector<type> can be used.
119Abbreviations po_ints(), po_doubles() and po_strings() are available.
120
121In addition to options introduced by a minus, so calles positional options
122can be given on the command line. To describe these options use
123
124\code
125
126 po::positional_options_description p;
127 p.add("option5", 2); // The first 2 positional options
128 p.add("option6", 3); // The next three positional options
129 // p.add("option7", -1); // All others, if wanted
130
131\endcode
132
133This assigns option-keys to the positional options (arguments) in the
134command-line. Note that the validity of the given commandline is checked.
135Hence, this way of defining the options makes sense.
136
137As needed options_descriptions can be grouped together
138
139\code
140
141 po::options_description config1("Section1");
142 po::options_description config2("Section2");
143
144 po::options_description configall;
145 configall.add(config1);
146 configall.add(config2);
147
148\endcode
149
150The member functions of Configurations allow to define for which option
151source these options are valid. The member functions are:
152
153\code
154
155 Configuration conf;
156
157 conf.AddOptionsCommandline(configall, true);
158 conf.AddOptionsConfigfile(config1, true);
159 conf.AddOptionsDatabase(config2, true);
160
161 // To enable the mapping of the position arguments call this
162 conf.SetArgumentPositions(p);
163
164\endcode
165
166If the second option is false, the options will not be displayed in any
167\b --help directive, but are available to the user. Each of the functions
168can be called more than once.
169
170A special case are the options from environment variables. Since you might
171want to use the same option-key for the command-line and the environment
172a mapping is needed (e.g. from \b PATH to \b --path). This mapping
173can be implemented by a mapping function and be initialized like this:
174
175\code
176
177 const string name_mapper(const string &str)
178 {
179 return str=="PATH" ? "path" : "";
180 }
181
182 conf.SetNameMapper(name_mapper);
183
184\endcode
185
186Assuming all the above is done in a function calles SetupConfiguration(),
187a simple program to demonstrate the power of the class could look like this:
188
189\code
190
191 int main(int argc, char **argv)
192 {
193 int opt;
194
195 Configuration conf(argv[0]);
196 SetupConfiguration(conf, opt);
197
198 po::variables_map vm;
199 try
200 {
201 vm = conf.Parse(argc, argv);
202 }
203 catch (std::exception &e)
204 {
205 po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
206 if (MO)
207 cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
208 else
209 cout << "Error: " << e.what() << endl;
210 cout << endl;
211
212 return -1;
213 }
214
215 cout << "Opt1: " << conf.GetString("option1") << endl;
216 cout << "Opt2: " << conf.GetInt("option2") << endl;
217 cout << "Opt3: " << conf.GetDouble("option3") << endl;
218 cout << "Opt4: " << opt << endl;
219
220 return 0;
221 }
222
223\endcode
224
225Another possibility to access the result is the direct approach, for example:
226
227\code
228
229 vector<int> i = vm["option2"].as<int>();
230 vector<string> vec = vm["option6"].as<vector<string>>();
231
232\endcode
233
234Note that accessing an option which was not given will throw an exception.
235Therefor its availability should first be checked in one of the following
236ways:
237
238\code
239
240 bool has_option1 = vm.count("option1");
241 bool has_option2 = conf.Has("option2");
242
243\endcode
244
245@section Examples
246
247 - An example can be found in \ref argv.cc
248
249@todo Maybe we should remove the necessity to propagate argv[0] in the constructor?
250
251*/
252// **************************************************************************
253#include "Configuration.h"
254
255#include <iostream>
256
257#include <boost/regex.hpp>
258#include <boost/filesystem.hpp>
259#include <boost/program_options.hpp>
260
261#include <mysql++/mysql++.h>
262
263using namespace std;
264
265namespace style = boost::program_options::command_line_style;
266
267// --------------------------------------------------------------------------
268//
269//! The purpose of this function is basically to connect to the database,
270//! and retrieve all the options entries from the 'Configuration' table.
271//!
272//! @param database
273//! The URL of the database from which the configuration data is
274//! retrieved. It should be given in the form
275//! \li [user[:password]@]server.com[:port][/database]
276//!
277//! with
278//! - user: user name (default is the current user)
279//! - password: necessary if required by the database rights
280//! - server: the URL of the server (can be 'localhost')
281//! - port: the port to which to connect (usually obsolete)
282//! - database: The name of the database containing the table
283//!
284//! @param desc
285//! A reference to the object with the description of the options
286//! which should be retrieved.
287//!
288//! @param allow_unregistered
289//! If this is true also unregistered, i.e. options unknown to desc,
290//! are returned. Otherwise an exception is thrown if such an option
291//! was retrieved.
292//!
293//! @return
294//! Return an object of type basic_parsed_options containing all
295//! the entries retrieved from the database. Options not found in
296//! desc are flagged as unregistered.
297//!
298//! @throws
299//! Two types of exceptions are thrown
300//! - It thows an unnamed exception if the options could not be
301//! retrieved properly from the databse.
302//! - If an option is not registered within the given descriptions
303//! and \b allow_unregistered is \b false, an exception of type
304//! \b po::unknown_option is thrown.
305//!
306//! @todo
307//! - The exceptions handling should be improved.
308//! - The final database layout is missing in the description
309//! - Shell we allow options to be given more than once?
310//
311po::basic_parsed_options<char>
312 Configuration::parse_database(const string &database, const po::options_description& desc, bool allow_unregistered)
313{
314 //static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))?");
315 static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))");
316 // 2: user
317 // 4: pass
318 // 5: server
319 // 7: port
320 // 9: db
321
322 boost::smatch what;
323 if (!boost::regex_match(database, what, expr, boost::match_extra))
324 {
325 cout << "Couldn't parse '" << database << "'." << endl;
326 throw;
327 }
328
329 if (what.size()!=10)
330 {
331 cout << "Error parsing '" << database << "'." << endl;
332 throw;
333 }
334
335 const string user = what[2];
336 const string passwd = what[4];
337 const string server = what[5];
338 const string db = what[9];
339 const int port = atoi(string(what[7]).c_str());
340
341 cout << "Connecting to '";
342 if (!user.empty())
343 cout << user << "@";
344 cout << server;
345 if (port)
346 cout << ":" << port;
347 if (!db.empty())
348 cout << "/" << db;
349 cout << "'" << endl;
350
351 mysqlpp::Connection conn(db.c_str(), server.c_str(), user.c_str(), passwd.c_str(), port);
352 if (!conn.connected())
353 {
354 cout << "MySQL connection error: " << conn.error() << endl;
355 throw;
356 }
357
358 // Retrieve a subset of the sample stock table set up by resetdb
359 // and display it.
360 // FIXME: What about a prefix?
361 mysqlpp::Query query = conn.query("select `Key`, Value from Configuration");
362
363 mysqlpp::StoreQueryResult res = query.store();
364 if (!res)
365 {
366 cout << "MySQL query failed: " << query.error() << endl;
367 throw;
368 }
369
370 set<string> allowed_options;
371
372 const vector<boost::shared_ptr<po::option_description>> &options = desc.options();
373 for (unsigned i=0; i<options.size(); ++i)
374 {
375 const po::option_description &d = *options[i];
376 if (d.long_name().empty())
377 boost::throw_exception(po::error("long name required for database"));
378
379 allowed_options.insert(d.long_name());
380 }
381
382 po::parsed_options result(&desc);
383
384 for (vector<mysqlpp::Row>::iterator v=res.begin(); v<res.end(); v++)
385 {
386 const string key = (*v)[0].c_str();
387 if (key.empty()) // key == > Throw exception
388 continue;
389
390 // Check if we are allowed to accept unregistered options,
391 // i.e. options which are not in options_description &desc.
392 const bool unregistered = allowed_options.find(key)==allowed_options.end();
393 if (unregistered && allow_unregistered)
394 boost::throw_exception(po::unknown_option(key));
395
396 // Create a key/value-pair and store whether it is a
397 // registered option of not
398 po::option n;
399 n.string_key = key;
400 // This is now identical to file parsing. What if we want
401 // to concatenate options like on the command line?
402 n.value.clear(); // Fixme: composing?
403 n.value.push_back((*v)[1].c_str());
404 n.unregistered = unregistered;
405
406 // If any parsing will be done in the future...
407 //n.value().original_tokens.clear();
408 //n.value().original_tokens.push_back(name);
409 //n.value().original_tokens.push_back(value);
410
411 result.options.push_back(n);
412 }
413
414 cout << endl;
415
416 return result;
417}
418
419// --------------------------------------------------------------------------
420//
421//!
422//
423Configuration::Configuration(const string &prgname) : fName(prgname), fNameMapper(&NameMapper)
424{
425 po::options_description generic("Generic options");
426 generic.add_options()
427 ("help", "Print available commandline options.")
428 ("help-environment", "Print available environment variables.")
429 ("help-database", "Print available options retreived from the database.")
430 ("help-config", "Print available configuration file options.")
431 ("print-all", "Print all options as parsed from all the different sources.")
432 ("print", "Print options as parsed from the commandline.")
433 ("print-default", "Print options as parsed from default configuration file.")
434 ("print-database", "Print options as retrieved from the database.")
435 ("print-config", "Print options as parsed from the high priority configuration file.")
436 ("print-environment", "Print options as parsed from the environment.")
437 ("print-unknown", "Print unrecognized options.")
438 ("print-options", "Print options as passed to program.")
439 ("dont-check", "Do not check validity of options from files and database.")
440 ("dont-check-files", "Do not check validity of options from files.")
441 ("dont-check-database", "Do not check validity of options from database.")
442 ;
443
444 po::options_description def_config;
445 def_config.add_options()
446 ("default", var<string>(prgname+string(".rc")), "Default configuration file.")
447 ;
448
449 po::options_description config("Configuration options");
450 config.add_options()
451 ("config,C", var<string>(), "Configuration file overwriting options retrieved from the database.")
452 ("database", var<string>(), "Database link as in\n\t[user:[password]@][server][:port][/database]\nOverwrites options from the default configuration file.")
453 ("no-database", "Suppress any access to the database even if a database URL was set.")
454 ;
455
456 fOptionsCommandline[kVisible].add(generic);
457 fOptionsCommandline[kVisible].add(config);
458 fOptionsCommandline[kVisible].add(def_config);
459 fOptionsConfigfile[kVisible].add(config);
460}
461
462// --------------------------------------------------------------------------
463//
464//!
465//
466void Configuration::PrintParsed(const po::parsed_options &parsed) const
467{
468 const vector< po::basic_option<char> >& options = parsed.options;
469
470 // .description -> Pointer to opt_commandline
471 // const std::vector< shared_ptr<option_description> >& options() const;
472
473 //const std::string& key(const std::string& option) const;
474 //const std::string& long_name() const;
475 //const std::string& description() const;
476 //shared_ptr<const value_semantic> semantic() const;
477
478 int maxlen = 0;
479 for (unsigned i=0; i<options.size(); ++i)
480 {
481 const po::basic_option<char> &opt = options[i];
482
483 if (opt.value.size()>0 && opt.string_key[0]!='-')
484 Max(maxlen, opt.string_key.length());
485 }
486
487 cout.setf(ios_base::left);
488
489 // =============> Implement prining of parsed options
490 for(unsigned i=0; i<options.size(); ++i)
491 {
492 const po::basic_option<char> &opt = options[i];
493
494 if (opt.value.size()==0 && !opt.string_key[0]=='-')
495 cout << "--";
496 cout << setw(maxlen) << opt.string_key;
497 if (opt.value.size()>0)
498 cout << " = " << opt.value[0];
499
500 //for (int j=0; j<options[i].value.size(); j++)
501 // cout << "\t = " << options[i].value[j];
502
503 //cout << "/" << options[i].position_key;
504 //cout << "/" << options[i].original_tokens[0];
505 //cout << "/" << options[i].unregistered << endl;
506 if (opt.unregistered)
507 cout << " # option unknown";
508 cout << endl;
509 }
510}
511
512// --------------------------------------------------------------------------
513//
514//!
515//
516void Configuration::PrintOptions()
517{
518 cout << "Options propagated to program:" << endl;
519
520 int maxlen = 0;
521 for (map<string,po::variable_value>::iterator m=fVariables.begin();
522 m!=fVariables.end(); m++)
523 Max(maxlen, m->first.length());
524
525 cout.setf(ios_base::left);
526
527 // =============> Implement prining of options in use
528 for (map<string,po::variable_value>::iterator m=fVariables.begin();
529 m!=fVariables.end(); m++)
530 {
531 cout << setw(maxlen) << m->first << " = ";
532
533 const po::variable_value &v = m->second;
534
535 if (v.value().type()==typeid(bool))
536 cout << (v.as<bool>()?"true":"false") << " # bool";
537
538 if (v.value().type()==typeid(string))
539 cout << v.as<string>() << " # string";
540
541 if (v.value().type()==typeid(int))
542 cout << v.as<int>() << " # int";
543
544 if (v.value().type()==typeid(double))
545 cout << v.as<double>() << " # double";
546
547 if (v.value().type()==typeid(float))
548 cout << v.as<float>() << " # float";
549
550 if (v.value().type()==typeid(vector<string>))
551 {
552 vector<string> vec = v.as<vector<string>>();
553 for (vector<string>::iterator s=vec.begin(); s<vec.end(); s++)
554 cout << *s << " ";
555 cout << " # strings";
556 }
557 if (v.value().type()==typeid(vector<double>))
558 {
559 vector<double> vec = v.as<vector<double>>();
560 for (vector<double>::iterator s=vec.begin(); s<vec.end(); s++)
561 cout << *s << " ";
562 cout << " # doubles";
563 }
564
565 if (v.defaulted())
566 cout << " # default value";
567 if (v.empty())
568 cout << " # empty value";
569
570 cout << endl;
571 }
572
573 cout << endl;
574}
575
576// --------------------------------------------------------------------------
577//
578//!
579//
580void Configuration::PrintUnknown(vector<string> &vec, int steps)
581{
582 for (vector<string>::iterator v=vec.begin(); v<vec.end(); v+=steps)
583 cout << " " << *v << endl;
584 cout << endl;
585}
586
587// --------------------------------------------------------------------------
588//
589//!
590//
591void Configuration::PrintUnknown()
592{
593 if (fUnknownCommandline.size())
594 {
595 cout << "Unknown commandline options:" << endl;
596 PrintUnknown(fUnknownCommandline);
597 }
598
599 if (fUnknownConfigfile.size())
600 {
601 cout << "Unknown options in configfile:" << endl;
602 PrintUnknown(fUnknownConfigfile, 2);
603 }
604
605 if (fUnknownEnvironment.size())
606 {
607 cout << "Unknown environment variables:" << endl;
608 PrintUnknown(fUnknownEnvironment);
609 }
610
611 if (fUnknownDatabase.size())
612 {
613 cout << "Unknown database entry:" << endl;
614 PrintUnknown(fUnknownDatabase);
615 }
616}
617
618// --------------------------------------------------------------------------
619//
620//!
621//
622void Configuration::AddOptionsCommandline(const po::options_description &cl, bool visible)
623{
624 fOptionsCommandline[visible].add(cl);
625}
626
627// --------------------------------------------------------------------------
628//
629//!
630//
631void Configuration::AddOptionsConfigfile(const po::options_description &cf, bool visible)
632{
633 fOptionsConfigfile[visible].add(cf);
634}
635
636// --------------------------------------------------------------------------
637//
638//!
639//
640void Configuration::AddOptionsEnvironment(const po::options_description &env, bool visible)
641{
642 fOptionsEnvironment[visible].add(env);
643}
644
645// --------------------------------------------------------------------------
646//
647//!
648//
649void Configuration::AddOptionsDatabase(const po::options_description &db, bool visible)
650{
651 fOptionsDatabase[visible].add(db);
652}
653
654// --------------------------------------------------------------------------
655//
656//!
657//
658void Configuration::SetArgumentPositions(const po::positional_options_description &desc)
659{
660 fArgumentPositions = desc;
661}
662
663// --------------------------------------------------------------------------
664//
665//!
666//
667void Configuration::SetNameMapper(const string (*mapper)(const string&))
668{
669 fNameMapper = mapper;
670}
671
672// --------------------------------------------------------------------------
673//
674//!
675//! The idea of the Parse() memeber-function is to parse the command-line,
676//! the configuration files, the databse and the environment and return
677//! a proper combined result.
678//!
679//! In details the following actions are performed in the given order:
680//!
681//! - (0) Init local variables with the list of options described by the
682//! data members.
683//! - (1) Reset the data members fPriorityFile, fDefaultFile, fDatabase
684//! - (2) Parse the command line
685//! - (3) Check for \b --help* command-line options and performe
686//! corresponding action
687//! - (4) Check for \b --print and \b --print-all and perform corresponding
688//! action
689//! - (5) Read and parse the default configuration file, which is either
690//! given by the default name or the \b --default command-line
691//! option. The default name is compiled from the argument
692//! given to the constructor and ".rc". If the file-name is
693//! identical to the default (no command-line option given)
694//! a missing configuration file is no error. Depending on
695//! the \b --dont-check and \b --dont-check-files options,
696//! unrecognized options in the file throw an exception or not.
697//! - (6) Check for \b --print-default and \b --print-all and perform
698//! corresponding action
699//! - (7) Read and parse the priority configuration file, which must be given
700//! by the \b --config or \b -C command-line option or a
701//! corresponding entry in the default-configuration file.
702//! If an option on the command-line and the in the configuration
703//! file exists, the command-line option has priority.
704//! If none is given, no priority file is read. Depending on
705//! the \b --dont-check and \b --dont-check-files options,
706//! unrecognized options in the file throw an exception or not.
707//! - (8) Check for \b --print-config and \b --print-all and perform
708//! corresponding action
709//! - (9) Retrieve options from the database according to the
710//! options \b --database and \b --no-database. Note that
711//! options given on the command-line have highest priority.
712//! The second priority is the priority-configuration file.
713//! The options from the default configuration-file have
714//! lowest priority.
715//! - (10) Check for \b --print-database and \b --print-all and perform
716//! corresponding action
717//! - (11) Parse the environment options.
718//! - (12) Check for \b --print-environment and \b --print-all and perform
719//! corresponding action
720//! - (13) Compile the final result. The priority of the options is (in
721//! decreasing order): command-line options, options from the
722//! priority configuration file, options from the database,
723//! options from the default configuration-file and options
724//! from the environment.
725//! - (14) Finally all options which were found and flagged as unrecognized,
726//! because they are not in the user-defined list of described
727//! options, are collected and stored in the corresponding
728//! data-members.
729//! - (15) Before the function returns it check for \b --print-options
730//! and \b --print-unknown and performs the corresponding actions.
731//!
732//!
733//! @param argc,argv
734//! arguments passed to <B>main(int argc, char **argv)</B>
735//!
736//! @returns
737//! A reference to the list with the resulting options with their
738//! values.
739//!
740//! @todo
741//! - describe the exceptions
742//! - describe what happens in a more general way
743//! - print a waring when no default coonfig file is read
744//
745const po::variables_map &Configuration::Parse(int argc, char **argv)
746{
747 const po::positional_options_description &opt_positional = fArgumentPositions;
748
749 // ------------------------ (0) --------------------------
750
751 po::options_description opt_commandline;
752 po::options_description opt_configfile;
753 po::options_description opt_environment;
754 po::options_description opt_database;
755
756 for (int i=0; i<2; i++)
757 {
758 opt_commandline.add(fOptionsCommandline[i]);
759 opt_configfile.add(fOptionsConfigfile[i]);
760 opt_environment.add(fOptionsEnvironment[i]);
761 opt_database.add(fOptionsDatabase[i]);
762 }
763
764 // ------------------------ (1) --------------------------
765
766 fPriorityFile = "";
767 fDefaultFile = "";
768 fDatabase = "";
769
770 // ------------------------ (2) --------------------------
771
772 po::command_line_parser parser(argc, argv);
773 parser.options(opt_commandline);
774 parser.positional(opt_positional);
775 parser.style(style::unix_style&~style::allow_guessing);
776 //parser.allow_unregistered();
777
778 const po::parsed_options parsed_commandline = parser.run();
779
780 // ------------------------ (3) --------------------------
781
782 po::variables_map getfiles;
783 po::store(parsed_commandline, getfiles);
784
785 if (getfiles.count("help"))
786 cout << endl << fOptionsCommandline[kVisible] << endl;
787 if (getfiles.count("help-config"))
788 cout << endl << fOptionsConfigfile[kVisible] << endl;
789 if (getfiles.count("help-env"))
790 cout << endl << fOptionsEnvironment[kVisible] << endl;
791 if (getfiles.count("help-database"))
792 cout << endl << fOptionsDatabase[kVisible] << endl;
793
794 // ------------------------ (4) --------------------------
795
796 if (getfiles.count("print") || getfiles.count("print-all"))
797 {
798 cout << endl << "Parsed commandline options:" << endl;
799 PrintParsed(parsed_commandline);
800 cout << endl;
801 }
802
803 // ------------------------ (5) --------------------------
804
805 // Get default file from command line
806 if (getfiles.count("default"))
807 {
808 fDefaultFile = getfiles["default"].as<string>();
809 cout << "Reading configuration from '" << fDefaultFile << "'." << endl;
810 }
811
812 const bool checkf = !getfiles.count("dont-check-files") && !getfiles.count("dont-check");
813 const bool defaulted = getfiles.count("default") && getfiles["default"].defaulted();
814 const bool exists = boost::filesystem::exists(fDefaultFile);
815
816 const po::parsed_options parsed_defaultfile =
817 !exists && defaulted ?
818 po::parsed_options(&opt_configfile) :
819 po::parse_config_file<char>(fDefaultFile.c_str(), opt_configfile, !checkf);
820
821 // ------------------------ (6) --------------------------
822
823 if (getfiles.count("print-default") || getfiles.count("print-all"))
824 {
825 if (!exists && defaulted)
826 cout << "No configuration file by --default option specified." << endl;
827 else
828 {
829 cout << endl << "Parsed options from '" << fDefaultFile << "':" << endl;
830 PrintParsed(parsed_defaultfile);
831 cout << endl;
832 }
833 }
834
835 po::store(parsed_defaultfile, getfiles);
836
837 // ------------------------ (7) --------------------------
838
839 // Get priority from commandline(1), defaultfile(2)
840 if (getfiles.count("config"))
841 {
842 fPriorityFile = getfiles["config"].as<string>();
843 cout << "Retrieved option from '" << fPriorityFile << "'." << endl;
844 }
845
846 // cout << "PRIO : " << fPriorityFile << endl;
847
848 const po::parsed_options parsed_priorityfile =
849 fPriorityFile.empty() ? po::parsed_options(&opt_configfile) :
850 po::parse_config_file<char>(fPriorityFile.c_str(), opt_configfile, !checkf);
851
852 // ------------------------ (8) --------------------------
853
854 if (getfiles.count("print-config") || getfiles.count("print-all"))
855 {
856 if (fPriorityFile.empty())
857 cout << "No configuration file by --config option specified." << endl;
858 else
859 {
860 cout << endl << "Parsed options from '" << fPriorityFile << "':" << endl;
861 PrintParsed(parsed_priorityfile);
862 cout << endl;
863 }
864 }
865
866 // ------------------------ (9) --------------------------
867
868 po::variables_map getdatabase;
869 po::store(parsed_commandline, getdatabase);
870 po::store(parsed_priorityfile, getdatabase);
871 po::store(parsed_defaultfile, getdatabase);
872
873 // cout << "NODB : " << getdatabase.count("no-database") << endl;
874
875 if (getdatabase.count("database") && !getdatabase.count("no-database"))
876 {
877 fDatabase = getdatabase["database"].as<string>();
878 cout << "Retrieving configuration from '" << fDatabase << "'." << endl;
879 }
880
881 // cout << "DB : " << fDatabase << endl;
882 const bool checkdb = !getdatabase.count("dont-check-database") && !getdatabase.count("dont-check");
883
884 const po::parsed_options parsed_database =
885 fDatabase.empty() ? po::parsed_options(&opt_database) :
886 parse_database(fDatabase, opt_database, !checkdb);
887
888 // ------------------------ (10) -------------------------
889
890 if (getfiles.count("print-database") || getfiles.count("print-all"))
891 {
892 if (fDatabase.empty())
893 cout << "No database access requested." << endl;
894 else
895 {
896 cout << endl << "Options retrieved from '" << fDatabase << "':" << endl;
897 PrintParsed(parsed_database);
898 cout << endl;
899 }
900 }
901
902 // ------------------------ (11) -------------------------
903
904 const po::parsed_options parsed_environment = po::parse_environment(opt_environment, *fNameMapper);
905
906 // ------------------------ (12) -------------------------
907
908 if (getfiles.count("print-environment"))
909 {
910 cout << "Parsed options from environment:" << endl;
911 PrintParsed(parsed_environment);
912 cout << endl;
913 }
914
915 // ------------------------ (13) -------------------------
916
917 po::variables_map result;
918 po::store(parsed_commandline, result);
919 po::store(parsed_priorityfile, result);
920 po::store(parsed_database, result);
921 po::store(parsed_defaultfile, result);
922 po::store(parsed_environment, result);
923 po::notify(result);
924
925 fVariables = result;
926
927 // ------------------------ (14) -------------------------
928
929 const vector<string> unknown1 = collect_unrecognized(parsed_defaultfile.options, po::exclude_positional);
930 const vector<string> unknown2 = collect_unrecognized(parsed_priorityfile.options, po::exclude_positional);
931
932 fUnknownConfigfile.clear();
933 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown1.begin(), unknown1.end());
934 fUnknownConfigfile.insert(fUnknownConfigfile.end(), unknown2.begin(), unknown2.end());
935
936 fUnknownCommandline = collect_unrecognized(parsed_commandline.options, po::exclude_positional);
937 fUnknownEnvironment = collect_unrecognized(parsed_environment.options, po::exclude_positional);
938 fUnknownDatabase = collect_unrecognized(parsed_database.options, po::exclude_positional);
939
940 // ------------------------ (15) -------------------------
941
942 if (result.count("print-options"))
943 PrintOptions();
944
945 if (result.count("print-unknown"))
946 PrintUnknown();
947
948 return fVariables;
949}
Note: See TracBrowser for help on using the repository browser.