From 2cbc634b3b603ec67c6c312bd18177cd52c71b63 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 18 Dec 2009 16:07:31 +0000 Subject: Ok...sweet, the OptParser now supports everything the old one did, but in much less code, and it does everything with more style and panache, also fewer bugs. --- src/optparser.cpp | 112 +++++++++++++++++++++++++++++++----------------- src/optparser.h | 29 +++++++++++-- src/tests/optparser.cpp | 8 ++++ 3 files changed, 106 insertions(+), 43 deletions(-) diff --git a/src/optparser.cpp b/src/optparser.cpp index d656e12..14e7418 100644 --- a/src/optparser.cpp +++ b/src/optparser.cpp @@ -21,7 +21,6 @@ void Bu::OptParser::parse( int argc, char **argv ) // Now we're on to something, which kind is it? if( argv[j][1] == '-' ) { - // Long param, cool, that's easy, first search for = int iEPos; for( iEPos = 2; argv[j][iEPos] != '\0' && argv[j][iEPos] != '='; iEPos++ ) { } @@ -39,36 +38,44 @@ void Bu::OptParser::parse( int argc, char **argv ) { sOpt.set( argv[j]+2 ); } - Option *pOpt = hlOption.get( sOpt ); - if( pOpt->sUsed ) + try { - Bu::StrArray aParams( iCount ); - aParams.append( sOpt ); - if( sExtraParam ) + // Long param, cool, that's easy, first search for = + Option *pOpt = hlOption.get( sOpt ); + if( pOpt->sUsed ) { - aParams.append( argv[j]+iEPos+1 ); + Bu::StrArray aParams( iCount ); + aParams.append( sOpt ); + if( sExtraParam ) + { + aParams.append( argv[j]+iEPos+1 ); + } + for( int k = j+1; k < argc; k++ ) + { + aParams.append( argv[k] ); + } + j += pOpt->sUsed( aParams ); } - for( int k = j+1; k < argc; k++ ) + else if( pOpt->pProxy ) { - aParams.append( argv[k] ); + if( pOpt->sOverride ) + { + pOpt->pProxy->setValue( pOpt->sOverride ); + } + else if( sExtraParam ) + { + pOpt->pProxy->setValue( sExtraParam ); + } + else if( argv[j+1] != '\0' ) + { + pOpt->pProxy->setValue( argv[j+1] ); + j++; + } } - j += pOpt->sUsed( aParams ); } - else if( pOpt->pProxy ) + catch( Bu::HashException &e ) { - if( pOpt->sOverride ) - { - pOpt->pProxy->setValue( pOpt->sOverride ); - } - else if( sExtraParam ) - { - pOpt->pProxy->setValue( sExtraParam ); - } - else if( argv[j+1] != '\0' ) - { - pOpt->pProxy->setValue( argv[j+1] ); - j++; - } + optionError( "--" + sOpt ); } } else @@ -76,22 +83,30 @@ void Bu::OptParser::parse( int argc, char **argv ) int iCPos; for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ ) { - Option *pOpt = hsOption.get( argv[j][iCPos] ); - char buf[2] = {argv[j][iCPos], '\0'}; - if( pOpt->bShortHasParams ) + try { + Option *pOpt = hsOption.get( argv[j][iCPos] ); + char buf[2] = {argv[j][iCPos], '\0'}; if( pOpt->sUsed ) { Bu::StrArray aParams( argc-j+1 ); aParams.append( buf ); + int iMod = 0; if( argv[j][iCPos+1] != '\0' ) + { aParams.append( argv[j]+iCPos+1 ); + iMod = -1; + } for( int k = j+1; k < argc; k++ ) { aParams.append( argv[k] ); } - j += pOpt->sUsed( aParams ); - break; + int iUsed = pOpt->sUsed( aParams ); + if( iUsed > 0 ) + { + j += iUsed + iMod; + break; + } } else if( pOpt->pProxy ) { @@ -116,20 +131,31 @@ void Bu::OptParser::parse( int argc, char **argv ) } } } - else + catch( Bu::HashException &e ) { - if( pOpt->sUsed ) - { - Bu::StrArray aParam( 1 ); - aParam.append( buf ); - pOpt->sUsed( aParam ); - } + Bu::FString sOpt("-"); + sOpt += argv[j][iCPos]; + optionError( sOpt ); } } } } else { + if( !sNonOption ) + { + optionError( argv[j] ); + } + else + { + int iCount = argc-j; + Bu::StrArray aParams( iCount ); + for( int k = j; k < argc; k++ ) + { + aParams.append( argv[k] ); + } + j += sNonOption( aParams ); + } } } } @@ -160,7 +186,6 @@ void Bu::OptParser::addHelpOption( char c, const Bu::FString &s, const Bu::FStri o.cOpt = c; o.sOpt = s; o.sHelp = sHelp; - o.bShortHasParams = false; addOption( o ); } @@ -251,6 +276,17 @@ int Bu::OptParser::optHelp( StrArray /*aParams*/ ) return 0; } +void Bu::OptParser::optionError( const Bu::FString sOption ) +{ + sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl; + exit( 1 ); +} + +void Bu::OptParser::setNonOption( OptionSignal sSignal ) +{ + sNonOption = sSignal; +} + Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, int iIndent ) { @@ -358,7 +394,6 @@ Bu::OptParser::_ValueProxy::~_ValueProxy() Bu::OptParser::Option::Option() : cOpt( '\0' ), - bShortHasParams( false ), pProxy( NULL ) { } @@ -368,7 +403,6 @@ Bu::OptParser::Option::Option( const Option &rSrc ) : sOpt( rSrc.sOpt ), sHelp( rSrc.sHelp ), sUsed( rSrc.sUsed ), - bShortHasParams( rSrc.bShortHasParams ), pProxy( NULL ), sOverride( rSrc.sOverride ) { diff --git a/src/optparser.h b/src/optparser.h index 425bc90..89ef14d 100644 --- a/src/optparser.h +++ b/src/optparser.h @@ -12,6 +12,18 @@ namespace Bu { typedef Bu::Array StrArray; + + /** + * POSIX/Gnu style command line parser. Handles long and short options in + * a variety of fun and useful ways, along with singal based callbacks and + * automatic variable setting. It's pretty easy to use, and very flexible. + * + * OptParser supports it's own builtin help mechanism which automatically + * enumerates the available options and their help in a well formatted and + * easy to read way, automatically formatting your help text per option and + * allows for addition "help banners" which can be placed wherever you + * would like. + */ class OptParser { private: @@ -67,7 +79,6 @@ namespace Bu Bu::FString sOpt; Bu::FString sHelp; OptionSignal sUsed; - bool bShortHasParams; _ValueProxy *pProxy; Bu::FString sOverride; }; @@ -103,7 +114,6 @@ namespace Bu o.cOpt = cOpt; o.sOpt = sOpt; o.pProxy = new ValueProxy( var ); - o.bShortHasParams = true; o.sHelp = sHelp; addOption( o ); } @@ -148,14 +158,24 @@ namespace Bu void setOverride( const Bu::FString &sOpt, const Bu::FString &sOverride ); -// void addOption( char cOpt, const Bu::FString &sOpt, - void addHelpOption( char c='h', const Bu::FString &s="help", const Bu::FString &sHelp="This help." ); void addHelpBanner( const Bu::FString &sText, bool bFormatted=true ); int optHelp( StrArray aParams ); + /** + * This function is called when an unrecognized option is found, the + * default behaviour is to print an error to stdout and exit( 1 ), if + * you want to do something different, just override this function. + * This is also called by default when something is found that hasn't + * been handled by an option, and isn't an option (starts with - or --). + * To change this behaviour call + */ + virtual void optionError( const Bu::FString sOption ); + + void setNonOption( OptionSignal sSignal ); + private: Bu::FString format( const Bu::FString &sIn, int iWidth, int iIndent ); @@ -163,6 +183,7 @@ namespace Bu ShortOptionHash hsOption; LongOptionHash hlOption; BannerList lBanner; + OptionSignal sNonOption; }; }; diff --git a/src/tests/optparser.cpp b/src/tests/optparser.cpp index f5df7ed..5c91351 100644 --- a/src/tests/optparser.cpp +++ b/src/tests/optparser.cpp @@ -40,6 +40,8 @@ public: setOverride("str", "Bob!"); addHelpOption(); + + setNonOption( slot( this, &Opts::nonOption ) ); } int yesparam( StrArray aParams ) @@ -54,6 +56,12 @@ public: return 0; } + int nonOption( StrArray aParams ) + { + sio << " - nonOption" << aParams << sio.nl; + return aParams.getSize()-1; + } + int iBob; float dBob; Bu::FString sVar; -- cgit v1.2.3