00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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 )
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 )
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;
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;
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] );
00860
00861 ++i;
00862 }
00863
00864
00865 while( ++i < m_argc ) { remains.push_back( m_argv[i] ); }
00866
00867 return matched;
00868 }
00869
00870
00871 }
00872
00873 #endif