00001
00002 #include <iostream>
00003 #include <fstream>
00004 #include <iomanip>
00005 #include <cstdlib>
00006 #include <cassert>
00007
00008 #include "TString.h"
00009
00010 #include "PhysicsTools/FWLite/interface/CommandLineParser.h"
00011 #include "PhysicsTools/FWLite/interface/dout.h"
00012 #include "PhysicsTools/FWLite/interface/dumpSTL.icc"
00013
00014 using namespace std;
00015 using namespace optutl;
00016
00017 const std::string CommandLineParser::kSpaces = " \t";
00018
00019
00020 CommandLineParser::CommandLineParser (const string &usage,
00021 unsigned int optionsType) :
00022 m_argv0(""), m_usageString (usage),
00023 m_printOptions (true), m_optionsType (optionsType)
00024 {
00025 if (m_optionsType & kEventContOpt)
00026 {
00027
00028 addOption ("totalSections", kInteger,
00029 "Total number of sections",
00030 0);
00031 addOption ("section", kInteger,
00032 "This section (from 1..totalSections inclusive)",
00033 0);
00034 addOption ("maxEvents", kInteger,
00035 "Maximum number of events to run over (0 for whole file)",
00036 0);
00037 addOption ("jobID", kInteger,
00038 "jobID given by CRAB,etc. (-1 means append nothing)",
00039 -1);
00040 addOption ("outputEvery", kInteger,
00041 "Output something once every N events (0 for never)",
00042 0);
00043
00044 addOption ("outputFile", kString,
00045 "Output filename",
00046 "output.root");
00047 addOption ("storePrepend", kString,
00048 "Prepend location on files starting with '/store/'");
00049 addOption ("tag", kString,
00050 "A 'tag' to append to output file (e.g., 'v2', etc.)");
00051
00052 addOption ("logName", kBool,
00053 "Print log name and exit");
00054
00055 addOption ("inputFiles", kStringVector,
00056 "List of input files");
00057 addOption ("secondaryInputFiles", kStringVector,
00058 "List of secondary input files (a.k.a. two-file-solution");
00059 addOption ("orderedSecondaryFiles", kBool,
00060 "Are the secondary files ordered?",
00061 false );
00062 return;
00063 }
00064
00065 cerr << "CommandLineParser() Error: type '" << optionsType
00066 << "' is not understood. Aborting." << endl;
00067 assert (0);
00068 }
00069
00070 void
00071 CommandLineParser::parseArguments (int argc, char** argv, bool returnArgs)
00072 {
00073 bool callHelp = false;
00074 SVec argsVec;
00075 m_argv0 = argv[0];
00076 m_fullArgVec.push_back (argv[0]);
00077 for (int loop = 1; loop < argc; ++loop)
00078 {
00079 string arg = argv[loop];
00080 m_fullArgVec.push_back (arg);
00081 string::size_type where = arg.find_first_of("=");
00082 if (string::npos != where)
00083 {
00084 if ( _setVariableFromString (arg) )
00085 {
00086 continue;
00087 }
00088 if ( _runVariableCommandFromString (arg) )
00089 {
00090 continue;
00091 }
00092 cerr << "Don't understand: " << arg << endl;
00093 exit(0);
00094 }
00095 else if (arg.at(0) == '-')
00096 {
00097 string::size_type where = arg.find_first_not_of("-");
00098 if (string::npos == where)
00099 {
00100
00101 cerr << "Don't understand: " << arg << endl;
00102 exit(0);
00103 continue;
00104 }
00105 lowercaseString (arg);
00106 char first = arg.at (where);
00107
00108 if ('p' == first)
00109 {
00110 m_printOptions = true;
00111 continue;
00112 }
00113 if ('n' == first)
00114 {
00115 m_printOptions = false;
00116 continue;
00117 }
00118
00119 if ('h' == first)
00120 {
00121 callHelp = true;
00122 continue;
00123 }
00124
00125 cerr << "Don't understand: " << arg << endl;
00126 exit(0);
00127 }
00128 if (returnArgs)
00129 {
00130 argsVec.push_back (arg);
00131 } else {
00132 cerr << "Don't understand: " << arg << endl;
00133 exit(0);
00134 }
00135 }
00136 if (callHelp)
00137 {
00138 help();
00139 }
00140 }
00141
00142 void
00143 CommandLineParser::help()
00144 {
00145 if (m_usageString.length())
00146 {
00147 cout << m_argv0 << " - " << m_usageString << endl;
00148 }
00149 cout << "--help - This screen" << endl
00150 << "--noPrint - Do not print out all settings" << endl
00151 << "--print - Print out all settings" << endl;
00152 printOptionValues();
00153 exit (0);
00154 }
00155
00156
00157 void
00158 CommandLineParser::split (SVec &retval, string line, string match,
00159 bool ignoreComments)
00160 {
00161 if (ignoreComments)
00162 {
00163 removeComment (line);
00164 }
00165 retval.clear();
00166
00167 string::size_type start1 = line.find_first_not_of (kSpaces);
00168
00169 char firstCh = line[start1];
00170 if ('#' == firstCh)
00171 {
00172
00173 return;
00174 }
00175
00176 line += match;
00177 string::size_type last = string::npos;
00178 string::size_type current = line.find_first_of(match);
00179 while (string::npos != current)
00180 {
00181 string::size_type pos;
00182 if (string::npos != last)
00183 {
00184 pos = last + 1;
00185 } else {
00186 pos = 0;
00187 }
00188 string part = line.substr( pos, current - last - 1);
00189
00190 if (part.length())
00191 {
00192 retval.push_back(part);
00193 }
00194 last = current;
00195 current = line.find_first_of(match, current + 1);
00196 }
00197 }
00198
00199 void
00200 CommandLineParser::removeComment (string &line)
00201 {
00202 string::size_type location = line.find ("#");
00203 if (string::npos != location)
00204 {
00205
00206 line = line.substr (0, location - 1);
00207 }
00208 }
00209
00210 void
00211 CommandLineParser::removeLeadingAndTrailingSpaces (std::string &line)
00212 {
00213 string::size_type pos = line.find_first_not_of (kSpaces);
00214 if (string::npos == pos)
00215 {
00216
00217 return;
00218 }
00219 if (pos)
00220 {
00221
00222 line = line.substr (pos);
00223 }
00224 pos = line.find_last_not_of (kSpaces);
00225 if (pos + 1 != line.length())
00226 {
00227
00228 line = line.substr (0, pos + 1);
00229 }
00230 }
00231
00232 string
00233 CommandLineParser::removeEnding (const string &input, const string &ending)
00234 {
00235 string::size_type position = input.rfind(ending);
00236 if (input.length() - ending.length() == position)
00237 {
00238
00239 return input.substr(0, position);
00240 }
00241
00242 return input;
00243 }
00244
00245 void
00246 CommandLineParser::findCommand (const string &line,
00247 string &command,
00248 string &rest)
00249 {
00250 command = rest = "";
00251 string::size_type nonspace = line.find_first_not_of (kSpaces);
00252 if (string::npos == nonspace)
00253 {
00254
00255 return;
00256 }
00257 string::size_type space = line.find_first_of (kSpaces, nonspace);
00258 if (string::npos == space)
00259 {
00260
00261 command = line.substr (nonspace);
00262 return;
00263 }
00264 command = line.substr (nonspace, space - nonspace);
00265 rest = line.substr (space + 1);
00266 removeLeadingAndTrailingSpaces (rest);
00267 }
00268
00269
00270 void
00271 CommandLineParser::printOptionValues()
00272 {
00273 cout << "------------------------------------------------------------------"
00274 << left << endl;
00275
00276 if (m_integerMap.size())
00277 {
00278 cout << endl << "Integer options:" << endl;
00279 }
00280 for (SIMapConstIter iter = m_integerMap.begin();
00281 m_integerMap.end() != iter;
00282 ++iter)
00283 {
00284 const string &description = m_variableDescriptionMap[ iter->first ];
00285 cout << " " << setw(14) << iter->first << " = " << setw(14)
00286 << iter->second;
00287 if (description.length())
00288 {
00289 cout << " - " << description;
00290 }
00291 cout << endl;
00292 }
00293
00294
00295 if (m_doubleMap.size())
00296 {
00297 cout << endl << "Double options:" << endl;
00298 }
00299 for (SDMapConstIter iter = m_doubleMap.begin();
00300 m_doubleMap.end() != iter;
00301 ++iter)
00302 {
00303 const string &description = m_variableDescriptionMap[ iter->first ];
00304 cout << " " << setw(14) << iter->first << " = " << setw(14)
00305 << iter->second;
00306 if (description.length())
00307 {
00308 cout << " - " << description;
00309 }
00310 cout << endl;
00311 }
00312
00313
00314 if (m_boolMap.size())
00315 {
00316 cout << endl << "Bool options:" << endl;
00317 }
00318 for (SBMapConstIter iter = m_boolMap.begin();
00319 m_boolMap.end() != iter;
00320 ++iter)
00321 {
00322 const string &description = m_variableDescriptionMap[ iter->first ];
00323 cout << " " << setw(14) << iter->first << " = " << setw(14);
00324 if (iter->second)
00325 {
00326 cout << "true";
00327 } else {
00328 cout << "false";
00329 }
00330 if (description.length())
00331 {
00332 cout << " - " << description;
00333 }
00334 cout << endl;
00335 }
00336
00337
00338 if (m_stringMap.size())
00339 {
00340 cout << endl << "String options:" << endl;
00341 }
00342 for (SSMapConstIter iter = m_stringMap.begin();
00343 m_stringMap.end() != iter;
00344 ++iter)
00345 {
00346 const string &description = m_variableDescriptionMap[ iter->first ];
00347 cout << " " << setw(14) << iter->first << " = ";
00348 const string value = "'" + iter->second + "'";
00349 cout << setw(14) << "";
00350 if (description.length())
00351 {
00352 cout << " - " << description;
00353 }
00354 cout << endl << " " << value << endl;
00355 }
00356
00357
00358 if (m_integerVecMap.size())
00359 {
00360 cout << endl << "Integer Vector options:" << endl;
00361 }
00362 for (SIVecMapConstIter iter = m_integerVecMap.begin();
00363 m_integerVecMap.end() != iter;
00364 ++iter)
00365 {
00366 const string &description = m_variableDescriptionMap[ iter->first ];
00367 cout << " " << setw(14) << iter->first << " = ";
00368 dumpSTL (iter->second);
00369 cout << endl;
00370 if (description.length())
00371 {
00372 cout << " - " << description;
00373 }
00374 cout << endl;
00375 }
00376
00377
00378 if (m_doubleVecMap.size())
00379 {
00380 cout << endl << "Double Vector options:" << endl;
00381 }
00382 for (SDVecMapConstIter iter = m_doubleVecMap.begin();
00383 m_doubleVecMap.end() != iter;
00384 ++iter)
00385 {
00386 const string &description = m_variableDescriptionMap[ iter->first ];
00387 cout << " " << setw(14) << iter->first << " = ";
00388 dumpSTL (iter->second);
00389 cout << endl;
00390 if (description.length())
00391 {
00392 cout << " - " << description;
00393 }
00394 cout << endl;
00395 }
00396
00397
00398 if (m_stringVecMap.size())
00399 {
00400 cout << endl << "String Vector options:" << endl;
00401 } else {
00402 cout << endl;
00403 }
00404 for (SSVecMapConstIter iter = m_stringVecMap.begin();
00405 m_stringVecMap.end() != iter;
00406 ++iter)
00407 {
00408 const string &description = m_variableDescriptionMap[ iter->first ];
00409 cout << " " << setw(14) << iter->first << " = ";
00410 if (description.length())
00411 {
00412 cout << setw(14) << "" << " - " << description;
00413 }
00414 cout << endl;
00415 dumpSTLeachEndl (iter->second, 8);
00416 }
00417
00418 cout << "------------------------------------------------------------------"
00419 << right << endl;
00420 }
00421
00422 bool
00423 CommandLineParser::_setVariableFromString (const string &arg,
00424 bool dontOverrideChange,
00425 int offset)
00426 {
00427 string::size_type where = arg.find_first_of("=", offset + 1);
00428 string varname = arg.substr (offset, where - offset);
00429 string value = arg.substr (where + 1);
00430 lowercaseString (varname);
00431
00432 SBMapConstIter sbiter = m_variableModifiedMap.find (varname);
00433 if (m_variableModifiedMap.end() == sbiter)
00434 {
00435
00436 return false;
00437 }
00438
00439
00440 if (dontOverrideChange && _valueHasBeenModified (varname) )
00441 {
00442
00443 return true;
00444 }
00445
00446 SIMapIter integerIter = m_integerMap.find(varname);
00447 if (m_integerMap.end() != integerIter)
00448 {
00449
00450
00451 integerIter->second = (int) atof( value.c_str() );
00452 m_variableModifiedMap[varname] = true;
00453 return true;
00454 }
00455
00456 SDMapIter doubleIter = m_doubleMap.find(varname);
00457 if (m_doubleMap.end() != doubleIter)
00458 {
00459
00460 doubleIter->second = atof( value.c_str() );
00461 m_variableModifiedMap[varname] = true;
00462 return true;
00463 }
00464
00465 SSMapIter stringIter = m_stringMap.find(varname);
00466 if (m_stringMap.end() != stringIter)
00467 {
00468
00469 stringIter->second = value;
00470 m_variableModifiedMap[varname] = true;
00471 return true;
00472 }
00473
00474 SBMapIter boolIter = m_boolMap.find(varname);
00475 if (m_boolMap.end() != boolIter)
00476 {
00477
00478 boolIter->second = 0 != atoi( value.c_str() );
00479 m_variableModifiedMap[varname] = true;
00480 return true;
00481 }
00482
00483 SIVecMapIter integerVecIter = m_integerVecMap.find(varname);
00484 if (m_integerVecMap.end() != integerVecIter)
00485 {
00486
00487 SVec words;
00488 split (words, value, ",");
00489 for (SVecConstIter wordIter = words.begin();
00490 words.end() != wordIter;
00491 ++wordIter)
00492 {
00493 integerVecIter->second.push_back( (int) atof( wordIter->c_str() ) );
00494 }
00495
00496
00497
00498 return true;
00499 }
00500
00501 SDVecMapIter doubleVecIter = m_doubleVecMap.find(varname);
00502 if (m_doubleVecMap.end() != doubleVecIter)
00503 {
00504
00505 SVec words;
00506 split (words, value, ",");
00507 for (SVecConstIter wordIter = words.begin();
00508 words.end() != wordIter;
00509 ++wordIter)
00510 {
00511 doubleVecIter->second.push_back( atof( wordIter->c_str() ) );
00512 }
00513
00514
00515
00516 return true;
00517 }
00518
00519 SSVecMapIter stringVecIter = m_stringVecMap.find(varname);
00520 if (m_stringVecMap.end() != stringVecIter)
00521 {
00522
00523 SVec words;
00524 split (words, value, ",");
00525 for (SVecConstIter wordIter = words.begin();
00526 words.end() != wordIter;
00527 ++wordIter)
00528 {
00529 stringVecIter->second.push_back( *wordIter );
00530 }
00531
00532
00533
00534 return true;
00535 }
00536
00537
00538 cerr << "CommandLineParser::SetVeriableFromString() Error: "
00539 << "Unknown variable and internal fault. Aborting." << endl;
00540 assert (0);
00541 return false;
00542 }
00543
00544 bool
00545 CommandLineParser::_setVariablesFromFile (const string &filename)
00546 {
00547 ifstream source (filename.c_str(), ios::in);
00548 if (! source)
00549 {
00550 cerr << "file " << filename << "could not be opened" << endl;
00551 return false;
00552 }
00553 string line;
00554 while (getline (source, line))
00555 {
00556
00557 string::size_type where = line.find_first_not_of(kSpaces);
00558 if (string::npos == where)
00559 {
00560
00561 continue;
00562 }
00563 char first = line.at (where);
00564 if ('-' != first)
00565 {
00566 continue;
00567 }
00568 where = line.find_first_not_of(kSpaces, where + 1);
00569 if (string::npos == where)
00570 {
00571
00572 continue;
00573 }
00574
00575
00576
00577 string withspaces = line.substr (where);
00578 string nospaces;
00579 for (int position = 0;
00580 position < (int) withspaces.length();
00581 ++position)
00582 {
00583 char ch = withspaces[position];
00584 if ('#' == ch)
00585 {
00586
00587 break;
00588 } else if (' ' == ch || '\t' == ch)
00589 {
00590 continue;
00591 }
00592 nospaces += ch;
00593 }
00594 if (! _setVariableFromString (nospaces, true) )
00595 {
00596 cerr << "Don't understand line" << endl << line << endl
00597 << "in options file '" << filename << "'. Aborting."
00598 << endl;
00599 exit(0);
00600 }
00601 }
00602 return true;
00603 }
00604
00605 bool
00606 CommandLineParser::_runVariableCommandFromString (const string &arg)
00607 {
00608 SVec equalWords;
00609 split (equalWords, arg, "=");
00610 if (2 != equalWords.size())
00611 {
00612 return false;
00613 }
00614 SVec commandWords;
00615 split (commandWords, equalWords.at(0), "_");
00616 if (2 != commandWords.size())
00617 {
00618 return false;
00619 }
00620 string &command = commandWords.at(1);
00621 lowercaseString (command);
00622 if (command != "load" && command != "clear")
00623 {
00624 return false;
00625 }
00626 const string &key = commandWords.at(0);
00627 OptionType type = hasOption (key);
00628 if (type < kIntegerVector || type > kStringVector)
00629 {
00630 cerr << "Command '" << command << "' only works on vectors." << endl;
00631 return false;
00632 }
00633
00635
00637 if ("clear" == command)
00638 {
00639 if (kIntegerVector == type)
00640 {
00641 integerVector(key).clear();
00642 } else if (kDoubleVector == type)
00643 {
00644 doubleVector(key).clear();
00645 } else if (kStringVector == type)
00646 {
00647 stringVector(key).clear();
00648 } else {
00649
00650
00651 assert (0);
00652 }
00653 return true;
00654 }
00655
00657
00659 const string &filename = equalWords.at(1);
00660 ifstream source (filename.c_str(), ios::in);
00661 if (! source)
00662 {
00663 cerr << "file " << filename << "could not be opened" << endl;
00664 return false;
00665 }
00666 string line;
00667 while (getline (source, line))
00668 {
00669
00670 string::size_type where = line.find_first_not_of (kSpaces);
00671 if (string::npos == where)
00672 {
00673
00674 continue;
00675 }
00676
00677 line = line.substr (where);
00678
00679 where = line.find_last_not_of (kSpaces);
00680 if (line.length() - 1 != where)
00681 {
00682 line = line.substr (0, where + 1);
00683 }
00684 if ('#' == line.at(0))
00685 {
00686
00687 continue;
00688 }
00689 if (kIntegerVector == type)
00690 {
00691 integerVector(key).push_back( (int) atof( line.c_str() ) );
00692 } else if (kDoubleVector == type)
00693 {
00694 doubleVector(key).push_back( atof( line.c_str() ) );
00695 } else if (kStringVector == type)
00696 {
00697 stringVector(key).push_back( line );
00698 } else {
00699
00700
00701 assert (0);
00702 }
00703 }
00704 return true;
00705
00706 }
00707
00708 void
00709 CommandLineParser::_getSectionFiles (const SVec &inputList, SVec &outputList,
00710 int section, int totalSections)
00711 {
00712
00713 assert (section > 0 && section <= totalSections);
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 int entries = (int) inputList.size();
00730 int perSection = entries / totalSections;
00731 int extra = entries % totalSections;
00732 --section;
00733 int current = perSection * section;
00734 int num = perSection - 1;
00735 if (section < extra)
00736 {
00737 current += section;
00738 ++num;
00739 } else
00740 {
00741 current += extra;
00742 }
00743 outputList.clear();
00744
00745
00746 for (int loop = current; loop <= current + num; ++loop)
00747 {
00748 outputList.push_back( inputList.at( loop ) );
00749 }
00750 }
00751
00752 void
00753 CommandLineParser::_finishDefaultOptions (std::string tag)
00754 {
00755 if (! m_optionsType & kEventContOpt)
00756 {
00757
00758 return;
00759 }
00761
00763 if ( integerValue ("totalSections") )
00764 {
00765
00766
00767 tag += Form ("_sec%03d", integerValue ("section"));
00768 SVec tempVec;
00769 _getSectionFiles ( stringVector ("inputFiles"),
00770 tempVec,
00771 integerValue ("section"),
00772 integerValue ("totalSections") );
00773 stringVector ("inputFiles") = tempVec;
00774 }
00775
00777
00779 const string &kStorePrepend = stringValue ("storePrepend");
00780 if (kStorePrepend.length())
00781 {
00782 string match = "/store/";
00783 int matchLen = match.length();
00784 SVec tempVec;
00785 SVec ¤tFiles = stringVector ("inputFiles");
00786 for (SVecConstIter iter = currentFiles.begin();
00787 currentFiles.end() != iter;
00788 ++iter)
00789 {
00790 const string &filename = *iter;
00791 if ((int) filename.length() > matchLen &&
00792 filename.substr(0, matchLen) == match)
00793 {
00794 tempVec.push_back( kStorePrepend + filename );
00795 } else {
00796 tempVec.push_back( filename);
00797 }
00798 }
00799 currentFiles = tempVec;
00800 }
00801
00803
00804
00805
00807 string outputFile = stringValue ("outputFile");
00808 bool modifyOutputFile = ( outputFile.length() );
00809 outputFile = removeEnding (outputFile, ".root");
00810 outputFile += tag;
00811 if ( integerValue ("maxEvents") )
00812 {
00813 outputFile += Form ("_maxevt%03d", integerValue ("maxEvents"));
00814 }
00815 if ( integerValue ("jobID") >= 0)
00816 {
00817 outputFile += Form ("_jobID%03d", integerValue ("jobID"));
00818 }
00819 if ( stringValue ("tag").length() )
00820 {
00821 outputFile += "_" + stringValue ("tag");
00822 }
00823
00825
00827 if ( boolValue ("logName") )
00828 {
00829 cout << outputFile << ".log" << endl;
00830 exit(0);
00831 }
00832 outputFile += ".root";
00833 if (modifyOutputFile)
00834 {
00835 stringValue ("outputFile") = outputFile;
00836 }
00837
00838
00839
00840 if (m_printOptions)
00841 {
00842 printOptionValues();
00843 }
00844 }
00845
00846
00847 ostream& operator<< (ostream& o_stream, const CommandLineParser &rhs)
00848 {
00849 return o_stream;
00850 }