CommandLineProcessor.cc

Go to the documentation of this file.
00001 // $Id: CommandLineProcessor.cc,v 1.10 2007/09/26 18:42:00 jeremy Exp $
00002 
00003 #include "CommandLineProcessor.hh"
00004 
00005 // slic
00006 #include "PackageInfo.hh"
00007 #include "CommandQueue.hh"
00008 #include "CommandLineOption.hh"
00009 
00010 // getopt
00011 #include "getopt.h"
00012 
00013 // stl
00014 #include <sstream>
00015 #include <cassert>
00016 
00017 using std::stringstream;
00018 using std::left;
00019 
00020 namespace slic
00021 {  
00022   CommandLineProcessor::CommandLineProcessor()
00023     : Module("CommandLineProcessor"),
00024       m_help_flag(0),
00025       m_interactive_flag(0),
00026       m_version_flag(0)
00027   {
00028     registerOptions();
00029     createOptionsString();
00030   }
00031 
00032   CommandLineProcessor::~CommandLineProcessor()
00033   {}
00034 
00035   void CommandLineProcessor::process(int argc, char** argv)
00036   {    
00037     // Description of SLIC's options in getopt's format.
00038     static struct option long_options[] = {
00039       {"help", no_argument, 0, 'h'},
00040       {"help", no_argument, 0, '?'},                
00041       {"version", no_argument, 0, 'v'},
00042       {"interactive", no_argument, 0, 'n'},
00043       {"macro", required_argument, 0, 'm'},
00044       {"event-file", required_argument, 0, 'i'},
00045       {"lcdd-url", required_argument, 0, 'g'},
00046       {"lcio-file", required_argument, 0, 'o'},
00047       {"lcio-path", required_argument, 0, 'p'},
00048       {"autoname", optional_argument, 0, 'O'},
00049       {"lcio-delete", no_argument, 0, 'x'},
00050       {"run-events", required_argument, 0, 'r'},
00051       {"skip-events", required_argument, 0, 's'},
00052       {"physics-list", required_argument, 0, 'l'},
00053       {"log-file", required_argument, 0, 'L'},
00054       {"seed", required_argument, 0, 'd'},
00055       {"dump-gdml", required_argument, 0, 'G'},
00056       {"optical", no_argument, 0, 'c'},
00057       {0, 0, 0, 0}
00058     };
00059 
00060     const char* optstr = m_getoptOptions.c_str();
00061 
00062     while (1) {
00063             
00064       int option_index = 0;
00065       int c;
00066 
00067       // Call getopt for next option.
00068       c = getopt_long (argc, 
00069                        argv, 
00070                        optstr,
00071                        long_options, 
00072                        &option_index);
00073 
00074 #ifdef SLIC_LOG
00075       log() << LOG::verbose << "Handling option <" << c << ">." << LOG::done;
00076 #endif
00077      
00078       // Done.
00079       if ( c == -1 ) 
00080         break;
00081       
00082       // Handle options.
00083       switch (c) {
00084 
00085       case 'h': 
00086         m_help_flag=1;
00087         break;
00088 
00089       case '?':
00090         m_help_flag=1;
00091         break;
00092 
00093       case 'n':
00094         m_interactive_flag=1;
00095         break;
00096 
00097       case 'v':
00098         m_version_flag=1;
00099         break;          
00100 
00101       default:     
00102 
00103         stringstream ostr;
00104         char cc = (char)c;
00105         ostr << cc;
00106         string theopt = ostr.str();
00107 
00108         if ( optarg ) {
00109           m_commandline.push_back( OptionsPair( theopt, optarg ) );
00110         }
00111         else {
00112           m_commandline.push_back( OptionsPair( theopt, "" ) );
00113         }
00114         
00115         break;
00116       }
00117     }
00118 
00119     //
00120     // The processing flow...
00121     //
00122     // 1) If version flag is set, print version and exit.
00123     //
00124     // 2) If usage flag is set or no arguments were received,
00125     //    print the usage and exit.
00126     //
00127     // 3) If a single non-option command was received, treat
00128     //    it as a macro to execute.
00129     //
00130     // 4) If no options were received or the number of options
00131     //    is less than the number of arguments, print usage
00132     //    and exit (syntax incorrect).
00133     //
00134     // 5) Finally, process the options in order if the syntax
00135     //    appears to be okay.
00136     //
00137 
00138     // Print the version information and abort.
00139     if ( m_version_flag ) {
00140       printVersion();
00141       abort();
00142     }    
00143     // Print the usage and abort if the help flag is set
00144     // or no arguments were received.
00145     else if ( m_help_flag || argc == 1 ) {
00146       printUsage();
00147       abort();
00148     }
00149     // Single macro to execute, if got 1 argument that is a non-option.
00150     else if ( argc == 2 && optind < argc ) {
00151       stringstream str;
00152       str << "/control/execute ";
00153       str << argv[1];
00154       m_g4q.add( str.str() );
00155     }
00156     // Probably extra arguments or no options.
00157     else if ( optind == 1 || optind < argc ) {
00158       printUsage();
00159       abort();
00160     }
00161     // Default is process all the options and build the CommandQueue.
00162     else {  
00163       processOptions();
00164     }
00165   }
00166 
00167   void CommandLineProcessor::printUsage()
00168   {
00169     printVersion();
00170 
00171     log() << LOG::okay << LOG::done;
00172     log() << LOG::okay << "**************" << LOG::done;
00173     log() << LOG::okay << "* SLIC Usage *" << LOG::done;
00174     log() << LOG::okay << "**************" << LOG::done;
00175 
00176     log() << LOG::okay << LOG::done;
00177     log() << LOG::okay << "Command line usage: " << LOG::done;
00178     log() << LOG::okay << LOG::done;
00179     log() << LOG::okay << "slic [single_macro_path]" << LOG::done;
00180     log() << LOG::okay << "slic [options]" << LOG::done;
00181 
00182     log() << LOG::okay << LOG::done;
00183 
00184     log() << LOG::okay << "Interactive usage: " << LOG::done;
00185     log() << LOG::okay << LOG::done;
00186     log() << LOG::okay << "slic -n" << LOG::done;
00187 
00188     log() << LOG::okay << LOG::done;
00189 
00190     printOptions();
00191 
00192     log() << LOG::okay << LOG::done;
00193   }
00194 
00195   void CommandLineProcessor::abort()
00196   {
00197     exit(0);
00198   }
00199 
00200   void CommandLineProcessor::registerOptions()
00201   {
00202     // Print application usage. 
00203     addOption(new CommandLineOption("h",
00204                                     "help",
00205                                     "Print SLIC usage.",
00206                                     0,
00207                                     0,
00208                                     "/slic/usage"));
00209 
00210     // Usage is also activated with the '?' switch.
00211     addOption(new CommandLineOption("?",
00212                                     "help",
00213                                     "Print SLIC usage.",
00214                                     0,
00215                                     0,
00216                                     "/slic/usage"));
00217     
00218     // Run in interactive mode.
00219     addOption(new CommandLineOption("n",
00220                              "interactive",
00221                              "Start a Geant4 interactive session.",
00222                              0,
00223                              0,
00224                              "/control/interactive"));
00225 
00226     // Print SLIC version info.
00227     addOption(new CommandLineOption("v",
00228                              "version",
00229                              "Print SLIC version.",
00230                              0,
00231                              0,
00232                              "/slic/version"));
00233 
00234     // Execute the commands from a macro file.
00235     addOption(new CommandLineOption("m",
00236                              "macro",
00237                              "Execute Geant4 commands from a file.",
00238                              1,
00239                              1,
00240                              "/control/execute"));
00241     
00242     // Set the URL of the input LCDD file. 
00243     addOption(new CommandLineOption("g",
00244                              "lcdd-url",
00245                              "Set LCDD geometry file URL.",
00246                              1,
00247                              1,
00248                              "/lcdd/url"));
00249 
00250     // Set the path to a generator file, e.g. StdHep or LCIO.
00251     addOption(new CommandLineOption("i",
00252                              "event-file",
00253                              "Set event input file full path.",
00254                              1,
00255                              1, 
00256                              "/generator/filename"));
00257 
00258     // Set the name of the LCIO output file. 
00259     addOption(new CommandLineOption("o",
00260                              "lcio-file",
00261                              "Set name of LCIO output file.",
00262                              1,
00263                              1,
00264                              "/lcio/filename"));
00265 
00266     // Set the path of output files. 
00267     addOption(new CommandLineOption("p",
00268                              "lcio-path",
00269                              "Set directory for LCIO output.",
00270                              1,
00271                              1,
00272                              "/lcio/path"));
00273     
00274     // Automatically name the LCIO output file.
00275     addOption(new CommandLineOption("O",
00276                              "autoname",
00277                              "Automatically name the LCIO output file.",
00278                              0,
00279                              1,
00280                              "/lcio/autoname"));
00281 
00282     // Overwrite an existing LCIO output file.
00283     addOption(new CommandLineOption("x",
00284                              "lcio-delete",
00285                              "Delete an existing LCIO file.",
00286                              0,
00287                              0,
00288                              "/lcio/fileExists delete"));
00289 
00290     // Number of events to run.
00291     addOption(new CommandLineOption("r",
00292                              "run-events",
00293                              "Run # of events.",
00294                              1,
00295                              1,
00296                              "/run/beamOn"));
00297 
00298     // Set number of events to skip from a file-based event source (e.g. StdHep).
00299     addOption(new CommandLineOption("s",
00300                              "skip-events",
00301                              "Set number of events to skip.",
00302                              1,
00303                              1,
00304                              "/generator/skipEvents"));
00305 
00306     // Set the physics list. 
00307     addOption(new CommandLineOption("l",
00308                              "physics-list",
00309                              "Set Geant4 physics list.",
00310                              1,
00311                              1,
00312                              "/physics/select"));
00313 
00314     // Set the name of the log file. 
00315     addOption(new CommandLineOption("L",
00316                              "log-file",
00317                              "Set logfile name.",
00318                              0,
00319                              0,
00320                              "/log/filename"));
00321     
00322     // Set the random seed.
00323     addOption(new CommandLineOption("d",
00324                              "seed",
00325                              "Set the random seed.  (No argument seeds with time.)",
00326                              0,
00327                              1,
00328                              "/random/seed"));
00329 
00330     // Dump the loaded Geant4 geometry to a GDML file.
00331     addOption(new CommandLineOption("G",
00332                              "dump-gdml",
00333                              "Dump geometry to GDML file.",
00334                              1,
00335                              1,
00336                              "/lcdd/dumpGDML"));
00337 
00338     // Enable optical physics processes.
00339     addOption(new CommandLineOption("c",
00340                                     "optical",
00341                                     "Enable optical physics processes.",
00342                                     0,
00343                                     0,
00344                                     "/physics/enableOptical"));
00345   }
00346 
00347   void CommandLineProcessor::processOption(const string& opt) 
00348   {      
00349     // Loop over all input arguments to look for this option.
00350     for ( CommandLineArguments::iterator it = m_commandline.begin();
00351           it != m_commandline.end();
00352           it++ ) {
00353 
00354       // Look for a matching switch in the arguments.
00355       if ( it->first == opt ) {
00356        
00357         // Get the associated specification for this option.
00358         CommandLineOption* cmdlineopt = getCommandLineOption(opt);
00359 
00360         // We must have a valid option!
00361         assert(cmdlineopt != 0);
00362 
00363         // Get the associated Geant4 command string.
00364         string cmdstr = cmdlineopt->getG4CommandString();
00365 
00366         // Add arguments to the command string, if some were passed.
00367         if ( it->second != "" ) {
00368           cmdstr += " ";
00369           cmdstr += it->second;
00370         }
00371 
00372         // Add the command string to the CommandQueue.
00373         m_g4q.add(cmdstr);
00374       }
00375     }
00376   }
00377 
00378   void CommandLineProcessor::addOption(CommandLineOption* opt)
00379   {
00380     m_cmds.push_back(opt);
00381   }   
00382 
00383   void CommandLineProcessor::processOptions()
00384   {
00385     // Logger.
00386     processOption("L");
00387 
00388     // Geometry file.
00389     processOption("g");
00390 
00391     // Optical processes.
00392     processOption("c");
00393 
00394     // Physics list.
00395     processOption("l");
00396     
00397     // Add initialization after geometry and physics,
00398     // but only if there was a geometry file argument.
00399     // Otherwise, initialize is not called, and the
00400     // user is given the PreInit prompt.
00401     if ( hasOption("g") ) {
00402       m_g4q.add("/run/initialize");
00403     }
00404     
00405     // Dump gdml.
00406     processOption("G");
00407 
00408     // Random seed.
00409     processOption("d");
00410 
00411     // Event file.
00412     processOption("i");
00413 
00414     // Output path.
00415     processOption("p");
00416 
00417     // Delete existing LCIO file.
00418     processOption("x");
00419 
00420     // Set LCIO file name.
00421     processOption("o");
00422 
00423     // Autoname the LCIO file.
00424     processOption("O");
00425 
00426     // Geant4 macro to run.
00427     processOption("m");
00428 
00429     // Events to skip.
00430     processOption("s");
00431 
00432     // Events to run.
00433     processOption("r");
00434     
00435     // Interactive mode, if selected.
00436     if (m_interactive_flag) {
00437       m_g4q.add("/control/interactive");
00438     }    
00439   }
00440 
00441   void CommandLineProcessor::printOptions()
00442   {
00443     log() << LOG::okay << "************************" << LOG::done;
00444     log() << LOG::okay << "* Command Line Options *" << LOG::done;
00445     log() << LOG::okay << "************************" << LOG::done;
00446     log() << LOG::okay << LOG::done;
00447 
00448     static const int opt_width = 8;
00449     static const int descr_width = 15;
00450     static const int name_width = 16;
00451     static const int cmd_width = 24;
00452     static const int sep_width = 60;
00453 
00454     log().getOutputStream().width(opt_width);
00455     log().getOutputStream() << left;
00456     
00457     log().getOutputStream() << left;
00458     log() << LOG::okay << "Option";
00459 
00460     log().getOutputStream().width(name_width);
00461     log().getOutputStream() << left;
00462     log() << LOG::okay << "Full Name";
00463 
00464     log().getOutputStream().width(cmd_width);
00465     log().getOutputStream() << left;
00466     log() << LOG::okay << "Macro Command";
00467 
00468     log().getOutputStream().width(descr_width);
00469     log().getOutputStream() << left;
00470     log() << LOG::okay << "Description";
00471 
00472     log().getOutputStream().fill('-');
00473     log().getOutputStream().width(sep_width);
00474 
00475     log() << LOG::okay << LOG::done;
00476     log() << LOG::okay << '-' << LOG::done;
00477 
00478     log().getOutputStream().fill(' ');
00479 
00480     for ( OptionsList::const_iterator iter = m_cmds.begin();
00481           iter != m_cmds.end();
00482           iter++ ) {
00483       CommandLineOption* cl_opt = (*iter);
00484 
00485       std::string opt_str = "-" + cl_opt->getShortName();
00486       log().getOutputStream().width(opt_width);
00487       log().getOutputStream() << left;
00488       log() << LOG::okay << opt_str;
00489 
00490       std::string name_str = "--" + cl_opt->getLongName();
00491       log().getOutputStream().width(name_width);
00492       log().getOutputStream() << left;
00493       log() << LOG::okay << name_str;
00494 
00495       log().getOutputStream().width(cmd_width);
00496       log().getOutputStream() << left;
00497       log() << LOG::okay << cl_opt->getG4CommandString();
00498 
00499       log().getOutputStream().width(descr_width);
00500       log().getOutputStream() << left;
00501       log() << LOG::okay << cl_opt->getDescription();
00502 
00503       log() << LOG::okay << LOG::done;
00504     }
00505   }
00506 
00507   CommandLineOption* CommandLineProcessor::getCommandLineOption(const std::string& opt)
00508   {
00509     CommandLineOption* clo = 0;
00510     for ( OptionsList::const_iterator iter = m_cmds.begin();
00511           iter != m_cmds.end();
00512           iter++ ) {
00513       if ( (*iter)->getShortName() == opt ) {
00514         clo = (*iter);
00515         break;
00516       }
00517     }
00518     return clo;
00519   }
00520 
00521   bool CommandLineProcessor::hasOption(const std::string& opt)
00522   {
00523     bool hasoption = false;
00524     for ( CommandLineArguments::iterator it = m_commandline.begin();
00525           it != m_commandline.end();
00526           it++ ) {
00527       if ( (*it).first == opt ) {
00528         hasoption=true;
00529         break;
00530       }
00531     }
00532     return hasoption;
00533   }
00534 
00535   void CommandLineProcessor::createOptionsString()
00536   {
00537     m_getoptOptions="";
00538     for ( OptionsList::iterator it = m_cmds.begin();
00539           it != m_cmds.end();
00540           it++ ) {
00541       CommandLineOption* opt = *it;
00542       m_getoptOptions += opt->getShortName();
00543       if ( opt->getMinArgs() ) {
00544         m_getoptOptions += ":";
00545       }
00546       else if ( opt->getMaxArgs() ) {
00547         m_getoptOptions += "::";
00548       }
00549     }
00550   }
00551 } // namespace slic

Generated on Thu Nov 15 15:24:15 2007 for Simulator for the Linear Collider by  doxygen 1.5.4