CmdLineParser.h

Go to the documentation of this file.
00001 // ---------------------------------------------------------------------------
00002 // $Id: CmdLineParser.h 232 2008-08-15 18:19:35Z daaugusto $
00003 //
00004 //   CmdLineParser.h (created on Tue Aug 8 11:01:58 BRT 2006)
00005 // 
00006 //   Command-line Parser
00007 //
00008 //   Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
00009 // 
00010 // Command-line Parser is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU General Public License as published
00012 // by the Free Software Foundation; either version 3 of the License, or (at
00013 // your option) any later version.
00014 // 
00015 // Command-line Parser is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
00018 // Public License for more details.
00019 // 
00020 // You should have received a copy of the GNU General Public License along
00021 // with Command-line Parser; if not, see <http://www.gnu.org/licenses/>.
00022 //
00023 // ------------------------------------------------------------------------
00024 
00025 #ifndef cmd_line_parser_h
00026 #define cmd_line_parser_h
00027 
00288 #include <string>
00289 #include <sstream>
00290 #include <list>
00291 #include <limits>
00292 #include <map>
00293 #include <cstring>
00294 
00295 #include "CmdLineException.h"
00296 
00297 // ---------------------------------------------------------------------
00298 namespace CmdLine {
00299 
00301 typedef long double FLOAT;
00302 
00304 typedef long INT;
00305 
00307 enum { NONE = 0,         
00308        SILENT = 1,       
00309        OUT_OF_RANGE = 2, 
00311        NO_VALUE = 4,     
00314        DUPLICATE = 8,    
00316        FIRSTONLY = 16    
00318 };
00319 
00320 // ---------------------------------------------------------------------
00324 template<class T> class Option {
00325 public:
00326    Option( T def, T min, T max ) 
00327       : m_value( def ), m_min( min ), m_max( max ),
00328         m_found( false ), m_has_alias( false ), m_flags( 0 ) {}
00329 
00330 public:
00331    T m_value, 
00332      m_min, 
00333      m_max; 
00335    bool m_found; 
00337 public:
00344    bool IsSet( unsigned flag ) const { return m_flags & flag; }
00345 
00351    Option<T>& Set( unsigned flag ) { return m_flags |= flag, *this; }
00352    
00358    Option<T>& UnSet( unsigned flag ) { return m_flags &= ~flag, *this; }
00359 
00365    Option<T>& Flags( unsigned flag ) { return m_flags = flag, *this; }
00366 
00367 public:
00374    bool m_has_alias;
00375 private:
00376    unsigned m_flags; 
00378 };
00379 
00380 // ---------------------------------------------------------------------
00385 template <class T> class OptionsType {
00386 public:
00391    OptionsType( const class Parser& parser ): m_parser( parser ) {}
00392 
00396    typedef typename std::map<std::string, void*>::const_iterator CI;
00397 
00411    Option<T>& Add(const std::string& name, const std::string& alias="", 
00412                           T def=T(), T min=T(), T max=T() )
00413    {
00414       CheckOption( name, alias );
00415 
00416       void* tmp = new Option<T>( def, min, max );
00417       m_opts[name] = tmp;
00418 
00419       if( alias.size() > 0 ) // was provided an alias?
00420       {
00421          m_opts[alias] = tmp;
00422          static_cast<Option<T>*>( tmp )->m_has_alias = true;
00423       }
00424 
00425       return *static_cast<Option<T>*>( tmp );
00426    }
00427 
00436    T Get( const std::string& s ) const
00437    {
00438       const Option<T>* p = Find( s ); if( p ) return p->m_value;
00439 
00440       throw E_Exception("","Option "+s+" does not exist");
00441    }
00442 
00453    bool Get( const std::string& s, T& value ) const
00454    {
00455       const Option<T>* p = Find( s ); 
00456 
00457       if( p ) {
00458          value = p->m_value;
00459          return p->m_found;
00460       }
00461 
00462       throw E_Exception("","Option "+s+" does not exist");
00463    }
00464 
00470    template<class C> C Get( const std::string& s ) const
00471    {
00472       return static_cast<C>( Get( s ) );
00473    }
00474 
00477    template<class C> bool Get( const std::string& s, C& value ) const
00478    {
00479       const Option<T>* p = Find( s ); 
00480 
00481       if( p ) {
00482          value = static_cast<C>( p->m_value );
00483          return p->m_found;
00484       }
00485 
00486       throw E_Exception("","Option "+s+" does not exist");
00487    }
00488 
00498    bool Found( const std::string& s ) const
00499    {
00500       const Option<T>* p = Find( s ); if( p ) return p->m_found;
00501 
00502       throw E_Exception("","Option "+s+" does not exist");
00503    }
00504 
00505 public:
00510    const class Parser& m_parser;
00511 
00512 protected:
00518    virtual ~OptionsType()
00519    {
00520       for( CI p = m_opts.begin(); p != m_opts.end(); ++p )
00521       {
00522          if( Cast(p)->m_has_alias ) { Cast(p)->m_has_alias = false; continue; }
00523 
00524          delete Cast(p);
00525       }
00526    }
00527 
00531    void CheckOption( const std::string& name, const std::string& alias ) const
00532    {
00533       if( name[0] != '-' )
00534          throw E_Exception( "","Invalid option name: '"+name+"'" );
00535 
00536       if( alias.size() > 0 && alias[0] != '-' )
00537          throw E_Exception( "","Invalid option alias: '"+alias+"'" );
00538    }
00539 
00544    Option<T>* Cast( CI p ) const { return static_cast<Option<T>*>(p->second); }
00545 
00550    Option<T>* Find( const std::string& s ) const
00551    { 
00552       CI p = m_opts.find(s); return p != m_opts.end() ? Cast(p) : 0;
00553    }
00554 
00567    bool CheckDuplicate( const Option<T>* p, const std::string opt ) const
00568    {
00569       if( p->m_found ) // already declared before?
00570       {
00571          if( p->IsSet( DUPLICATE ) ) throw E_Duplicate( opt );
00572 
00573          if( !p->IsSet( SILENT ) )
00574             std::cerr << "> Option '" << opt 
00575                       << "' was declared more than once.\n";
00576 
00577          return !p->IsSet( FIRSTONLY );
00578       }
00579 
00580       return true; // ok, not declared before
00581    }
00582 
00583 private:
00588    std::map<std::string, void*> m_opts;
00589 };
00590 
00591 class Parser;
00592 
00593 // ---------------------------------------------------------------------
00597 class OptionsINT: public OptionsType<INT> {
00598 public:
00599    OptionsINT( const Parser& parser ): OptionsType<INT>( parser ) {}
00600    
00601    Option<INT>& Add( const std::string&, const std::string& = "", 
00602                      INT = 0, INT = std::numeric_limits<INT>::min(), 
00603                      INT = std::numeric_limits<INT>::max() );
00608    bool Match( int&, char**, int );
00609 
00610 };
00611 
00612 // ---------------------------------------------------------------------
00616 class OptionsFLOAT: public OptionsType<FLOAT> {
00617 public:
00618    OptionsFLOAT( const Parser& parser ): OptionsType<FLOAT>( parser ) {}
00619 
00620    Option<FLOAT>& Add( const std::string&, const std::string& = "", 
00621                        FLOAT = 0.0, FLOAT = std::numeric_limits<FLOAT>::min(), 
00622                        FLOAT = std::numeric_limits<FLOAT>::max() );
00623 
00628    bool Match( int&, char**, int );
00629 
00632    friend bool OptionsINT::Match( int&, char**, int );
00633 };
00634 
00635 // ---------------------------------------------------------------------
00639 class OptionsBOOL: public OptionsType<bool> {
00640 public:
00641    OptionsBOOL( const Parser& parser ): OptionsType<bool>( parser ) {}
00646    bool Match( int&, char**, int );
00647 };
00648 
00649 // ---------------------------------------------------------------------
00653 class OptionsCHAR: public OptionsType<char> {
00654 public:
00655    OptionsCHAR( const Parser& parser ): OptionsType<char>( parser ) {}
00656 
00686    Option<char>& Add( const std::string&, const std::string& = "", char =
00687                            '\0', const char* = 0, bool = false );
00688 
00707    bool Match( int&, char**, int );
00708 
00709 private:
00710    std::map<std::string, std::pair<const char*, bool> > m_ranges;
00711 };
00712 
00713 // ---------------------------------------------------------------------
00717 class OptionsSTRING: public OptionsType<std::string> {
00718 public:
00719    OptionsSTRING( const Parser& parser ): OptionsType<std::string>( parser ) {}
00720 
00729    Option<std::string>& Add( const std::string&, const std::string& = "", 
00730                              std::string = "", const char* first = 0, ... );
00731 
00736    bool Match( int&, char**, int );
00737 
00738 private:
00739    std::map<std::string, std::list<std::string> > m_ranges;
00740 };
00741 
00742 // ---------------------------------------------------------------------
00746 class Parser {
00747 public:
00758    Parser( int argc, char** argv, unsigned flags = 0 ): 
00759            Int( *this ), Float( *this ), Bool( *this ), Char( *this ), 
00760            String( *this ), m_argc( argc ), m_argv( argv ), m_flags( flags ) 
00761    { }
00762 
00769    int Process();
00770 
00794    template<class T> int Process( T& );
00795 
00802    bool IsSet( unsigned flag ) const { return m_flags & flag; }
00803 
00809    Parser& Set( unsigned flag ) { return m_flags |= flag, *this; }
00810    
00816    Parser& UnSet( unsigned flag ) { return m_flags &= ~flag, *this; }
00817 
00823    Parser& Flags( unsigned flag ) { return m_flags = flag, *this; }
00824 
00825 public:
00826    class OptionsINT Int; 
00827    class OptionsFLOAT Float; 
00828    class OptionsBOOL Bool; 
00829    class OptionsCHAR Char; 
00830    class OptionsSTRING String; 
00832    friend class OptionsINT;
00833    friend class OptionsFLOAT;
00834    friend class OptionsBOOL;
00835    friend class OptionsCHAR;
00836    friend class OptionsSTRING;
00837 private:
00838    int m_argc; 
00839    char** m_argv; 
00840    unsigned m_flags; 
00842 };
00843 
00844 // ---------------------------------------------------------------------
00845 template<class T> int Parser::Process( T& remains )
00846 {
00847    remains.clear(); int i = 1, matched = 0;
00848 
00849    while( i < m_argc )
00850    {
00851       if( !strcmp( m_argv[i], "--" ) ) break; // "--" stops the option processing
00852 
00853       if( m_argv[i][0] == '-' && ( Int.Match( i, m_argv, m_argc ) || 
00854           Float.Match( i, m_argv, m_argc ) || Bool.Match( i, m_argv, m_argc ) || 
00855           Char.Match( i, m_argv, m_argc ) || String.Match( i, m_argv, m_argc )) )
00856       {
00857          ++matched;
00858       }
00859       else remains.push_back( m_argv[i] ); // not a valid option
00860 
00861       ++i;
00862    }
00863 
00864    // only if encountered "--": do not process the remaining
00865    while( ++i < m_argc ) { remains.push_back( m_argv[i] ); }
00866 
00867    return matched;
00868 }
00869 
00870 // ---------------------------------------------------------------------
00871 } // end namespace CmdLine
00872 // ---------------------------------------------------------------------
00873 #endif