- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# CmdLine.h

Go to the documentation of this file.

    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 <tclap/SwitchArg.h>
    00028 #include <tclap/MultiSwitchArg.h>
    00029 #include <tclap/UnlabeledValueArg.h>
    00030 #include <tclap/UnlabeledMultiArg.h>
    00031
    00032 #include <tclap/XorHandler.h>
    00033 #include <tclap/HelpVisitor.h>
    00034 #include <tclap/VersionVisitor.h>
    00035 #include <tclap/IgnoreRestVisitor.h>
    00036
    00037 #include <tclap/CmdLineOutput.h>
    00038 #include <tclap/StdOutput.h>
    00039
    00040 #include <tclap/Constraint.h>
    00041 #include <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
    00070 class CmdLine : public CmdLineInterface
    00071 {
    00072     protected:
    00073
    00078         std::list<Arg*> _argList;
    00079
    00083         std::string _progName;
    00084
    00088         std::string _message;
    00089
    00093         std::string _version;
    00094
    00100         int _numRequired;
    00101
    00106         char _delimiter;
    00107
    00111         XorHandler _xorHandler;
    00112
    00118         std::list<Arg*> _argDeleteOnExitList;
    00119
    00125         std::list<Visitor*> _visitorDeleteOnExitList;
    00126
    00130         CmdLineOutput* _output;
    00131
    00135         bool _handleExceptions;
    00136
    00140         void missingArgsException();
    00141
    00148         bool _emptyCombined(const std::string& s);
    00149
    00153         void deleteOnExit(Arg* ptr);
    00154
    00158         void deleteOnExit(Visitor* ptr);
    00159
    00160 private:
    00161
    00165         CmdLine(const CmdLine& rhs);
    00166         CmdLine& operator=(const CmdLine& rhs);
    00167
    00172         void _constructor();
    00173
    00174
    00179         bool _userSetOutput;
    00180
    00184         bool _helpAndVersion;
    00185
    00186     public:
    00187
    00200         CmdLine(const std::string& message,
    00201                 const char delimiter = ' ',
    00202                 const std::string& version = "none",
    00203                 bool helpAndVersion = true);
    00204
    00208         virtual ~CmdLine();
    00209
    00214         void add( Arg& a );
    00215
    00220         void add( Arg* a );
    00221
    00228         void xorAdd( Arg& a, Arg& b );
    00229
    00235         void xorAdd( std::vector<Arg*>& xors );
    00236
    00242         void parse(int argc, const char * const * argv);
    00243
    00249         void parse(std::vector<std::string>& args);
    00250
    00254         CmdLineOutput* getOutput();
    00255
    00259         void setOutput(CmdLineOutput* co);
    00260
    00264         std::string& getVersion();
    00265
    00269         std::string& getProgramName();
    00270
    00274         std::list<Arg*>& getArgList();
    00275
    00279         XorHandler& getXorHandler();
    00280
    00284         char getDelimiter();
    00285
    00289         std::string& getMessage();
    00290
    00294         bool hasHelpAndVersion();
    00295
    00301         void setExceptionHandling(const bool state);
    00302
    00309         bool getExceptionHandling() const;
    00310
    00314         void reset();
    00315
    00316 };
    00317
    00318
    00320 //Begin CmdLine.cpp
    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
    00627 //End CmdLine.cpp
    00629
    00630
    00631
    00632 } //namespace TCLAP
    00633 #endif