diff options
Diffstat (limited to 'src')
-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; |