QwAnalysis
QwOptions.cc
Go to the documentation of this file.
1 /*!
2  * \file QwOptions.cc
3  * \brief An options class which parses command line, config file and environment
4  *
5  * \author Wouter Deconinck
6  * \date 2009-12-01
7  */
8 
9 #if __STDC_VERSION__ < 199901L
10 # if __GNUC__ >= 2
11 # define __func__ __FUNCTION__
12 # else
13 # define __func__ "<unknown>"
14 # endif
15 #endif
16 
17 
18 #include "QwOptions.h"
19 
20 // System headers
21 #include <iostream>
22 #include <fstream>
23 #include <cstdlib>
24 #include <TROOT.h>
25 
26 // Globally defined instance of the options object
28 
29 // Qweak headers
30 #include "QwLog.h"
31 #include "QwParameterFile.h"
32 #include "QwSVNVersion.h"
33 
34 // Qweak objects with default options
35 #include "QwSubsystemArray.h"
36 #include "QwEventBuffer.h"
37 #include "QwEPICSEvent.h"
38 #include "QwDatabase.h"
39 #include "QwRootFile.h"
40 #include "QwHistogramHelper.h"
41 
42 // Initialize the static command line arguments to zero
43 int QwOptions::fArgc = 0;
44 char** QwOptions::fArgv = 0;
45 
46 /**
47  * The default constructor sets up the options description object with some
48  * options that should always be there. The other options can be setup
49  * wherever this object is accessible.
50  */
52  : fParsed(false)
53 {
54  // No default config files
55  fConfigFiles.clear();
56 
57  // Declare the default options
58  AddDefaultOptions()("usage", "print this help message");
59  AddDefaultOptions()("help,h", "print this help message");
60  AddDefaultOptions()("version,V", "print the version string");
61  AddDefaultOptions()("config,c", po::value<std::string>(), "read ONLY this config file\n(will override default config files)");
62  AddDefaultOptions()("add-config,a", po::value<std::vector<std::string> >(), "read ALSO this config file\n(will keep the default config files)");
63 }
64 
65 /**
66  * Define standard options on the specified options object
67  * @param options Options object
68  */
70 {
71  // Define logging options (Note: only QwLog takes a pointer argument!!!)
72  QwLog::DefineOptions(&options);
73 
74  // Define execution options
76  // Define database options
78  // Define ROOT file options
80  // Define EPICS event options
82  // Define subsystem array options
84  // Define histogram helper options
86 }
87 
88 /**
89  * Destructor where we clean up locally allocated memory
90  */
92 {
93  // Clean up the copy of the command line arguments
94  // Note: only the array of arguments is allocated, the arguments themselves
95  // are still owned by main.
96  if (fArgv)
97  delete[] fArgv;
98 
99  // Delete the option blocks
100  for (size_t i = 0; i < fOptionBlock.size(); i++)
101  delete fOptionBlock.at(i);
102  fOptionBlock.clear();
103 }
104 
105 /**
106  * Make a local copy of the command line arguments so they are available
107  * for later parsing.
108  * @param argc Number of arguments
109  * @param argv[] Array of arguments
110  * @param default_config_file Flag to enable default config file named by executable
111  */
112 void QwOptions::SetCommandLine(int argc, char* argv[], bool default_config_file)
113 {
114  // Copy command line options
115  fArgc = argc;
116  if (fArgv) delete[] fArgv;
117  fArgv = new char*[fArgc];
118  QwDebug << "Arguments:";
119  for (int i = 0; i < argc; i++) {
120  fArgv[i] = argv[i];
121  QwDebug << " " << fArgv[i];
122  }
123  QwDebug << QwLog::endl;
124 
125  fParsed = false;
126 
127  // Add default config file based on file name
128  if (fArgc > 0 && default_config_file) {
129  std::string path = fArgv[0];
130  QwDebug << "Invocation name: " << path << QwLog::endl;
131  // Find file name from full path
132  size_t pos = path.find_last_of('/');
133  if (pos != std::string::npos)
134  // Called with path
135  AddConfigFile(path.substr(pos+1) + ".conf");
136  else
137  // Called without path
138  AddConfigFile(path + ".conf");
139  }
140 }
141 
142 
143 
144 /**
145  * Combine the options of the various option descriptions in one object for
146  * parsing at once. This avoids having to try/catch every single option
147  * description
148  */
149 po::options_description* QwOptions::CombineOptions()
150 {
151  // The options can be grouped by defining a vector fOptions of
152  // options_description objects. Each entry can have a name and
153  // will show up as a separate section in the usage information.
154  po::options_description* options = new po::options_description("options");
155  for (size_t i = 0; i < fOptionBlockName.size(); i++) {
156  // Right now every parser gets access to all options
157  options->add(*fOptionBlock.at(i));
158  }
159  return options;
160 }
161 
162 /**
163  * Parse the command line arguments for options and warn when encountering
164  * an unknown option, then notify the variables map. Print usage instructions
165  * when no options are given, or when explicitly asked for.
166  */
168 {
169 #if BOOST_VERSION >= 103300
170  // Boost versions starting with 1.33.00 allow unrecognized options to be
171  // passed through the parser.
172  try {
173  po::options_description* command_line_options = CombineOptions();
174  po::store(po::command_line_parser(fArgc, fArgv).options(*command_line_options).allow_unregistered().run(), fVariablesMap);
175  delete command_line_options;
176  } catch (std::exception const& e) {
177  QwWarning << e.what() << " while parsing command line arguments" << QwLog::endl;
178  exit(10);
179  }
180 #endif
181 
182 #if BOOST_VERSION < 103300
183  // Boost versions before 1.33.00 do not allow unrecognized options to be
184  // passed through the parser.
185  try {
186  // Boost versions before 1.33.00 do not recognize "allow_unregistered".
187  po::options_description* command_line_options = CombineOptions();
188  po::store(po::command_line_parser(fArgc, fArgv).options(*command_line_options).run(), fVariablesMap);
189  delete command_line_options;
190  } catch (std::exception const& e) {
191  QwWarning << e.what() << " while parsing command line arguments" << QwLog::endl;
192  QwWarning << "All command line arguments may have been ignored!" << QwLog::endl;
193  exit(10);
194  }
195 #endif
196 
197  // Notify of new options
198  po::notify(fVariablesMap);
199 
200  // If option help/usage, print help text
201  if (fVariablesMap.count("help") || fVariablesMap.count("usage")) {
202  Usage();
203  exit(0);
204  }
205 
206  // If option version, print version string
207  if (fVariablesMap.count("version")) {
208  Version();
209  exit(0);
210  }
211 
212  // If a configuration file is specified, load it.
213  if (fVariablesMap.count("config") > 0) {
214  QwWarning << "Overriding the default configuration files with "
215  << "user-defined configuration file "
216  << fVariablesMap["config"].as<std::string>() << QwLog::endl;
217  SetConfigFile(fVariablesMap["config"].as<std::string>());
218  }
219  // If a configuration file is specified, load it.
220  if (fVariablesMap.count("add-config") > 0) {
221  QwWarning << "Adding user-defined configuration file " << QwLog::endl;
222  AddConfigFile(fVariablesMap["add-config"].as<std::vector<std::string> >());
223  }
224 }
225 
226 /**
227  * Parse the environment variables for options and notify the variables map.
228  */
230 {
231  try {
232  po::options_description* environment_options = CombineOptions();
233  po::store(po::parse_environment(*environment_options, "Qw"), fVariablesMap);
234  delete environment_options;
235  } catch (std::exception const& e) {
236  QwWarning << e.what() << " while parsing environment variables" << QwLog::endl;
237  exit(10);
238  }
239  // Notify of new options
240  po::notify(fVariablesMap);
241 }
242 
243 /**
244  * Parse the configuration file for options and warn when encountering
245  * an unknown option, then notify the variables map.
246  */
248 {
249  for (size_t i = 0; i < fConfigFiles.size(); i++) {
250  QwParameterFile configfile(fConfigFiles.at(i).c_str());
251  std::stringstream configstream;
252  configstream << configfile.rdbuf();
253 
254  try {
255 #if BOOST_VERSION >= 103500
256  // Boost version after 1.35 have bool allow_unregistered = false in
257  // their signature. This allows for unknown options in the config file.
258  po::options_description* config_file_options = CombineOptions();
259  po::store(po::parse_config_file(configstream, *config_file_options, true),
260  fVariablesMap);
261  delete config_file_options;
262 #else
263  // Boost versions before 1.35 cannot handle files with unregistered
264  // options.
265  po::options_description* config_file_options = CombineOptions();
266  po::store(po::parse_config_file(configstream, *config_file_options),
267  fVariablesMap);
268  delete config_file_options;
269 #endif
270  } catch (std::exception const& e) {
271  QwWarning << e.what() << " while parsing configuration file "
272  << fConfigFiles.at(i) << QwLog::endl;
273 #if BOOST_VERSION < 103500
274  QwWarning << "The entire configuration file was ignored!" << QwLog::endl;
275 #endif
276  exit(10);
277  }
278  // Notify of new options
279  po::notify(fVariablesMap);
280  }
281 }
282 
283 
284 
285 /**
286  * Print usage information
287  */
289 {
291  QwMessage << "Welcome to the Qweak analyzer code." << QwLog::endl;
293  for (size_t i = 0; i < fOptionBlock.size(); i++)
294  QwMessage << *(fOptionBlock.at(i)) << QwLog::endl;
295 }
296 
297 
298 /**
299  * Print version string
300  */
302 {
303  TString root_version = gROOT->GetVersion();
304  root_version += ", Date : ";
305  root_version += gROOT->GetVersionDate();
306 #if ROOT_VERSION_CODE < ROOT_VERSION(6,0,0)
307  root_version += ", SVN : ";
308  root_version += gROOT->GetSvnRevision();
309  root_version += " ";
310  root_version += gROOT->GetSvnBranch();
311 #else // ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0)
312  root_version += ", GIT : ";
313  root_version += gROOT->GetGitCommit();
314  root_version += " ";
315  root_version += gROOT->GetGitBranch();
316 #endif
317 
318  QwMessage << "\n Qweak Analysis Framework : " << fArgv[0] << QwLog::endl;
319  QwMessage << " * Revision: " << QWANA_SVN_REVISION << QwLog::endl;
320  QwMessage << " * URL: " << QWANA_SVN_URL << QwLog::endl;
321  QwMessage << " * Last Changed Rev: " << QWANA_SVN_LASTCHANGEDREVISION << QwLog::endl;
322  QwMessage << " * ROOT " << root_version << QwLog::endl;
323 }
324 
325 
326 /**
327  * Get a pair of integers specified as a colon-separated range
328  * This function uses the utility function QwParameterFile::ParseIntRange.
329  * @param key Option key
330  * @return Pair of integers
331  */
332 std::pair<int,int> QwOptions::GetIntValuePair(const std::string& key)
333 {
334  std::pair<int, int> mypair;
335  mypair.first = 0;
336  mypair.second = 0;
337 
338  if (fParsed == false) Parse();
339  if (fVariablesMap.count(key)) {
340  std::string range = fVariablesMap[key].as<std::string>();
341  mypair = QwParameterFile::ParseIntRange(":",range);
342  }
343 
344  return mypair;
345 }
#define QwMessage
Predefined log drain for regular messages.
Definition: QwLog.h:50
void ParseCommandLine()
Parse the command line arguments.
Definition: QwOptions.cc:167
std::vector< po::options_description * > fOptionBlock
Definition: QwOptions.h:316
#define QWANA_SVN_REVISION
std::streambuf * rdbuf() const
Access the streambuf pointer in the same way as on a std::ifstream.
std::vector< std::string > fOptionBlockName
Definition: QwOptions.h:317
An options class.
Definition: QwOptions.h:133
static void DefineOptions(QwOptions &options)
Define the configuration options.
po::options_description_easy_init AddDefaultOptions()
Add a default option.
Definition: QwOptions.h:159
void ParseConfigFile()
Parse the configuration file.
Definition: QwOptions.cc:247
QwOptions()
Default constructor.
Definition: QwOptions.cc:51
A class for handling connections to the Qweak database.
virtual ~QwOptions()
Default destructor.
Definition: QwOptions.cc:91
static const double e
Definition: QwUnits.h:91
QwOptions gQwOptions
Definition: QwOptions.cc:27
#define QWANA_SVN_LASTCHANGEDREVISION
static char ** fArgv
Definition: QwOptions.h:310
std::vector< std::string > fConfigFiles
Configuration file.
Definition: QwOptions.h:301
void ParseEnvironment()
Parse the environment variables.
Definition: QwOptions.cc:229
bool fParsed
Definition: QwOptions.h:322
void Usage()
Print usage information.
Definition: QwOptions.cc:288
std::pair< int, int > GetIntValuePair(const std::string &key)
Get a pair of integer values.
Definition: QwOptions.cc:332
void SetConfigFile(const std::string &configfile)
Set a configuration file.
Definition: QwOptions.h:192
#define QwDebug
Predefined log drain for debugging output.
Definition: QwLog.h:60
A logfile class, based on an identical class in the Hermes analyzer.
void Version()
Print version string.
Definition: QwOptions.cc:301
void AddConfigFile(const std::string &configfile)
Add a configuration file.
Definition: QwOptions.h:199
static void DefineOptions(QwOptions *options)
Define available class options for QwOptions.
Definition: QwLog.cc:73
void Parse(bool force=false)
Parse all sources of options.
Definition: QwOptions.h:222
static void DefineOptions(QwOptions &options)
Define the configuration options.
Definition: QwEPICSEvent.cc:69
static void DefineOptions(QwOptions &options)
po::options_description * CombineOptions()
Combine the various option description in one.
Definition: QwOptions.cc:149
static std::pair< int, int > ParseIntRange(const std::string &separatorchars, const std::string &range)
Parse a range of integers as #:# where either can be missing.
static void DefineOptions(QwOptions &options)
Define configuration options for global array.
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
An options class which parses command line, config file and environment.
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
#define QWANA_SVN_URL
static void DefineOptions(QwOptions &options)
Defines available class options for QwOptions.
Definition: QwDatabase.cc:209
static void DefineOptions(QwOptions &options)
Define the options.
Definition: QwOptions.cc:69
static int fArgc
Command line arguments.
Definition: QwOptions.h:309
po::variables_map fVariablesMap
Definition: QwOptions.h:320
static void DefineOptions(QwOptions &options)
Define the configuration options.
Definition: QwRootFile.cc:169
void SetCommandLine(int argc, char *argv[], bool default_config_file=true)
Set the command line arguments.
Definition: QwOptions.cc:112