diff options
| -rw-r--r-- | src/optparser.cpp | 112 | ||||
| -rw-r--r-- | src/optparser.h | 29 | ||||
| -rw-r--r-- | 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 ) | |||
| 21 | // Now we're on to something, which kind is it? | 21 | // Now we're on to something, which kind is it? |
| 22 | if( argv[j][1] == '-' ) | 22 | if( argv[j][1] == '-' ) |
| 23 | { | 23 | { |
| 24 | // Long param, cool, that's easy, first search for = | ||
| 25 | int iEPos; | 24 | int iEPos; |
| 26 | for( iEPos = 2; argv[j][iEPos] != '\0' && | 25 | for( iEPos = 2; argv[j][iEPos] != '\0' && |
| 27 | argv[j][iEPos] != '='; iEPos++ ) { } | 26 | argv[j][iEPos] != '='; iEPos++ ) { } |
| @@ -39,36 +38,44 @@ void Bu::OptParser::parse( int argc, char **argv ) | |||
| 39 | { | 38 | { |
| 40 | sOpt.set( argv[j]+2 ); | 39 | sOpt.set( argv[j]+2 ); |
| 41 | } | 40 | } |
| 42 | Option *pOpt = hlOption.get( sOpt ); | 41 | try |
| 43 | if( pOpt->sUsed ) | ||
| 44 | { | 42 | { |
| 45 | Bu::StrArray aParams( iCount ); | 43 | // Long param, cool, that's easy, first search for = |
| 46 | aParams.append( sOpt ); | 44 | Option *pOpt = hlOption.get( sOpt ); |
| 47 | if( sExtraParam ) | 45 | if( pOpt->sUsed ) |
| 48 | { | 46 | { |
| 49 | aParams.append( argv[j]+iEPos+1 ); | 47 | Bu::StrArray aParams( iCount ); |
| 48 | aParams.append( sOpt ); | ||
| 49 | if( sExtraParam ) | ||
| 50 | { | ||
| 51 | aParams.append( argv[j]+iEPos+1 ); | ||
| 52 | } | ||
| 53 | for( int k = j+1; k < argc; k++ ) | ||
| 54 | { | ||
| 55 | aParams.append( argv[k] ); | ||
| 56 | } | ||
| 57 | j += pOpt->sUsed( aParams ); | ||
| 50 | } | 58 | } |
| 51 | for( int k = j+1; k < argc; k++ ) | 59 | else if( pOpt->pProxy ) |
| 52 | { | 60 | { |
| 53 | aParams.append( argv[k] ); | 61 | if( pOpt->sOverride ) |
| 62 | { | ||
| 63 | pOpt->pProxy->setValue( pOpt->sOverride ); | ||
| 64 | } | ||
| 65 | else if( sExtraParam ) | ||
| 66 | { | ||
| 67 | pOpt->pProxy->setValue( sExtraParam ); | ||
| 68 | } | ||
| 69 | else if( argv[j+1] != '\0' ) | ||
| 70 | { | ||
| 71 | pOpt->pProxy->setValue( argv[j+1] ); | ||
| 72 | j++; | ||
| 73 | } | ||
| 54 | } | 74 | } |
| 55 | j += pOpt->sUsed( aParams ); | ||
| 56 | } | 75 | } |
| 57 | else if( pOpt->pProxy ) | 76 | catch( Bu::HashException &e ) |
| 58 | { | 77 | { |
| 59 | if( pOpt->sOverride ) | 78 | optionError( "--" + sOpt ); |
| 60 | { | ||
| 61 | pOpt->pProxy->setValue( pOpt->sOverride ); | ||
| 62 | } | ||
| 63 | else if( sExtraParam ) | ||
| 64 | { | ||
| 65 | pOpt->pProxy->setValue( sExtraParam ); | ||
| 66 | } | ||
| 67 | else if( argv[j+1] != '\0' ) | ||
| 68 | { | ||
| 69 | pOpt->pProxy->setValue( argv[j+1] ); | ||
| 70 | j++; | ||
| 71 | } | ||
| 72 | } | 79 | } |
| 73 | } | 80 | } |
| 74 | else | 81 | else |
| @@ -76,22 +83,30 @@ void Bu::OptParser::parse( int argc, char **argv ) | |||
| 76 | int iCPos; | 83 | int iCPos; |
| 77 | for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ ) | 84 | for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ ) |
| 78 | { | 85 | { |
| 79 | Option *pOpt = hsOption.get( argv[j][iCPos] ); | 86 | try |
| 80 | char buf[2] = {argv[j][iCPos], '\0'}; | ||
| 81 | if( pOpt->bShortHasParams ) | ||
| 82 | { | 87 | { |
| 88 | Option *pOpt = hsOption.get( argv[j][iCPos] ); | ||
| 89 | char buf[2] = {argv[j][iCPos], '\0'}; | ||
| 83 | if( pOpt->sUsed ) | 90 | if( pOpt->sUsed ) |
| 84 | { | 91 | { |
| 85 | Bu::StrArray aParams( argc-j+1 ); | 92 | Bu::StrArray aParams( argc-j+1 ); |
| 86 | aParams.append( buf ); | 93 | aParams.append( buf ); |
| 94 | int iMod = 0; | ||
| 87 | if( argv[j][iCPos+1] != '\0' ) | 95 | if( argv[j][iCPos+1] != '\0' ) |
| 96 | { | ||
| 88 | aParams.append( argv[j]+iCPos+1 ); | 97 | aParams.append( argv[j]+iCPos+1 ); |
| 98 | iMod = -1; | ||
| 99 | } | ||
| 89 | for( int k = j+1; k < argc; k++ ) | 100 | for( int k = j+1; k < argc; k++ ) |
| 90 | { | 101 | { |
| 91 | aParams.append( argv[k] ); | 102 | aParams.append( argv[k] ); |
| 92 | } | 103 | } |
| 93 | j += pOpt->sUsed( aParams ); | 104 | int iUsed = pOpt->sUsed( aParams ); |
| 94 | break; | 105 | if( iUsed > 0 ) |
| 106 | { | ||
| 107 | j += iUsed + iMod; | ||
| 108 | break; | ||
| 109 | } | ||
| 95 | } | 110 | } |
| 96 | else if( pOpt->pProxy ) | 111 | else if( pOpt->pProxy ) |
| 97 | { | 112 | { |
| @@ -116,20 +131,31 @@ void Bu::OptParser::parse( int argc, char **argv ) | |||
| 116 | } | 131 | } |
| 117 | } | 132 | } |
| 118 | } | 133 | } |
| 119 | else | 134 | catch( Bu::HashException &e ) |
| 120 | { | 135 | { |
| 121 | if( pOpt->sUsed ) | 136 | Bu::FString sOpt("-"); |
| 122 | { | 137 | sOpt += argv[j][iCPos]; |
| 123 | Bu::StrArray aParam( 1 ); | 138 | optionError( sOpt ); |
| 124 | aParam.append( buf ); | ||
| 125 | pOpt->sUsed( aParam ); | ||
| 126 | } | ||
| 127 | } | 139 | } |
| 128 | } | 140 | } |
| 129 | } | 141 | } |
| 130 | } | 142 | } |
| 131 | else | 143 | else |
| 132 | { | 144 | { |
| 145 | if( !sNonOption ) | ||
| 146 | { | ||
| 147 | optionError( argv[j] ); | ||
| 148 | } | ||
| 149 | else | ||
| 150 | { | ||
| 151 | int iCount = argc-j; | ||
| 152 | Bu::StrArray aParams( iCount ); | ||
| 153 | for( int k = j; k < argc; k++ ) | ||
| 154 | { | ||
| 155 | aParams.append( argv[k] ); | ||
| 156 | } | ||
| 157 | j += sNonOption( aParams ); | ||
| 158 | } | ||
| 133 | } | 159 | } |
| 134 | } | 160 | } |
| 135 | } | 161 | } |
| @@ -160,7 +186,6 @@ void Bu::OptParser::addHelpOption( char c, const Bu::FString &s, const Bu::FStri | |||
| 160 | o.cOpt = c; | 186 | o.cOpt = c; |
| 161 | o.sOpt = s; | 187 | o.sOpt = s; |
| 162 | o.sHelp = sHelp; | 188 | o.sHelp = sHelp; |
| 163 | o.bShortHasParams = false; | ||
| 164 | addOption( o ); | 189 | addOption( o ); |
| 165 | } | 190 | } |
| 166 | 191 | ||
| @@ -251,6 +276,17 @@ int Bu::OptParser::optHelp( StrArray /*aParams*/ ) | |||
| 251 | return 0; | 276 | return 0; |
| 252 | } | 277 | } |
| 253 | 278 | ||
| 279 | void Bu::OptParser::optionError( const Bu::FString sOption ) | ||
| 280 | { | ||
| 281 | sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl; | ||
| 282 | exit( 1 ); | ||
| 283 | } | ||
| 284 | |||
| 285 | void Bu::OptParser::setNonOption( OptionSignal sSignal ) | ||
| 286 | { | ||
| 287 | sNonOption = sSignal; | ||
| 288 | } | ||
| 289 | |||
| 254 | Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, | 290 | Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, |
| 255 | int iIndent ) | 291 | int iIndent ) |
| 256 | { | 292 | { |
| @@ -358,7 +394,6 @@ Bu::OptParser::_ValueProxy::~_ValueProxy() | |||
| 358 | 394 | ||
| 359 | Bu::OptParser::Option::Option() : | 395 | Bu::OptParser::Option::Option() : |
| 360 | cOpt( '\0' ), | 396 | cOpt( '\0' ), |
| 361 | bShortHasParams( false ), | ||
| 362 | pProxy( NULL ) | 397 | pProxy( NULL ) |
| 363 | { | 398 | { |
| 364 | } | 399 | } |
| @@ -368,7 +403,6 @@ Bu::OptParser::Option::Option( const Option &rSrc ) : | |||
| 368 | sOpt( rSrc.sOpt ), | 403 | sOpt( rSrc.sOpt ), |
| 369 | sHelp( rSrc.sHelp ), | 404 | sHelp( rSrc.sHelp ), |
| 370 | sUsed( rSrc.sUsed ), | 405 | sUsed( rSrc.sUsed ), |
| 371 | bShortHasParams( rSrc.bShortHasParams ), | ||
| 372 | pProxy( NULL ), | 406 | pProxy( NULL ), |
| 373 | sOverride( rSrc.sOverride ) | 407 | sOverride( rSrc.sOverride ) |
| 374 | { | 408 | { |
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 @@ | |||
| 12 | namespace Bu | 12 | namespace Bu |
| 13 | { | 13 | { |
| 14 | typedef Bu::Array<Bu::FString> StrArray; | 14 | typedef Bu::Array<Bu::FString> StrArray; |
| 15 | |||
| 16 | /** | ||
| 17 | * POSIX/Gnu style command line parser. Handles long and short options in | ||
| 18 | * a variety of fun and useful ways, along with singal based callbacks and | ||
| 19 | * automatic variable setting. It's pretty easy to use, and very flexible. | ||
| 20 | * | ||
| 21 | * OptParser supports it's own builtin help mechanism which automatically | ||
| 22 | * enumerates the available options and their help in a well formatted and | ||
| 23 | * easy to read way, automatically formatting your help text per option and | ||
| 24 | * allows for addition "help banners" which can be placed wherever you | ||
| 25 | * would like. | ||
| 26 | */ | ||
| 15 | class OptParser | 27 | class OptParser |
| 16 | { | 28 | { |
| 17 | private: | 29 | private: |
| @@ -67,7 +79,6 @@ namespace Bu | |||
| 67 | Bu::FString sOpt; | 79 | Bu::FString sOpt; |
| 68 | Bu::FString sHelp; | 80 | Bu::FString sHelp; |
| 69 | OptionSignal sUsed; | 81 | OptionSignal sUsed; |
| 70 | bool bShortHasParams; | ||
| 71 | _ValueProxy *pProxy; | 82 | _ValueProxy *pProxy; |
| 72 | Bu::FString sOverride; | 83 | Bu::FString sOverride; |
| 73 | }; | 84 | }; |
| @@ -103,7 +114,6 @@ namespace Bu | |||
| 103 | o.cOpt = cOpt; | 114 | o.cOpt = cOpt; |
| 104 | o.sOpt = sOpt; | 115 | o.sOpt = sOpt; |
| 105 | o.pProxy = new ValueProxy<vtype>( var ); | 116 | o.pProxy = new ValueProxy<vtype>( var ); |
| 106 | o.bShortHasParams = true; | ||
| 107 | o.sHelp = sHelp; | 117 | o.sHelp = sHelp; |
| 108 | addOption( o ); | 118 | addOption( o ); |
| 109 | } | 119 | } |
| @@ -148,14 +158,24 @@ namespace Bu | |||
| 148 | void setOverride( const Bu::FString &sOpt, | 158 | void setOverride( const Bu::FString &sOpt, |
| 149 | const Bu::FString &sOverride ); | 159 | const Bu::FString &sOverride ); |
| 150 | 160 | ||
| 151 | // void addOption( char cOpt, const Bu::FString &sOpt, | ||
| 152 | |||
| 153 | void addHelpOption( char c='h', const Bu::FString &s="help", | 161 | void addHelpOption( char c='h', const Bu::FString &s="help", |
| 154 | const Bu::FString &sHelp="This help." ); | 162 | const Bu::FString &sHelp="This help." ); |
| 155 | void addHelpBanner( const Bu::FString &sText, bool bFormatted=true ); | 163 | void addHelpBanner( const Bu::FString &sText, bool bFormatted=true ); |
| 156 | 164 | ||
| 157 | int optHelp( StrArray aParams ); | 165 | int optHelp( StrArray aParams ); |
| 158 | 166 | ||
| 167 | /** | ||
| 168 | * This function is called when an unrecognized option is found, the | ||
| 169 | * default behaviour is to print an error to stdout and exit( 1 ), if | ||
| 170 | * you want to do something different, just override this function. | ||
| 171 | * This is also called by default when something is found that hasn't | ||
| 172 | * been handled by an option, and isn't an option (starts with - or --). | ||
| 173 | * To change this behaviour call | ||
| 174 | */ | ||
| 175 | virtual void optionError( const Bu::FString sOption ); | ||
| 176 | |||
| 177 | void setNonOption( OptionSignal sSignal ); | ||
| 178 | |||
| 159 | private: | 179 | private: |
| 160 | Bu::FString format( const Bu::FString &sIn, int iWidth, int iIndent ); | 180 | Bu::FString format( const Bu::FString &sIn, int iWidth, int iIndent ); |
| 161 | 181 | ||
| @@ -163,6 +183,7 @@ namespace Bu | |||
| 163 | ShortOptionHash hsOption; | 183 | ShortOptionHash hsOption; |
| 164 | LongOptionHash hlOption; | 184 | LongOptionHash hlOption; |
| 165 | BannerList lBanner; | 185 | BannerList lBanner; |
| 186 | OptionSignal sNonOption; | ||
| 166 | }; | 187 | }; |
| 167 | }; | 188 | }; |
| 168 | 189 | ||
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: | |||
| 40 | setOverride("str", "Bob!"); | 40 | setOverride("str", "Bob!"); |
| 41 | 41 | ||
| 42 | addHelpOption(); | 42 | addHelpOption(); |
| 43 | |||
| 44 | setNonOption( slot( this, &Opts::nonOption ) ); | ||
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | int yesparam( StrArray aParams ) | 47 | int yesparam( StrArray aParams ) |
| @@ -54,6 +56,12 @@ public: | |||
| 54 | return 0; | 56 | return 0; |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 59 | int nonOption( StrArray aParams ) | ||
| 60 | { | ||
| 61 | sio << " - nonOption" << aParams << sio.nl; | ||
| 62 | return aParams.getSize()-1; | ||
| 63 | } | ||
| 64 | |||
| 57 | int iBob; | 65 | int iBob; |
| 58 | float dBob; | 66 | float dBob; |
| 59 | Bu::FString sVar; | 67 | Bu::FString sVar; |
