CMS 3D CMS Logo

/data/git/CMSSW_5_3_11_patch5/src/PhysicsTools/FWLite/src/CommandLineParser.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
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       // Integer options
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       // String options
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       // Bool options
00052       addOption ("logName",       kBool,
00053                  "Print log name and exit");
00054       // String vector options
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    // If we're still here, we have a type I don't understand.
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       } // tag=value strings
00095       else if (arg.at(0) == '-')
00096       {
00097          string::size_type where = arg.find_first_not_of("-");
00098          if (string::npos == where)
00099          {
00100             // a poorly formed option
00101             cerr << "Don't understand: " << arg << endl;
00102             exit(0);
00103             continue;
00104          }
00105          lowercaseString (arg);
00106          char first = arg.at (where);
00107          // Print the values
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          // Exit after printing values
00119          if ('h' == first)
00120          {
00121             callHelp = true;
00122             continue;
00123          }
00124          // if we're still here, then we've got a problem.
00125          cerr << "Don't understand: " << arg << endl;
00126          exit(0);
00127       } // -arg strings
00128       if (returnArgs)
00129       {
00130          argsVec.push_back (arg);
00131       } else {
00132          cerr << "Don't understand: " << arg << endl;
00133          exit(0);
00134       }
00135    } // for loop
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    } // if ignoreComments
00165    retval.clear();
00166    // find the first non-space
00167    string::size_type start1 = line.find_first_not_of (kSpaces);
00168    // Is the first non-space character a '#'
00169    char firstCh = line[start1];
00170    if ('#' == firstCh)
00171    {
00172       // this line is a comment
00173       return;
00174    }
00175 
00176    line += match; // get last word of line
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       // don't bother adding 0 length strings
00190       if (part.length()) 
00191       {
00192          retval.push_back(part);
00193       }
00194       last = current;
00195       current = line.find_first_of(match, current + 1);
00196    } // while we're finding spaces
00197 }
00198 
00199 void
00200 CommandLineParser::removeComment (string &line)
00201 {
00202    string::size_type location = line.find ("#");
00203    if (string::npos != location)
00204    {
00205       // we've got a comment.  Strip it out
00206       line = line.substr (0, location - 1);
00207    } // if found
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       // we don't have anything here at all.  Just quit now
00217       return;
00218    }
00219    if (pos)
00220    {
00221       // We have spaces at the beginning.
00222       line = line.substr (pos);
00223    }
00224    pos = line.find_last_not_of (kSpaces);
00225    if (pos + 1 != line.length())
00226    {
00227       // we've got spaces at the end
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       // we've got it
00239       return input.substr(0, position);
00240    }
00241    // If we're still here, it wasn't there
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       // we don't have anything here at all.  Just quit now
00255       return;
00256    }
00257    string::size_type space = line.find_first_of (kSpaces, nonspace);
00258    if (string::npos == space)
00259    {
00260       // we only have a command and nothing else
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    // Print the integers next
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    } // for iter
00293 
00294    // Print the doubles next
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    } // for iter
00312 
00313    // Print the bools first
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    } // for iter
00336 
00337    // Print the strings next
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    } // for iter
00356 
00357    // Integer Vec
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    } // for iter
00376 
00377    // Double Vec
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    } // for iter
00396 
00397    // String Vec
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    } // for iter
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    // check to make sure this is a valid option
00432    SBMapConstIter sbiter = m_variableModifiedMap.find (varname);
00433    if (m_variableModifiedMap.end() == sbiter)
00434    {
00435       // Not found.  Not a valid option
00436       return false;
00437    }
00438    // if 'dontOverrideChange' is set, then we are being asked to NOT
00439    // change any variables that have already been changed.
00440    if (dontOverrideChange && _valueHasBeenModified (varname) )
00441    {
00442       // don't go any further
00443       return true;
00444    }
00445    // integers
00446    SIMapIter integerIter = m_integerMap.find(varname);
00447    if (m_integerMap.end() != integerIter)
00448    {
00449       // we found it
00450       // use 'atof' instead of 'atoi' to get scientific notation
00451       integerIter->second = (int) atof( value.c_str() );
00452       m_variableModifiedMap[varname] = true;
00453       return true;
00454    }
00455    // double
00456    SDMapIter doubleIter = m_doubleMap.find(varname);
00457    if (m_doubleMap.end() != doubleIter)
00458    {
00459       // we found it
00460       doubleIter->second = atof( value.c_str() );
00461       m_variableModifiedMap[varname] = true;
00462       return true;
00463    }
00464    // string
00465    SSMapIter stringIter = m_stringMap.find(varname);
00466    if (m_stringMap.end() != stringIter)
00467    {
00468       // we found it
00469       stringIter->second = value;
00470       m_variableModifiedMap[varname] = true;
00471       return true;
00472    }
00473    // bool
00474    SBMapIter boolIter = m_boolMap.find(varname);
00475    if (m_boolMap.end() != boolIter)
00476    {
00477       // we found it
00478       boolIter->second = 0 != atoi( value.c_str() );
00479       m_variableModifiedMap[varname] = true;
00480       return true;
00481    }
00482    // IntegerVec
00483    SIVecMapIter integerVecIter = m_integerVecMap.find(varname);
00484    if (m_integerVecMap.end() != integerVecIter)
00485    {
00486       // we found it
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       // we don't want to mark this as modified because we can add
00496       // many values to this
00497       // m_variableModifiedMap[varname] = true;
00498       return true;
00499    }
00500    // DoubleVec
00501    SDVecMapIter doubleVecIter = m_doubleVecMap.find(varname);
00502    if (m_doubleVecMap.end() != doubleVecIter)
00503    {
00504       // we found it
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       // we don't want to mark this as modified because we can add
00514       // many values to this
00515       // m_variableModifiedMap[varname] = true;
00516       return true;
00517    }
00518    // StringVec
00519    SSVecMapIter stringVecIter = m_stringVecMap.find(varname);
00520    if (m_stringVecMap.end() != stringVecIter)
00521    {
00522       // we found it
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       // we don't want to mark this as modified because we can add
00532       // many values to this
00533       // m_variableModifiedMap[varname] = true;
00534       return true;
00535    }
00536    // We didn't find your variable.  And we really shouldn't be here
00537    // because we should have know that we didn't find your variable.
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       // find the first nonspace
00557       string::size_type where = line.find_first_not_of(kSpaces);
00558       if (string::npos == where)
00559       {
00560          // no non-spaces
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          // no non-spaces
00572          continue;
00573       }
00574       // Get string starting at first nonspace after '-'.  Copy it to
00575       // another string without copying any spaces and stopping at the
00576       // first '#'.
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             // start of a comment
00587             break;
00588          } else if (' ' == ch || '\t' == ch)
00589          {
00590             continue;
00591          }
00592          nospaces += ch;
00593       } // for position
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       } // if setting variable failed
00601    } // while getline
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    // Clear //
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          // If we're here, then I made a coding mistake and want to
00650          // know about it.
00651          assert (0);
00652       }
00653       return true;
00654    }
00655 
00657    // Load //
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       // find the first nonspace
00670       string::size_type where = line.find_first_not_of (kSpaces);
00671       if (string::npos == where)
00672       {
00673          // no non-spaces
00674          continue;
00675       }
00676       // get rid of leading spaces
00677       line = line.substr (where);
00678       // get rid of trailing spaces
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          // this is a comment line, ignore it
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          // If we're here, then I made a coding mistake and want to
00700          // know about it.
00701          assert (0);
00702       }
00703    } // while getline
00704    return true;
00705    
00706 }
00707 
00708 void
00709 CommandLineParser::_getSectionFiles (const SVec &inputList, SVec &outputList,
00710                                      int section, int totalSections)
00711 {
00712    // Make sure the segment numbers make sense
00713    assert (section > 0 && section <= totalSections);
00714 
00715    // The Perl code:
00716    // my $entries    = @list;
00717    // my $perSection = int ($entries / $totalSections);
00718    // my $extra      = $entries % $totalSections;
00719    // --$section; # we want 0..n-1 not 1..n
00720    // my $start = $perSection * $section;
00721    // my $num   = $perSection - 1;
00722    // if ($section < $extra) {
00723    //    $start += $section;
00724    //    ++$num;
00725    // } else {
00726    //    $start += $extra;
00727    // };
00728    // my $end = $start + $num;
00729    int entries = (int) inputList.size();
00730    int perSection = entries / totalSections;
00731    int extra = entries % totalSections;
00732    --section; // we want 0..n-1, not 1..n.
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    // we want to go from 0 to num inclusive, so make sure we have '<='
00745    // and not '='
00746    for (int loop = current; loop <= current + num; ++loop)
00747    {
00748       outputList.push_back( inputList.at( loop ) );
00749    } // for loop
00750 }
00751 
00752 void 
00753 CommandLineParser::_finishDefaultOptions (std::string tag)
00754 {
00755    if (! m_optionsType & kEventContOpt)
00756    {
00757       // nothing to see here, folks
00758       return;
00759    }
00761    // Deal with sections //
00763    if ( integerValue ("totalSections") )
00764    {
00765       // we have a request to break this into sections.  First, note
00766       // this in the output file
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    } // if section requested
00775 
00777    // Store lfn to pfn //
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 &currentFiles = 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    } // if storePrepend.
00801 
00803    // //////////////////////////// //
00804    // // Modify output filename // //
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    // Log File Name, if requested //
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    // finally, if they asked us to print all options, let's do so
00839    // after we've modified all variables appropriately
00840    if (m_printOptions)
00841    {
00842       printOptionValues();
00843    } // if printOptions
00844 }
00845 
00846 // friends
00847 ostream& operator<< (ostream& o_stream, const CommandLineParser &rhs)
00848 {
00849    return o_stream;
00850 }