aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/optparser.cpp225
-rw-r--r--src/optparser.h17
-rw-r--r--src/signals.h12
-rw-r--r--src/tests/optparser.cpp25
-rw-r--r--src/tests/signals.cpp39
5 files changed, 300 insertions, 18 deletions
diff --git a/src/optparser.cpp b/src/optparser.cpp
index 2046792..f99dd85 100644
--- a/src/optparser.cpp
+++ b/src/optparser.cpp
@@ -1,4 +1,8 @@
1#include "bu/optparser.h" 1#include "bu/optparser.h"
2#include "bu/sio.h"
3using namespace Bu;
4
5#include <stdlib.h>
2 6
3Bu::OptParser::OptParser() 7Bu::OptParser::OptParser()
4{ 8{
@@ -8,6 +12,81 @@ Bu::OptParser::~OptParser()
8{ 12{
9} 13}
10 14
15void Bu::OptParser::parse( int argc, char **argv )
16{
17 for( int j = 1; j < argc; j++ )
18 {
19 if( argv[j][0] == '-' )
20 {
21 // Now we're on to something, which kind is it?
22 if( argv[j][1] == '-' )
23 {
24 // Long param, cool, that's easy, first search for =
25 int iEPos;
26 for( iEPos = 2; argv[j][iEPos] != '\0' &&
27 argv[j][iEPos] != '='; iEPos++ ) { }
28
29 Bu::FString sOpt;
30 int iCount = argc-j;
31 if( argv[j][iEPos] == '=' )
32 {
33 sOpt.set( argv[j]+2, iEPos-2 );
34 iCount++;
35 }
36 else
37 {
38 sOpt.set( argv[j]+2 );
39 }
40 Option *pOpt = hlOption.get( sOpt );
41 Bu::StrArray aParams( iCount );
42 aParams.append( sOpt );
43 if( argv[j][iEPos] == '=' )
44 {
45 aParams.append( argv[j]+iEPos+1 );
46 }
47 for( int k = j+1; k < argc; k++ )
48 {
49 aParams.append( argv[k] );
50 }
51 if( pOpt->sUsed )
52 j += pOpt->sUsed( aParams );
53 }
54 else
55 {
56 int iCPos;
57 for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ )
58 {
59 Option *pOpt = hsOption.get( argv[j][iCPos] );
60 Bu::StrArray aParams( argc-j+1 );
61 char buf[2] = {argv[j][iCPos], '\0'};
62 aParams.append( buf );
63 if( pOpt->bShortHasParams )
64 {
65 if( argv[j][iCPos+1] != '\0' )
66 aParams.append( argv[j]+iCPos+1 );
67 for( int k = j+1; k < argc; k++ )
68 {
69 aParams.append( argv[k] );
70 }
71 if( pOpt->sUsed )
72 {
73 j += pOpt->sUsed( aParams );
74 }
75 break;
76 }
77 else
78 {
79 pOpt->sUsed( aParams );
80 }
81 }
82 }
83 }
84 else
85 {
86 }
87 }
88}
89
11void Bu::OptParser::addOption( const Option &opt ) 90void Bu::OptParser::addOption( const Option &opt )
12{ 91{
13 lOption.append( opt ); 92 lOption.append( opt );
@@ -15,13 +94,155 @@ void Bu::OptParser::addOption( const Option &opt )
15 hsOption.insert( opt.cOpt, &lOption.last() ); 94 hsOption.insert( opt.cOpt, &lOption.last() );
16 if( opt.sOpt ) 95 if( opt.sOpt )
17 hlOption.insert( opt.sOpt, &lOption.last() ); 96 hlOption.insert( opt.sOpt, &lOption.last() );
97}
18 98
99void Bu::OptParser::addHelpOption( char c, const Bu::FString &s, const Bu::FString &sHelp )
100{
101 Option o;
102 o.sUsed = slot( this, &OptParser::optHelp );
103 o.cOpt = c;
104 o.sOpt = s;
105 o.sHelp = sHelp;
106 o.bShortHasParams = false;
107 addOption( o );
108}
109
110int Bu::OptParser::optHelp( StrArray aParams )
111{
112 bool bHasShort = false;
113 int iMaxWidth = 0;
114 int iScrWidth = 80;
115 char *env = getenv("COLUMNS");
116 if( env )
117 iScrWidth = strtol( env, NULL, 10 );
118 for( OptionList::iterator i = lOption.begin(); i; i++ )
119 {
120 if( (*i).cOpt != '\0' )
121 bHasShort = true;
122 if( (*i).sOpt && iMaxWidth < (*i).sOpt.getSize() )
123 iMaxWidth = (*i).sOpt.getSize();
124 }
125 int iIndent = 4;
126 if( bHasShort )
127 iIndent += 4;
128 if( iMaxWidth > 0 )
129 iIndent += 4 + iMaxWidth;
130 for( OptionList::iterator i = lOption.begin(); i; i++ )
131 {
132 sio << " ";
133 if( bHasShort )
134 {
135 if( (*i).cOpt == '\0' )
136 sio << " ";
137 else
138 sio << "-" << (*i).cOpt;
139 sio << " ";
140 }
141 if( iMaxWidth > 0 )
142 {
143 if( (*i).sOpt )
144 {
145 sio << "--" << Fmt(iMaxWidth, Fmt::Left) << (*i).sOpt;
146 }
147 else
148 {
149 sio << " " << Fmt(iMaxWidth) << "";
150 }
151 sio << " ";
152 }
153 sio << format( (*i).sHelp, iScrWidth-iIndent-1, iIndent );
154 sio << sio.nl;
155 }
156 exit( 0 );
157 return 0;
19} 158}
20 159
21Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, 160Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth,
22 int iIndent ) 161 int iIndent )
23{ 162{
163 Bu::FString sOut;
164 Bu::FString sIndent;
165 for( int j = 0; j < iIndent; j++ )
166 sIndent.append(" ", 1);
167 bool bFirst = true;
168 int iSpaceCount = 0;
169 bool bSpace = false;
170 int iPrevLineLen;
171 int iLineLen = 0;
172 char c;
173 Bu::FString::const_iterator iLastSpace, iStart;
174 for( Bu::FString::const_iterator i = iLastSpace = iStart = sIn.begin(); i; i++ )
175 {
176 c = *i;
177 if( *i == ' ' )
178 {
179 if( bSpace == false )
180 {
181 iLastSpace = i;
182 iSpaceCount++;
183 bSpace = true;
184 iPrevLineLen = iLineLen;
185 }
186 }
187 else
188 {
189 bSpace = false;
190 }
191 iLineLen++;
24 192
193 if( iLineLen >= iWidth )
194 {
195 iSpaceCount--;
196 if( bFirst == true )
197 bFirst = false;
198 else
199 sOut += sIndent;
200 int iExtraSpaces = iWidth-iPrevLineLen;
201 bSpace = false;
202 float fFill = 0.0;
203 int iSubSpaceCount = 0;
204 float fAdd = ((float)iExtraSpaces/(float)iSpaceCount);
205 for( Bu::FString::const_iterator k = iStart; k != iLastSpace; k++ )
206 {
207 sOut += *k;
208 if( *k == ' ' )
209 {
210 if( bSpace == false && iExtraSpaces > 0 )
211 {
212 bSpace = true;
213 fFill += fAdd;
214 iSubSpaceCount++;
215 for( int sp = 0; sp < (int)(fFill); sp++ )
216 {
217 sOut += ' ';
218 iExtraSpaces--;
219 }
220 fFill -= (int)fFill;
221 if( iSubSpaceCount == iSpaceCount && iExtraSpaces > 0 )
222 {
223 for(; iExtraSpaces > 0; iExtraSpaces-- )
224 {
225 sOut += ' ';
226 }
227 }
228 }
229 }
230 else
231 bSpace = false;
232 }
233 //sOut.append( iStart, iLastSpace );
234 sOut.append("\n");
235 for(; iLastSpace && *iLastSpace == ' '; iLastSpace++ ) { }
236 iStart = i = iLastSpace;
237 bSpace = false;
238 iLineLen = 1;
239 iSpaceCount = 0;
240 }
241 }
242 if( !bFirst )
243 sOut += sIndent;
244 sOut.append( iStart );
245 return sOut;
25} 246}
26 247
27 248
@@ -29,7 +250,9 @@ Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth,
29// Code for Bu::OptParser::Option 250// Code for Bu::OptParser::Option
30// 251//
31 252
32Bu::OptParser::Option::Option() 253Bu::OptParser::Option::Option() :
254 cOpt( '\0' ),
255 bShortHasParams( false )
33{ 256{
34} 257}
35 258
diff --git a/src/optparser.h b/src/optparser.h
index 39f048d..ed32e45 100644
--- a/src/optparser.h
+++ b/src/optparser.h
@@ -4,12 +4,16 @@
4#include "bu/fstring.h" 4#include "bu/fstring.h"
5#include "bu/list.h" 5#include "bu/list.h"
6#include "bu/hash.h" 6#include "bu/hash.h"
7#include "bu/signals.h"
8#include "bu/array.h"
7 9
8namespace Bu 10namespace Bu
9{ 11{
12 typedef Bu::Array<Bu::FString> StrArray;
10 class OptParser 13 class OptParser
11 { 14 {
12 public: 15 public:
16 typedef Signal1<int, StrArray> OptionSignal;
13 class Option 17 class Option
14 { 18 {
15 public: 19 public:
@@ -18,22 +22,21 @@ namespace Bu
18 22
19 char cOpt; 23 char cOpt;
20 Bu::FString sOpt; 24 Bu::FString sOpt;
21 Bu::FString sDesc; 25 Bu::FString sHelp;
26 OptionSignal sUsed;
27 bool bShortHasParams;
22 }; 28 };
23 29
24 public: 30 public:
25 OptParser(); 31 OptParser();
26 virtual ~OptParser(); 32 virtual ~OptParser();
27 33
28 void parse( int argc, char *argv[] ); 34 void parse( int argc, char **argv );
29 35
30 void addOption( const Option &opt ); 36 void addOption( const Option &opt );
37 void addHelpOption( char c, const Bu::FString &s, const Bu::FString &sHelp );
31 38
32 template<typename c> 39 int optHelp( StrArray aParams );
33 void callback( c *pObj, int (c::*fnc)( int, char *[] ) )
34 {
35 (pObj->*fnc)( 0, NULL );
36 }
37 40
38 private: 41 private:
39 Bu::FString format( const Bu::FString &sIn, int iWidth, int iIndent ); 42 Bu::FString format( const Bu::FString &sIn, int iWidth, int iIndent );
diff --git a/src/signals.h b/src/signals.h
index 3f892b8..075e5bf 100644
--- a/src/signals.h
+++ b/src/signals.h
@@ -89,7 +89,7 @@ namespace Bu
89 bool isSet() const { return pCb != NULL; } 89 bool isSet() const { return pCb != NULL; }
90 operator bool() const { return isSet(); } 90 operator bool() const { return isSet(); }
91 91
92 Signal0 &operator=( const Signal0 &rhs ) 92 Signal0<ret> &operator=( const Signal0<ret> &rhs )
93 { 93 {
94 pCb = rhs.pCb->clone(); 94 pCb = rhs.pCb->clone();
95 return *this; 95 return *this;
@@ -198,7 +198,7 @@ namespace Bu
198 bool isSet() const { return pCb != NULL; } 198 bool isSet() const { return pCb != NULL; }
199 operator bool() const { return isSet(); } 199 operator bool() const { return isSet(); }
200 200
201 Signal1 &operator=( const Signal1 &rhs ) 201 Signal1<ret, p1t> &operator=( const Signal1<ret, p1t> &rhs )
202 { 202 {
203 pCb = rhs.pCb->clone(); 203 pCb = rhs.pCb->clone();
204 return *this; 204 return *this;
@@ -307,7 +307,7 @@ namespace Bu
307 bool isSet() const { return pCb != NULL; } 307 bool isSet() const { return pCb != NULL; }
308 operator bool() const { return isSet(); } 308 operator bool() const { return isSet(); }
309 309
310 Signal2 &operator=( const Signal2 &rhs ) 310 Signal2<ret, p1t, p2t> &operator=( const Signal2<ret, p1t, p2t> &rhs )
311 { 311 {
312 pCb = rhs.pCb->clone(); 312 pCb = rhs.pCb->clone();
313 return *this; 313 return *this;
@@ -416,7 +416,7 @@ namespace Bu
416 bool isSet() const { return pCb != NULL; } 416 bool isSet() const { return pCb != NULL; }
417 operator bool() const { return isSet(); } 417 operator bool() const { return isSet(); }
418 418
419 Signal3 &operator=( const Signal3 &rhs ) 419 Signal3<ret, p1t, p2t, p3t> &operator=( const Signal3<ret, p1t, p2t, p3t> &rhs )
420 { 420 {
421 pCb = rhs.pCb->clone(); 421 pCb = rhs.pCb->clone();
422 return *this; 422 return *this;
@@ -525,7 +525,7 @@ namespace Bu
525 bool isSet() const { return pCb != NULL; } 525 bool isSet() const { return pCb != NULL; }
526 operator bool() const { return isSet(); } 526 operator bool() const { return isSet(); }
527 527
528 Signal4 &operator=( const Signal4 &rhs ) 528 Signal4<ret, p1t, p2t, p3t, p4t> &operator=( const Signal4<ret, p1t, p2t, p3t, p4t> &rhs )
529 { 529 {
530 pCb = rhs.pCb->clone(); 530 pCb = rhs.pCb->clone();
531 return *this; 531 return *this;
@@ -634,7 +634,7 @@ namespace Bu
634 bool isSet() const { return pCb != NULL; } 634 bool isSet() const { return pCb != NULL; }
635 operator bool() const { return isSet(); } 635 operator bool() const { return isSet(); }
636 636
637 Signal5 &operator=( const Signal5 &rhs ) 637 Signal5<ret, p1t, p2t, p3t, p4t, p5t> &operator=( const Signal5<ret, p1t, p2t, p3t, p4t, p5t> &rhs )
638 { 638 {
639 pCb = rhs.pCb->clone(); 639 pCb = rhs.pCb->clone();
640 return *this; 640 return *this;
diff --git a/src/tests/optparser.cpp b/src/tests/optparser.cpp
index 9168af8..ee2ea58 100644
--- a/src/tests/optparser.cpp
+++ b/src/tests/optparser.cpp
@@ -8,13 +8,30 @@ public:
8 Opts() : 8 Opts() :
9 iBob( 542 ) 9 iBob( 542 )
10 { 10 {
11 callback( this, &Opts::cb ); 11 Option o;
12 o.sUsed = slot( this, &Opts::cb );
13 o.cOpt = 'x';
14 o.sOpt = "things";
15 o.bShortHasParams = true;
16 o.sHelp = "This is the first test parameter. It calls a function, and takes parameters.";
17 addOption( o );
18
19 Option o2;
20 o2.sUsed = slot( this, &Opts::cb );
21 o2.cOpt = 'y';
22 o2.sOpt = "stuff";
23 o2.bShortHasParams = false;
24 o2.sHelp = "This is the second test parameter. It does not take parameters. However, I do want to make this part much longer to see how it looks when you add way too much text to one of these things. It can't really be that bad, right?";
25 addOption( o2 );
26
27 addHelpOption('h', "help", "This help.");
12 } 28 }
13 29
14 int cb( int argc, char *argv[] ) 30 int cb( StrArray aParams )
15 { 31 {
16 sio << "Hey, cb was called, here's a class var: " << iBob << sio.nl; 32 sio << "Hey, cb was called, here's a class var: " << iBob << sio.nl;
17 return 5; 33 sio << "argv[] = " << aParams << sio.nl;
34 return 1;
18 } 35 }
19 36
20 int iBob; 37 int iBob;
@@ -23,5 +40,7 @@ public:
23int main( int argc, char *argv[] ) 40int main( int argc, char *argv[] )
24{ 41{
25 Opts o; 42 Opts o;
43
44 o.parse( argc, argv );
26} 45}
27 46
diff --git a/src/tests/signals.cpp b/src/tests/signals.cpp
index b4b1363..4af2b8e 100644
--- a/src/tests/signals.cpp
+++ b/src/tests/signals.cpp
@@ -51,7 +51,32 @@ private:
51 51
52void pfnc0() 52void pfnc0()
53{ 53{
54 sio << "This doesn't have state, it's pfnc0()!" << sio.nl; 54 sio << ": void pfnc0()" << sio.nl;
55}
56
57void pfnc1( int a )
58{
59 sio << ": void pfnc1( " << a << " )" << sio.nl;
60}
61
62void pfnc2( int a, Bu::FString b )
63{
64 sio << ": void pfnc2( " << a << ", \"" << b << "\" )" << sio.nl;
65}
66
67void pfnc3( int a, Bu::FString b, double c )
68{
69 sio << ": void pfnc3( " << a << ", \"" << b << "\", " << c << " )" << sio.nl;
70}
71
72void pfnc4( int a, Bu::FString b, double c, char d )
73{
74 sio << ": void pfnc4( " << a << ", \"" << b << "\", " << c << ", '" << d << "' )" << sio.nl;
75}
76
77void pfnc5( int a, Bu::FString b, double c, char d, long e )
78{
79 sio << ": void pfnc5( " << a << ", \"" << b << "\", " << c << ", '" << d << "', " << e << " )" << sio.nl;
55} 80}
56 81
57void callit( Signal0<void> sig ) 82void callit( Signal0<void> sig )
@@ -65,21 +90,33 @@ int main()
65 90
66 Signal0<void> cb0( slot( &t, &Thing::fnc0 ) ); 91 Signal0<void> cb0( slot( &t, &Thing::fnc0 ) );
67 cb0(); 92 cb0();
93 cb0 = slot( &pfnc0 );
94 cb0();
68 95
69 Signal1<void, int> cb1( slot( &t, &Thing::fnc1 ) ); 96 Signal1<void, int> cb1( slot( &t, &Thing::fnc1 ) );
70 cb1( 5 ); 97 cb1( 5 );
98 cb1 = slot( &pfnc1 );
99 cb1( 5 );
71 100
72 Signal2<void, int, Bu::FString> cb2( slot( &t, &Thing::fnc2 ) ); 101 Signal2<void, int, Bu::FString> cb2( slot( &t, &Thing::fnc2 ) );
73 cb2( 5, "Hi there" ); 102 cb2( 5, "Hi there" );
103 cb2 = slot( &pfnc2 );
104 cb2( 5, "Hi there" );
74 105
75 Signal3<void, int, Bu::FString, double> cb3( slot( &t, &Thing::fnc3 ) ); 106 Signal3<void, int, Bu::FString, double> cb3( slot( &t, &Thing::fnc3 ) );
76 cb3( 5, "Hi there", 12.85 ); 107 cb3( 5, "Hi there", 12.85 );
108 cb3 = slot( &pfnc3 );
109 cb3( 5, "Hi there", 12.85 );
77 110
78 Signal4<void, int, Bu::FString, double, char> cb4( slot( &t, &Thing::fnc4 ) ); 111 Signal4<void, int, Bu::FString, double, char> cb4( slot( &t, &Thing::fnc4 ) );
79 cb4( 5, "Hi there", 12.85, 'z' ); 112 cb4( 5, "Hi there", 12.85, 'z' );
113 cb4 = slot( &pfnc4 );
114 cb4( 5, "Hi there", 12.85, 'z' );
80 115
81 Signal5<void, int, Bu::FString, double, char, long> cb5( slot( &t, &Thing::fnc5 ) ); 116 Signal5<void, int, Bu::FString, double, char, long> cb5( slot( &t, &Thing::fnc5 ) );
82 cb5( 5, "Hi there", 12.85, 'z', 849 ); 117 cb5( 5, "Hi there", 12.85, 'z', 849 );
118 cb5 = slot( &pfnc5 );
119 cb5( 5, "Hi there", 12.85, 'z', 849 );
83 120
84// Signal1<int, int> cb1( slot( &t, &Thing::fnc1 ) ); 121// Signal1<int, int> cb1( slot( &t, &Thing::fnc1 ) );
85// sio << "Result: " << cb1( 5 ) << sio.nl; 122// sio << "Result: " << cb1( 5 ) << sio.nl;