BASIS  version 1.2.3 (revision 2104)
CmdLine.h
00001 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
00002 
00003 /******************************************************************************
00004  *
00005  *  file:  CmdLine.h
00006  *
00007  *  Copyright (c) 2003, Michael E. Smoot .
00008  *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
00009  *  All rights reverved.
00010  *
00011  *  See the file COPYING in the top directory of this distribution for
00012  *  more information.
00013  *
00014  *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00017  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020  *  DEALINGS IN THE SOFTWARE.
00021  *
00022  *****************************************************************************/
00023 
00024 #ifndef TCLAP_CMDLINE_H
00025 #define TCLAP_CMDLINE_H
00026 
00027 #include <sbia/tclap/SwitchArg.h>
00028 #include <sbia/tclap/MultiSwitchArg.h>
00029 #include <sbia/tclap/UnlabeledValueArg.h>
00030 #include <sbia/tclap/UnlabeledMultiArg.h>
00031 
00032 #include <sbia/tclap/XorHandler.h>
00033 #include <sbia/tclap/HelpVisitor.h>
00034 #include <sbia/tclap/VersionVisitor.h>
00035 #include <sbia/tclap/IgnoreRestVisitor.h>
00036 
00037 #include <sbia/tclap/CmdLineOutput.h>
00038 #include <sbia/tclap/StdOutput.h>
00039 
00040 #include <sbia/tclap/Constraint.h>
00041 #include <sbia/tclap/ValuesConstraint.h>
00042 
00043 #include <string>
00044 #include <vector>
00045 #include <list>
00046 #include <iostream>
00047 #include <iomanip>
00048 #include <algorithm>
00049 #include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
00050 
00051 namespace TCLAP {
00052 
00053 template<typename T> void DelPtr(T ptr)
00054 {
00055     delete ptr;
00056 }
00057 
00058 template<typename C> void ClearContainer(C &c)
00059 {
00060     typedef typename C::value_type value_type;
00061     std::for_each(c.begin(), c.end(), DelPtr<value_type>);
00062     c.clear();
00063 }
00064 
00065 
00066 /**
00067  * The base class that manages the command line definition and passes
00068  * along the parsing to the appropriate Arg classes.
00069  */
00070 class CmdLine : public CmdLineInterface
00071 {
00072     protected:
00073 
00074         /**
00075          * The list of arguments that will be tested against the
00076          * command line.
00077          */
00078         std::list<Arg*> _argList;
00079 
00080         /**
00081          * The name of the program.  Set to argv[0].
00082          */
00083         std::string _progName;
00084 
00085         /**
00086          * A message used to describe the program.  Used in the usage output.
00087          */
00088         std::string _message;
00089 
00090         /**
00091          * The version to be displayed with the --version switch.
00092          */
00093         std::string _version;
00094 
00095         /**
00096          * The number of arguments that are required to be present on
00097          * the command line. This is set dynamically, based on the
00098          * Args added to the CmdLine object.
00099          */
00100         int _numRequired;
00101 
00102         /**
00103          * The character that is used to separate the argument flag/name
00104          * from the value.  Defaults to ' ' (space).
00105          */
00106         char _delimiter;
00107 
00108         /**
00109          * The handler that manages xoring lists of args.
00110          */
00111         XorHandler _xorHandler;
00112 
00113         /**
00114          * A list of Args to be explicitly deleted when the destructor
00115          * is called.  At the moment, this only includes the three default
00116          * Args.
00117          */
00118         std::list<Arg*> _argDeleteOnExitList;
00119 
00120         /**
00121          * A list of Visitors to be explicitly deleted when the destructor
00122          * is called.  At the moment, these are the Vistors created for the
00123          * default Args.
00124          */
00125         std::list<Visitor*> _visitorDeleteOnExitList;
00126 
00127         /**
00128          * Object that handles all output for the CmdLine.
00129          */
00130         CmdLineOutput* _output;
00131 
00132         /**
00133          * Should CmdLine handle parsing exceptions internally?
00134          */
00135         bool _handleExceptions;
00136 
00137         /**
00138          * Throws an exception listing the missing args.
00139          */
00140         void missingArgsException();
00141 
00142         /**
00143          * Checks whether a name/flag string matches entirely matches
00144          * the Arg::blankChar.  Used when multiple switches are combined
00145          * into a single argument.
00146          * \param s - The message to be used in the usage.
00147          */
00148         bool _emptyCombined(const std::string& s);
00149 
00150         /**
00151          * Perform a delete ptr; operation on ptr when this object is deleted.
00152          */
00153         void deleteOnExit(Arg* ptr);
00154 
00155         /**
00156          * Perform a delete ptr; operation on ptr when this object is deleted.
00157          */
00158         void deleteOnExit(Visitor* ptr);
00159 
00160 private:
00161 
00162         /**
00163          * Prevent accidental copying.
00164          */
00165         CmdLine(const CmdLine& rhs);
00166         CmdLine& operator=(const CmdLine& rhs);
00167 
00168         /**
00169          * Encapsulates the code common to the constructors
00170          * (which is all of it).
00171          */
00172         void _constructor();
00173 
00174 
00175         /**
00176          * Is set to true when a user sets the output object. We use this so
00177          * that we don't delete objects that are created outside of this lib.
00178          */
00179         bool _userSetOutput;
00180 
00181         /**
00182          * Whether or not to automatically create help and version switches.
00183          */
00184         bool _helpAndVersion;
00185 
00186     public:
00187 
00188         /**
00189          * Command line constructor. Defines how the arguments will be
00190          * parsed.
00191          * \param message - The message to be used in the usage
00192          * output.
00193          * \param delimiter - The character that is used to separate
00194          * the argument flag/name from the value.  Defaults to ' ' (space).
00195          * \param version - The version number to be used in the
00196          * --version switch.
00197          * \param helpAndVersion - Whether or not to create the Help and
00198          * Version switches. Defaults to true.
00199          */
00200         CmdLine(const std::string& message,
00201                 const char delimiter = ' ',
00202                 const std::string& version = "none",
00203                 bool helpAndVersion = true);
00204 
00205         /**
00206          * Deletes any resources allocated by a CmdLine object.
00207          */
00208         virtual ~CmdLine();
00209 
00210         /**
00211          * Adds an argument to the list of arguments to be parsed.
00212          * \param a - Argument to be added.
00213          */
00214         void add( Arg& a );
00215 
00216         /**
00217          * An alternative add.  Functionally identical.
00218          * \param a - Argument to be added.
00219          */
00220         void add( Arg* a );
00221 
00222         /**
00223          * Add two Args that will be xor'd.  If this method is used, add does
00224          * not need to be called.
00225          * \param a - Argument to be added and xor'd.
00226          * \param b - Argument to be added and xor'd.
00227          */
00228         void xorAdd( Arg& a, Arg& b );
00229 
00230         /**
00231          * Add a list of Args that will be xor'd.  If this method is used,
00232          * add does not need to be called.
00233          * \param xors - List of Args to be added and xor'd.
00234          */
00235         void xorAdd( std::vector<Arg*>& xors );
00236 
00237         /**
00238          * Parses the command line.
00239          * \param argc - Number of arguments.
00240          * \param argv - Array of arguments.
00241          */
00242         void parse(int argc, const char * const * argv);
00243 
00244         /**
00245          * Parses the command line.
00246          * \param args - A vector of strings representing the args.
00247          * args[0] is still the program name.
00248          */
00249         void parse(std::vector<std::string>& args);
00250 
00251         /**
00252          *
00253          */
00254         CmdLineOutput* getOutput();
00255 
00256         /**
00257          *
00258          */
00259         void setOutput(CmdLineOutput* co);
00260 
00261         /**
00262          *
00263          */
00264         std::string& getVersion();
00265 
00266         /**
00267          *
00268          */
00269         std::string& getProgramName();
00270 
00271         /**
00272          *
00273          */
00274         std::list<Arg*>& getArgList();
00275 
00276         /**
00277          *
00278          */
00279         XorHandler& getXorHandler();
00280 
00281         /**
00282          *
00283          */
00284         char getDelimiter();
00285 
00286         /**
00287          *
00288          */
00289         std::string& getMessage();
00290 
00291         /**
00292          *
00293          */
00294         bool hasHelpAndVersion();
00295 
00296         /**
00297          * Disables or enables CmdLine's internal parsing exception handling.
00298          *
00299          * @param state Should CmdLine handle parsing exceptions internally?
00300          */
00301         void setExceptionHandling(const bool state);
00302 
00303         /**
00304          * Returns the current state of the internal exception handling.
00305          *
00306          * @retval true Parsing exceptions are handled internally.
00307          * @retval false Parsing exceptions are propagated to the caller.
00308          */
00309         bool getExceptionHandling() const;
00310 
00311         /**
00312          * Allows the CmdLine object to be reused.
00313          */
00314         void reset();
00315 
00316 };
00317 
00318 
00319 ///////////////////////////////////////////////////////////////////////////////
00320 //Begin CmdLine.cpp
00321 ///////////////////////////////////////////////////////////////////////////////
00322 
00323 inline CmdLine::CmdLine(const std::string& m,
00324                         char delim,
00325                         const std::string& v,
00326                         bool help )
00327     :
00328   _argList(std::list<Arg*>()),
00329   _progName("not_set_yet"),
00330   _message(m),
00331   _version(v),
00332   _numRequired(0),
00333   _delimiter(delim),
00334   _xorHandler(XorHandler()),
00335   _argDeleteOnExitList(std::list<Arg*>()),
00336   _visitorDeleteOnExitList(std::list<Visitor*>()),
00337   _output(0),
00338   _handleExceptions(true),
00339   _userSetOutput(false),
00340   _helpAndVersion(help)
00341 {
00342     _constructor();
00343 }
00344 
00345 inline CmdLine::~CmdLine()
00346 {
00347     ClearContainer(_argDeleteOnExitList);
00348     ClearContainer(_visitorDeleteOnExitList);
00349 
00350     if ( !_userSetOutput ) {
00351         delete _output;
00352         _output = 0;
00353     }
00354 }
00355 
00356 inline void CmdLine::_constructor()
00357 {
00358     _output = new StdOutput;
00359 
00360     Arg::setDelimiter( _delimiter );
00361 
00362     Visitor* v;
00363 
00364     if ( _helpAndVersion )
00365     {
00366         v = new HelpVisitor( this, &_output );
00367         SwitchArg* help = new SwitchArg("h","help",
00368                               "Displays usage information and exits.",
00369                               false, v);
00370         add( help );
00371         deleteOnExit(help);
00372         deleteOnExit(v);
00373 
00374         v = new VersionVisitor( this, &_output );
00375         SwitchArg* vers = new SwitchArg("","version",
00376                               "Displays version information and exits.",
00377                               false, v);
00378         add( vers );
00379         deleteOnExit(vers);
00380         deleteOnExit(v);
00381     }
00382 
00383     v = new IgnoreRestVisitor();
00384     SwitchArg* ignore  = new SwitchArg(Arg::flagStartString(),
00385               Arg::ignoreNameString(),
00386               "Ignores the rest of the labeled arguments following this flag.",
00387               false, v);
00388     add( ignore );
00389     deleteOnExit(ignore);
00390     deleteOnExit(v);
00391 }
00392 
00393 inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
00394 {
00395     _xorHandler.add( ors );
00396 
00397     for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
00398     {
00399         (*it)->forceRequired();
00400         (*it)->setRequireLabel( "OR required" );
00401         add( *it );
00402     }
00403 }
00404 
00405 inline void CmdLine::xorAdd( Arg& a, Arg& b )
00406 {
00407     std::vector<Arg*> ors;
00408     ors.push_back( &a );
00409     ors.push_back( &b );
00410     xorAdd( ors );
00411 }
00412 
00413 inline void CmdLine::add( Arg& a )
00414 {
00415     add( &a );
00416 }
00417 
00418 inline void CmdLine::add( Arg* a )
00419 {
00420     for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
00421         if ( *a == *(*it) )
00422             throw( SpecificationException(
00423                     "Argument with same flag/name already exists!",
00424                     a->longID() ) );
00425 
00426     a->addToList( _argList );
00427 
00428     if ( a->isRequired() )
00429         _numRequired++;
00430 }
00431 
00432 
00433 inline void CmdLine::parse(int argc, const char * const * argv)
00434 {
00435         // this step is necessary so that we have easy access to
00436         // mutable strings.
00437         std::vector<std::string> args;
00438         for (int i = 0; i < argc; i++)
00439             args.push_back(argv[i]);
00440 
00441         parse(args);
00442 }
00443 
00444 inline void CmdLine::parse(std::vector<std::string>& args)
00445 {
00446     bool shouldExit = false;
00447     int estat = 0;
00448 
00449     try {
00450         _progName = args.front();
00451         args.erase(args.begin());
00452 
00453         int requiredCount = 0;
00454 
00455         for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) 
00456         {
00457             bool matched = false;
00458             for (ArgListIterator it = _argList.begin();
00459                  it != _argList.end(); it++) {
00460                 if ( (*it)->processArg( &i, args ) )
00461                 {
00462                     requiredCount += _xorHandler.check( *it );
00463                     matched = true;
00464                     break;
00465                 }
00466             }
00467 
00468             // checks to see if the argument is an empty combined
00469             // switch and if so, then we've actually matched it
00470             if ( !matched && _emptyCombined( args[i] ) )
00471                 matched = true;
00472 
00473             if ( !matched && !Arg::ignoreRest() )
00474                 throw(CmdLineParseException("Couldn't find match "
00475                                             "for argument",
00476                                             args[i]));
00477         }
00478 
00479         if ( requiredCount < _numRequired )
00480             missingArgsException();
00481 
00482         if ( requiredCount > _numRequired )
00483             throw(CmdLineParseException("Too many arguments!"));
00484 
00485     } catch ( ArgException& e ) {
00486         // If we're not handling the exceptions, rethrow.
00487         if ( !_handleExceptions) {
00488             throw;
00489         }
00490 
00491         try {
00492             _output->failure(*this,e);
00493         } catch ( ExitException &ee ) {
00494             estat = ee.getExitStatus();
00495             shouldExit = true;
00496         }
00497     } catch (ExitException &ee) {
00498         // If we're not handling the exceptions, rethrow.
00499         if ( !_handleExceptions) {
00500             throw;
00501         }
00502 
00503         estat = ee.getExitStatus();
00504         shouldExit = true;
00505     }
00506 
00507     if (shouldExit)
00508         exit(estat);
00509 }
00510 
00511 inline bool CmdLine::_emptyCombined(const std::string& s)
00512 {
00513     if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
00514         return false;
00515 
00516     for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
00517         if ( s[i] != Arg::blankChar() )
00518             return false;
00519 
00520     return true;
00521 }
00522 
00523 inline void CmdLine::missingArgsException()
00524 {
00525         int count = 0;
00526 
00527         std::string missingArgList;
00528         for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
00529         {
00530             if ( (*it)->isRequired() && !(*it)->isSet() )
00531             {
00532                 missingArgList += (*it)->getName();
00533                 missingArgList += ", ";
00534                 count++;
00535             }
00536         }
00537         missingArgList = missingArgList.substr(0,missingArgList.length()-2);
00538 
00539         std::string msg;
00540         if ( count > 1 )
00541             msg = "Required arguments missing: ";
00542         else
00543             msg = "Required argument missing: ";
00544 
00545         msg += missingArgList;
00546 
00547         throw(CmdLineParseException(msg));
00548 }
00549 
00550 inline void CmdLine::deleteOnExit(Arg* ptr)
00551 {
00552     _argDeleteOnExitList.push_back(ptr);
00553 }
00554 
00555 inline void CmdLine::deleteOnExit(Visitor* ptr)
00556 {
00557     _visitorDeleteOnExitList.push_back(ptr);
00558 }
00559 
00560 inline CmdLineOutput* CmdLine::getOutput()
00561 {
00562     return _output;
00563 }
00564 
00565 inline void CmdLine::setOutput(CmdLineOutput* co)
00566 {
00567     if ( !_userSetOutput )
00568         delete _output;
00569     _userSetOutput = true;
00570     _output = co;
00571 }
00572 
00573 inline std::string& CmdLine::getVersion()
00574 {
00575     return _version;
00576 }
00577 
00578 inline std::string& CmdLine::getProgramName()
00579 {
00580     return _progName;
00581 }
00582 
00583 inline std::list<Arg*>& CmdLine::getArgList()
00584 {
00585     return _argList;
00586 }
00587 
00588 inline XorHandler& CmdLine::getXorHandler()
00589 {
00590     return _xorHandler;
00591 }
00592 
00593 inline char CmdLine::getDelimiter()
00594 {
00595     return _delimiter;
00596 }
00597 
00598 inline std::string& CmdLine::getMessage()
00599 {
00600     return _message;
00601 }
00602 
00603 inline bool CmdLine::hasHelpAndVersion()
00604 {
00605     return _helpAndVersion;
00606 }
00607 
00608 inline void CmdLine::setExceptionHandling(const bool state)
00609 {
00610     _handleExceptions = state;
00611 }
00612 
00613 inline bool CmdLine::getExceptionHandling() const
00614 {
00615     return _handleExceptions;
00616 }
00617 
00618 inline void CmdLine::reset()
00619 {
00620     for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
00621         (*it)->reset();
00622     
00623     _progName.clear();
00624 }
00625 
00626 ///////////////////////////////////////////////////////////////////////////////
00627 //End CmdLine.cpp
00628 ///////////////////////////////////////////////////////////////////////////////
00629 
00630 
00631 
00632 } //namespace TCLAP
00633 #endif