CMS 3D CMS Logo

CommandLineParser.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 #include <iostream>
3 #include <fstream>
4 #include <iomanip>
5 #include <cstdlib>
6 #include <cassert>
7 
8 #include "TString.h"
9 
12 #include "PhysicsTools/FWLite/interface/dumpSTL.icc"
13 
14 using namespace std;
15 using namespace optutl;
16 
17 const std::string CommandLineParser::kSpaces = " \t";
18 
19 CommandLineParser::CommandLineParser(const string &usage, unsigned int optionsType)
20  : m_argv0(""), m_usageString(usage), m_printOptions(true), m_optionsType(optionsType) {
22  // Integer options
23  addOption("totalSections", kInteger, "Total number of sections", 0);
24  addOption("section", kInteger, "This section (from 1..totalSections inclusive)", 0);
25  addOption("maxEvents", kInteger, "Maximum number of events to run over (0 for whole file)", 0);
26  addOption("jobID", kInteger, "jobID given by CRAB,etc. (-1 means append nothing)", -1);
27  addOption("outputEvery", kInteger, "Output something once every N events (0 for never)", 0);
28  // String options
29  addOption("outputFile", kString, "Output filename", "output.root");
30  addOption("storePrepend", kString, "Prepend location on files starting with '/store/'");
31  addOption("tag", kString, "A 'tag' to append to output file (e.g., 'v2', etc.)");
32  // Bool options
33  addOption("logName", kBool, "Print log name and exit");
34  // String vector options
35  addOption("inputFiles", kStringVector, "List of input files");
36  addOption("secondaryInputFiles", kStringVector, "List of secondary input files (a.k.a. two-file-solution");
37  addOption("orderedSecondaryFiles", kBool, "Are the secondary files ordered?", false);
38  return;
39  }
40  // If we're still here, we have a type I don't understand.
41  cerr << "CommandLineParser() Error: type '" << optionsType << "' is not understood. Aborting." << endl;
42  assert(0);
43 }
44 
45 void CommandLineParser::parseArguments(int argc, char **argv, bool returnArgs) {
46  bool callHelp = false;
47  SVec argsVec;
48  m_argv0 = argv[0];
49  m_fullArgVec.push_back(argv[0]);
50  for (int loop = 1; loop < argc; ++loop) {
51  string arg = argv[loop];
52  m_fullArgVec.push_back(arg);
53  string::size_type where = arg.find_first_of("=");
54  if (string::npos != where) {
55  if (_setVariableFromString(arg)) {
56  continue;
57  }
59  continue;
60  }
61  cerr << "Don't understand: " << arg << endl;
62  exit(0);
63  } // tag=value strings
64  else if (arg.at(0) == '-') {
65  string::size_type where = arg.find_first_not_of("-");
66  if (string::npos == where) {
67  // a poorly formed option
68  cerr << "Don't understand: " << arg << endl;
69  exit(0);
70  continue;
71  }
72  lowercaseString(arg);
73  char first = arg.at(where);
74  // Print the values
75  if ('p' == first) {
76  m_printOptions = true;
77  continue;
78  }
79  if ('n' == first) {
80  m_printOptions = false;
81  continue;
82  }
83  // Exit after printing values
84  if ('h' == first) {
85  callHelp = true;
86  continue;
87  }
88  // if we're still here, then we've got a problem.
89  cerr << "Don't understand: " << arg << endl;
90  exit(0);
91  } // -arg strings
92  if (returnArgs) {
93  argsVec.push_back(arg);
94  } else {
95  cerr << "Don't understand: " << arg << endl;
96  exit(0);
97  }
98  } // for loop
99  if (callHelp) {
100  help();
101  }
102 }
103 
105  if (m_usageString.length()) {
106  cout << m_argv0 << " - " << m_usageString << endl;
107  }
108  cout << "--help - This screen" << endl
109  << "--noPrint - Do not print out all settings" << endl
110  << "--print - Print out all settings" << endl;
112  exit(0);
113 }
114 
115 void CommandLineParser::split(SVec &retval, string line, string match, bool ignoreComments) {
116  if (ignoreComments) {
117  removeComment(line);
118  } // if ignoreComments
119  retval.clear();
120  // find the first non-space
121  string::size_type start1 = line.find_first_not_of(kSpaces);
122  // Is the first non-space character a '#'
123  char firstCh = line[start1];
124  if ('#' == firstCh) {
125  // this line is a comment
126  return;
127  }
128 
129  line += match; // get last word of line
130  string::size_type last = string::npos;
131  string::size_type current = line.find_first_of(match);
132  while (string::npos != current) {
134  if (string::npos != last) {
135  pos = last + 1;
136  } else {
137  pos = 0;
138  }
139  string part = line.substr(pos, current - last - 1);
140  // don't bother adding 0 length strings
141  if (part.length()) {
142  retval.push_back(part);
143  }
144  last = current;
145  current = line.find_first_of(match, current + 1);
146  } // while we're finding spaces
147 }
148 
150  string::size_type location = line.find("#");
151  if (string::npos != location) {
152  // we've got a comment. Strip it out
153  line = line.substr(0, location - 1);
154  } // if found
155 }
156 
158  string::size_type pos = line.find_first_not_of(kSpaces);
159  if (string::npos == pos) {
160  // we don't have anything here at all. Just quit now
161  return;
162  }
163  if (pos) {
164  // We have spaces at the beginning.
165  line = line.substr(pos);
166  }
167  pos = line.find_last_not_of(kSpaces);
168  if (pos + 1 != line.length()) {
169  // we've got spaces at the end
170  line = line.substr(0, pos + 1);
171  }
172 }
173 
174 string CommandLineParser::removeEnding(const string &input, const string &ending) {
175  string::size_type position = input.rfind(ending);
176  if (input.length() - ending.length() == position) {
177  // we've got it
178  return input.substr(0, position);
179  }
180  // If we're still here, it wasn't there
181  return input;
182 }
183 
184 void CommandLineParser::findCommand(const string &line, string &command, string &rest) {
185  command = rest = "";
186  string::size_type nonspace = line.find_first_not_of(kSpaces);
187  if (string::npos == nonspace) {
188  // we don't have anything here at all. Just quit now
189  return;
190  }
191  string::size_type space = line.find_first_of(kSpaces, nonspace);
192  if (string::npos == space) {
193  // we only have a command and nothing else
194  command = line.substr(nonspace);
195  return;
196  }
197  command = line.substr(nonspace, space - nonspace);
198  rest = line.substr(space + 1);
200 }
201 
203  cout << "------------------------------------------------------------------" << left << endl;
204  // Print the integers next
205  if (!m_integerMap.empty()) {
206  cout << endl << "Integer options:" << endl;
207  }
208  for (SIMapConstIter iter = m_integerMap.begin(); m_integerMap.end() != iter; ++iter) {
209  const string &description = m_variableDescriptionMap[iter->first];
210  cout << " " << setw(14) << iter->first << " = " << setw(14) << iter->second;
211  if (description.length()) {
212  cout << " - " << description;
213  }
214  cout << endl;
215  } // for iter
216 
217  // Print the doubles next
218  if (!m_doubleMap.empty()) {
219  cout << endl << "Double options:" << endl;
220  }
221  for (SDMapConstIter iter = m_doubleMap.begin(); m_doubleMap.end() != iter; ++iter) {
222  const string &description = m_variableDescriptionMap[iter->first];
223  cout << " " << setw(14) << iter->first << " = " << setw(14) << iter->second;
224  if (description.length()) {
225  cout << " - " << description;
226  }
227  cout << endl;
228  } // for iter
229 
230  // Print the bools first
231  if (!m_boolMap.empty()) {
232  cout << endl << "Bool options:" << endl;
233  }
234  for (SBMapConstIter iter = m_boolMap.begin(); m_boolMap.end() != iter; ++iter) {
235  const string &description = m_variableDescriptionMap[iter->first];
236  cout << " " << setw(14) << iter->first << " = " << setw(14);
237  if (iter->second) {
238  cout << "true";
239  } else {
240  cout << "false";
241  }
242  if (description.length()) {
243  cout << " - " << description;
244  }
245  cout << endl;
246  } // for iter
247 
248  // Print the strings next
249  if (!m_stringMap.empty()) {
250  cout << endl << "String options:" << endl;
251  }
252  for (SSMapConstIter iter = m_stringMap.begin(); m_stringMap.end() != iter; ++iter) {
253  const string &description = m_variableDescriptionMap[iter->first];
254  cout << " " << setw(14) << iter->first << " = ";
255  const string value = "'" + iter->second + "'";
256  cout << setw(14) << "";
257  if (description.length()) {
258  cout << " - " << description;
259  }
260  cout << endl << " " << value << endl;
261  } // for iter
262 
263  // Integer Vec
264  if (!m_integerVecMap.empty()) {
265  cout << endl << "Integer Vector options:" << endl;
266  }
267  for (SIVecMapConstIter iter = m_integerVecMap.begin(); m_integerVecMap.end() != iter; ++iter) {
268  const string &description = m_variableDescriptionMap[iter->first];
269  cout << " " << setw(14) << iter->first << " = ";
270  dumpSTL(iter->second);
271  cout << endl;
272  if (description.length()) {
273  cout << " - " << description;
274  }
275  cout << endl;
276  } // for iter
277 
278  // Double Vec
279  if (!m_doubleVecMap.empty()) {
280  cout << endl << "Double Vector options:" << endl;
281  }
282  for (SDVecMapConstIter iter = m_doubleVecMap.begin(); m_doubleVecMap.end() != iter; ++iter) {
283  const string &description = m_variableDescriptionMap[iter->first];
284  cout << " " << setw(14) << iter->first << " = ";
285  dumpSTL(iter->second);
286  cout << endl;
287  if (description.length()) {
288  cout << " - " << description;
289  }
290  cout << endl;
291  } // for iter
292 
293  // String Vec
294  if (!m_stringVecMap.empty()) {
295  cout << endl << "String Vector options:" << endl;
296  } else {
297  cout << endl;
298  }
299  for (SSVecMapConstIter iter = m_stringVecMap.begin(); m_stringVecMap.end() != iter; ++iter) {
300  const string &description = m_variableDescriptionMap[iter->first];
301  cout << " " << setw(14) << iter->first << " = ";
302  if (description.length()) {
303  cout << setw(14) << ""
304  << " - " << description;
305  }
306  cout << endl;
307  dumpSTLeachEndl(iter->second, 8);
308  } // for iter
309 
310  cout << "------------------------------------------------------------------" << right << endl;
311 }
312 
313 bool CommandLineParser::_setVariableFromString(const string &arg, bool dontOverrideChange, int offset) {
314  string::size_type where = arg.find_first_of("=", offset + 1);
315  string varname = arg.substr(offset, where - offset);
316  string value = arg.substr(where + 1);
317  lowercaseString(varname);
318  // check to make sure this is a valid option
319  SBMapConstIter sbiter = m_variableModifiedMap.find(varname);
320  if (m_variableModifiedMap.end() == sbiter) {
321  // Not found. Not a valid option
322  return false;
323  }
324  // if 'dontOverrideChange' is set, then we are being asked to NOT
325  // change any variables that have already been changed.
326  if (dontOverrideChange && _valueHasBeenModified(varname)) {
327  // don't go any further
328  return true;
329  }
330  // integers
331  SIMapIter integerIter = m_integerMap.find(varname);
332  if (m_integerMap.end() != integerIter) {
333  // we found it
334  // use 'atof' instead of 'atoi' to get scientific notation
335  integerIter->second = (int)atof(value.c_str());
336  m_variableModifiedMap[varname] = true;
337  return true;
338  }
339  // double
340  SDMapIter doubleIter = m_doubleMap.find(varname);
341  if (m_doubleMap.end() != doubleIter) {
342  // we found it
343  doubleIter->second = atof(value.c_str());
344  m_variableModifiedMap[varname] = true;
345  return true;
346  }
347  // string
348  SSMapIter stringIter = m_stringMap.find(varname);
349  if (m_stringMap.end() != stringIter) {
350  // we found it
351  stringIter->second = value;
352  m_variableModifiedMap[varname] = true;
353  return true;
354  }
355  // bool
356  SBMapIter boolIter = m_boolMap.find(varname);
357  if (m_boolMap.end() != boolIter) {
358  // we found it
359  boolIter->second = 0 != atoi(value.c_str());
360  m_variableModifiedMap[varname] = true;
361  return true;
362  }
363  // IntegerVec
364  SIVecMapIter integerVecIter = m_integerVecMap.find(varname);
365  if (m_integerVecMap.end() != integerVecIter) {
366  // we found it
367  SVec words;
368  split(words, value, ",");
369  for (SVecConstIter wordIter = words.begin(); words.end() != wordIter; ++wordIter) {
370  integerVecIter->second.push_back((int)atof(wordIter->c_str()));
371  }
372  // we don't want to mark this as modified because we can add
373  // many values to this
374  // m_variableModifiedMap[varname] = true;
375  return true;
376  }
377  // DoubleVec
378  SDVecMapIter doubleVecIter = m_doubleVecMap.find(varname);
379  if (m_doubleVecMap.end() != doubleVecIter) {
380  // we found it
381  SVec words;
382  split(words, value, ",");
383  for (SVecConstIter wordIter = words.begin(); words.end() != wordIter; ++wordIter) {
384  doubleVecIter->second.push_back(atof(wordIter->c_str()));
385  }
386  // we don't want to mark this as modified because we can add
387  // many values to this
388  // m_variableModifiedMap[varname] = true;
389  return true;
390  }
391  // StringVec
392  SSVecMapIter stringVecIter = m_stringVecMap.find(varname);
393  if (m_stringVecMap.end() != stringVecIter) {
394  // we found it
395  SVec words;
396  split(words, value, ",");
397  for (SVecConstIter wordIter = words.begin(); words.end() != wordIter; ++wordIter) {
398  stringVecIter->second.push_back(*wordIter);
399  }
400  // we don't want to mark this as modified because we can add
401  // many values to this
402  // m_variableModifiedMap[varname] = true;
403  return true;
404  }
405  // We didn't find your variable. And we really shouldn't be here
406  // because we should have know that we didn't find your variable.
407  cerr << "CommandLineParser::SetVeriableFromString() Error: "
408  << "Unknown variable and internal fault. Aborting." << endl;
409  assert(0);
410  return false;
411 }
412 
414  ifstream source(filename.c_str(), ios::in);
415  if (!source) {
416  cerr << "file " << filename << "could not be opened" << endl;
417  return false;
418  }
419  string line;
420  while (getline(source, line)) {
421  // find the first nonspace
422  string::size_type where = line.find_first_not_of(kSpaces);
423  if (string::npos == where) {
424  // no non-spaces
425  continue;
426  }
427  char first = line.at(where);
428  if ('-' != first) {
429  continue;
430  }
431  where = line.find_first_not_of(kSpaces, where + 1);
432  if (string::npos == where) {
433  // no non-spaces
434  continue;
435  }
436  // Get string starting at first nonspace after '-'. Copy it to
437  // another string without copying any spaces and stopping at the
438  // first '#'.
439  string withspaces = line.substr(where);
440  string nospaces;
441  for (int position = 0; position < (int)withspaces.length(); ++position) {
442  char ch = withspaces[position];
443  if ('#' == ch) {
444  // start of a comment
445  break;
446  } else if (' ' == ch || '\t' == ch) {
447  continue;
448  }
449  nospaces += ch;
450  } // for position
451  if (!_setVariableFromString(nospaces, true)) {
452  cerr << "Don't understand line" << endl
453  << line << endl
454  << "in options file '" << filename << "'. Aborting." << endl;
455  exit(0);
456  } // if setting variable failed
457  } // while getline
458  return true;
459 }
460 
462  SVec equalWords;
463  split(equalWords, arg, "=");
464  if (2 != equalWords.size()) {
465  return false;
466  }
467  SVec commandWords;
468  split(commandWords, equalWords.at(0), "_");
469  if (2 != commandWords.size()) {
470  return false;
471  }
472  string &command = commandWords.at(1);
473  lowercaseString(command);
474  if (command != "load" && command != "clear") {
475  return false;
476  }
477  const string &key = commandWords.at(0);
478  OptionType type = hasOption(key);
480  cerr << "Command '" << command << "' only works on vectors." << endl;
481  return false;
482  }
483 
485  // Clear //
487  if ("clear" == command) {
488  if (kIntegerVector == type) {
489  integerVector(key).clear();
490  } else if (kDoubleVector == type) {
491  doubleVector(key).clear();
492  } else if (kStringVector == type) {
493  stringVector(key).clear();
494  } else {
495  // If we're here, then I made a coding mistake and want to
496  // know about it.
497  assert(0);
498  }
499  return true;
500  }
501 
503  // Load //
505  const string &filename = equalWords.at(1);
506  ifstream source(filename.c_str(), ios::in);
507  if (!source) {
508  cerr << "file " << filename << "could not be opened" << endl;
509  return false;
510  }
511  string line;
512  while (getline(source, line)) {
513  // find the first nonspace
514  string::size_type where = line.find_first_not_of(kSpaces);
515  if (string::npos == where) {
516  // no non-spaces
517  continue;
518  }
519  // get rid of leading spaces
520  line = line.substr(where);
521  // get rid of trailing spaces
522  where = line.find_last_not_of(kSpaces);
523  if (line.length() - 1 != where) {
524  line = line.substr(0, where + 1);
525  }
526  if ('#' == line.at(0)) {
527  // this is a comment line, ignore it
528  continue;
529  }
530  if (kIntegerVector == type) {
531  integerVector(key).push_back((int)atof(line.c_str()));
532  } else if (kDoubleVector == type) {
533  doubleVector(key).push_back(atof(line.c_str()));
534  } else if (kStringVector == type) {
535  stringVector(key).push_back(line);
536  } else {
537  // If we're here, then I made a coding mistake and want to
538  // know about it.
539  assert(0);
540  }
541  } // while getline
542  return true;
543 }
544 
545 void CommandLineParser::_getSectionFiles(const SVec &inputList, SVec &outputList, int section, int totalSections) {
546  // Make sure the segment numbers make sense
547  assert(section > 0 && section <= totalSections);
548 
549  // The Perl code:
550  // my $entries = @list;
551  // my $perSection = int ($entries / $totalSections);
552  // my $extra = $entries % $totalSections;
553  // --$section; # we want 0..n-1 not 1..n
554  // my $start = $perSection * $section;
555  // my $num = $perSection - 1;
556  // if ($section < $extra) {
557  // $start += $section;
558  // ++$num;
559  // } else {
560  // $start += $extra;
561  // };
562  // my $end = $start + $num;
563  int entries = (int)inputList.size();
564  int perSection = entries / totalSections;
565  int extra = entries % totalSections;
566  --section; // we want 0..n-1, not 1..n.
567  int current = perSection * section;
568  int num = perSection - 1;
569  if (section < extra) {
570  current += section;
571  ++num;
572  } else {
573  current += extra;
574  }
575  outputList.clear();
576  // we want to go from 0 to num inclusive, so make sure we have '<='
577  // and not '='
578  for (int loop = current; loop <= current + num; ++loop) {
579  outputList.push_back(inputList.at(loop));
580  } // for loop
581 }
582 
584  if (!(m_optionsType & kEventContOpt)) {
585  // nothing to see here, folks
586  return;
587  }
589  // Deal with sections //
591  if (integerValue("totalSections")) {
592  // we have a request to break this into sections. First, note
593  // this in the output file
594  tag += Form("_sec%03d", integerValue("section"));
595  SVec tempVec;
596  _getSectionFiles(stringVector("inputFiles"), tempVec, integerValue("section"), integerValue("totalSections"));
597  stringVector("inputFiles") = tempVec;
598  } // if section requested
599 
601  // Store lfn to pfn //
603  const string &kStorePrepend = stringValue("storePrepend");
604  if (kStorePrepend.length()) {
605  string match = "/store/";
606  int matchLen = match.length();
607  SVec tempVec;
608  SVec &currentFiles = stringVector("inputFiles");
609  for (SVecConstIter iter = currentFiles.begin(); currentFiles.end() != iter; ++iter) {
610  const string &filename = *iter;
611  if ((int)filename.length() > matchLen && filename.substr(0, matchLen) == match) {
612  tempVec.push_back(kStorePrepend + filename);
613  } else {
614  tempVec.push_back(filename);
615  }
616  }
617  currentFiles = tempVec;
618  } // if storePrepend.
619 
621  // //////////////////////////// //
622  // // Modify output filename // //
623  // //////////////////////////// //
625  string outputFile = stringValue("outputFile");
626  bool modifyOutputFile = (outputFile.length());
627  outputFile = removeEnding(outputFile, ".root");
628  outputFile += tag;
629  if (integerValue("maxEvents")) {
630  outputFile += Form("_maxevt%03d", integerValue("maxEvents"));
631  }
632  if (integerValue("jobID") >= 0) {
633  outputFile += Form("_jobID%03d", integerValue("jobID"));
634  }
635  if (stringValue("tag").length()) {
636  outputFile += "_" + stringValue("tag");
637  }
638 
640  // Log File Name, if requested //
642  if (boolValue("logName")) {
643  cout << outputFile << ".log" << endl;
644  exit(0);
645  }
646  outputFile += ".root";
647  if (modifyOutputFile) {
648  stringValue("outputFile") = outputFile;
649  }
650 
651  // finally, if they asked us to print all options, let's do so
652  // after we've modified all variables appropriately
653  if (m_printOptions) {
655  } // if printOptions
656 }
657 
658 // friends
659 ostream &operator<<(ostream &o_stream, const CommandLineParser &rhs) { return o_stream; }
bool _runVariableCommandFromString(const std::string &arg)
type
Definition: HCALResponse.h:21
SIMap::const_iterator SIMapConstIter
void _getSectionFiles(const SVec &inputList, SVec &outputList, int section, int totalSection)
void _finishDefaultOptions(std::string tag="")
bool _setVariablesFromFile(const std::string &filename)
static std::string removeEnding(const std::string &input, const std::string &ending)
SDMap::const_iterator SDMapConstIter
SSMap::iterator SSMapIter
SBMap::iterator SBMapIter
SIMap::iterator SIMapIter
std::string & stringValue(std::string key)
friend std::ostream & operator<<(std::ostream &o_stream, const CommandLineParser &rhs)
void parseArguments(int argc, char **argv, bool allowArgs=false)
static void removeLeadingAndTrailingSpaces(std::string &line)
static void split(SVec &retval, std::string line, std::string match=" \t", bool ignoreComments=true)
SBMap::const_iterator SBMapConstIter
SIVecMap::iterator SIVecMapIter
outputList
All other commands ##.
Definition: compareJSON.py:63
SSVecMap::const_iterator SSVecMapConstIter
std::vector< std::string > SVec
uint16_t size_type
A arg
Definition: Factorize.h:36
static std::string const input
Definition: EdmProvDump.cc:48
int & integerValue(std::string key)
SSMap::const_iterator SSMapConstIter
static const std::string kSpaces
SIVecMap::const_iterator SIVecMapConstIter
DVec & doubleVector(std::string key)
static void lowercaseString(std::string &arg)
Definition: value.py:1
SSVecMap::iterator SSVecMapIter
SDVecMap::iterator SDVecMapIter
bool _setVariableFromString(const std::string &arg, bool dontOverrideChange=false, int offset=0)
bool _valueHasBeenModified(const std::string &key)
static void removeComment(std::string &line)
IVec & integerVector(std::string key)
part
Definition: HCALResponse.h:20
SVec & stringVector(std::string key)
list command
Definition: mps_check.py:25
static void findCommand(const std::string &line, std::string &command, std::string &rest)
bool & boolValue(std::string key)
static int position[264][3]
Definition: ReadPGInfo.cc:289
void addOption(std::string key, OptionType type, const std::string &description="")
void usage()
Definition: array2xmlEB.cc:14
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10
SDMap::iterator SDMapIter
static std::string const source
Definition: EdmProvDump.cc:47
SDVecMap::const_iterator SDVecMapConstIter
SVec::const_iterator SVecConstIter
OptionType hasOption(std::string key)
def exit(msg="")