aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-12-18 16:07:31 +0000
committerMike Buland <eichlan@xagasoft.com>2009-12-18 16:07:31 +0000
commit2cbc634b3b603ec67c6c312bd18177cd52c71b63 (patch)
treead743e9cd660f325e1020cdea4f746938d102261
parent038815ae3a019ac56fa1c62e18c5861166d3a975 (diff)
downloadlibbu++-2cbc634b3b603ec67c6c312bd18177cd52c71b63.tar.gz
libbu++-2cbc634b3b603ec67c6c312bd18177cd52c71b63.tar.bz2
libbu++-2cbc634b3b603ec67c6c312bd18177cd52c71b63.tar.xz
libbu++-2cbc634b3b603ec67c6c312bd18177cd52c71b63.zip
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.
-rw-r--r--src/optparser.cpp112
-rw-r--r--src/optparser.h29
-rw-r--r--src/tests/optparser.cpp8
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
279void Bu::OptParser::optionError( const Bu::FString sOption )
280{
281 sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl;
282 exit( 1 );
283}
284
285void Bu::OptParser::setNonOption( OptionSignal sSignal )
286{
287 sNonOption = sSignal;
288}
289
254Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, 290Bu::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
359Bu::OptParser::Option::Option() : 395Bu::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 @@
12namespace Bu 12namespace 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;