From 146930268a695dcc0432599d625ec3eb7e74025e Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 18 Dec 2009 08:59:16 +0000 Subject: The OptParser still needs help banners and more helper functions, but otherwise, it's done. It works great, and provides much flexibility and usefulness. It now relies on the input side of the Formatter class, which at the moment supports reading strings...not real useful yet... Next up, adding readers for numbers and such, then it'll be mostly complete. Also, fixed a bug when copying uninitialized signal objects. --- src/formatter.cpp | 172 +++++++++++++++++++++++++++++------------------- src/formatter.h | 54 ++++++++------- src/optparser.cpp | 105 +++++++++++++++++++++++------ src/optparser.h | 59 +++++++++++++++++ src/signals.h | 12 ++-- src/tests/optparser.cpp | 5 ++ 6 files changed, 289 insertions(+), 118 deletions(-) diff --git a/src/formatter.cpp b/src/formatter.cpp index 830e527..5ab1b3f 100644 --- a/src/formatter.cpp +++ b/src/formatter.cpp @@ -9,8 +9,8 @@ #include -Bu::Formatter::Formatter( Stream &rOut ) : - rOut( rOut ), +Bu::Formatter::Formatter( Stream &rStream ) : + rStream( rStream ), uIndent( 0 ), cIndent( '\t' ) { @@ -22,12 +22,12 @@ Bu::Formatter::~Formatter() void Bu::Formatter::write( const Bu::FString &sStr ) { - rOut.write( sStr ); + rStream.write( sStr ); } void Bu::Formatter::write( const void *sStr, int iLen ) { - rOut.write( sStr, iLen ); + rStream.write( sStr, iLen ); } void Bu::Formatter::writeAligned( const Bu::FString &sStr ) @@ -111,6 +111,36 @@ void Bu::Formatter::writeAligned( const char *sStr, int iLen ) usedFormat(); } +Bu::FString Bu::Formatter::readToken() +{ + Bu::FString sRet; + for(;;) + { + char buf; + int iRead = rStream.read( &buf, 1 ); + if( iRead == 0 ) + return sRet; + if( buf == ' ' || buf == '\t' || buf == '\n' || buf == '\r' ) + continue; + else + { + sRet += buf; + break; + } + } + for(;;) + { + char buf; + int iRead = rStream.read( &buf, 1 ); + if( iRead == 0 ) + return sRet; + if( buf == ' ' || buf == '\t' || buf == '\n' || buf == '\r' ) + return sRet; + else + sRet += buf; + } +} + void Bu::Formatter::incIndent() { if( uIndent < 0xFFU ) @@ -192,137 +222,143 @@ Bu::Formatter::Fmt &Bu::Formatter::Fmt::caps( bool bCaps ) return *this; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const Bu::Formatter::Fmt &f ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Formatter::Fmt &fmt ) { - rOut.setTempFormat( f ); - return rOut; + f.setTempFormat( fmt ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, Bu::Formatter::Special s ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, Bu::Formatter::Special s ) { switch( s ) { case Formatter::nl: { - rOut.write("\n", 1 ); - char ci = rOut.getIndentChar(); - for( int j = 0; j < rOut.getIndent(); j++ ) - rOut.write( &ci, 1 ); + f.write("\n", 1 ); + char ci = f.getIndentChar(); + for( int j = 0; j < f.getIndent(); j++ ) + f.write( &ci, 1 ); } break; case Formatter::flush: - rOut.doFlush(); + f.doFlush(); break; } - return rOut; + return f; +} + +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const char *sStr ) +{ + f.writeAligned( sStr, strlen( sStr ) ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const char *sStr ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, char *sStr ) { - rOut.writeAligned( sStr, strlen( sStr ) ); - return rOut; + f.writeAligned( sStr, strlen( sStr ) ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, char *sStr ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::FString &sStr ) { - rOut.writeAligned( sStr, strlen( sStr ) ); - return rOut; + f.writeAligned( sStr ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const Bu::FString &sStr ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed char c ) { - rOut.writeAligned( sStr ); - return rOut; + f.write( (char *)&c, 1 ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, signed char c ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, char c ) { - rOut.write( (char *)&c, 1 ); - return rOut; + f.write( (char *)&c, 1 ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, char c ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned char c ) { - rOut.write( (char *)&c, 1 ); - return rOut; + f.write( (char *)&c, 1 ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, unsigned char c ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed short i ) { - rOut.write( (char *)&c, 1 ); - return rOut; + f.ifmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, signed short i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned short i ) { - rOut.ifmt( i ); - return rOut; + f.ufmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, unsigned short i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed int i ) { - rOut.ufmt( i ); - return rOut; + f.ifmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, signed int i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned int i ) { - rOut.ifmt( i ); - return rOut; + f.ufmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, unsigned int i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed long i ) { - rOut.ufmt( i ); - return rOut; + f.ifmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, signed long i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned long i ) { - rOut.ifmt( i ); - return rOut; + f.ufmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, unsigned long i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed long long i ) { - rOut.ufmt( i ); - return rOut; + f.ifmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, signed long long i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned long long i ) { - rOut.ifmt( i ); - return rOut; + f.ufmt( i ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, unsigned long long i ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, float flt ) { - rOut.ufmt( i ); - return rOut; + f.ffmt( flt ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, float f ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, double flt ) { - rOut.ffmt( f ); - return rOut; + f.ffmt( flt ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, double f ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, long double flt ) { - rOut.ffmt( f ); - return rOut; + f.ffmt( flt ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, long double f ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, bool b ) { - rOut.ffmt( f ); - return rOut; + f.writeAligned( b?("true"):("false") ); + return f; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, bool b ) +Bu::Formatter &Bu::operator>>( Bu::Formatter &f, Bu::FString &sStr ) { - rOut.writeAligned( b?("true"):("false") ); - return rOut; + sStr = f.readToken(); + return f; } diff --git a/src/formatter.h b/src/formatter.h index db144eb..aec5c5d 100644 --- a/src/formatter.h +++ b/src/formatter.h @@ -15,7 +15,7 @@ namespace Bu class Formatter { public: - Formatter( Stream &rOut ); + Formatter( Stream &rStream ); virtual ~Formatter(); typedef struct Fmt @@ -103,6 +103,8 @@ namespace Bu void writeAligned( const Bu::FString &sStr ); void writeAligned( const char *sStr, int iLen ); + Bu::FString readToken(); + void incIndent(); void decIndent(); void setIndent( uint8_t uLevel ); @@ -206,11 +208,11 @@ namespace Bu void doFlush() { - rOut.flush(); + rStream.flush(); } private: - Stream &rOut; + Stream &rStream; Fmt fLast; bool bTempFmt; uint8_t uIndent; @@ -219,31 +221,33 @@ namespace Bu typedef Formatter::Fmt Fmt; - Formatter &operator<<( Formatter &rOut, const Formatter::Fmt &f ); - Formatter &operator<<( Formatter &rOut, Formatter::Special s ); - Formatter &operator<<( Formatter &rOut, const char *sStr ); - Formatter &operator<<( Formatter &rOut, char *sStr ); - Formatter &operator<<( Formatter &rOut, const Bu::FString &sStr ); - Formatter &operator<<( Formatter &rOut, signed char c ); - Formatter &operator<<( Formatter &rOut, char c ); - Formatter &operator<<( Formatter &rOut, unsigned char c ); - Formatter &operator<<( Formatter &rOut, signed short i ); - Formatter &operator<<( Formatter &rOut, unsigned short i ); - Formatter &operator<<( Formatter &rOut, signed int i ); - Formatter &operator<<( Formatter &rOut, unsigned int i ); - Formatter &operator<<( Formatter &rOut, signed long i ); - Formatter &operator<<( Formatter &rOut, unsigned long i ); - Formatter &operator<<( Formatter &rOut, signed long long i ); - Formatter &operator<<( Formatter &rOut, unsigned long long i ); - Formatter &operator<<( Formatter &rOut, float f ); - Formatter &operator<<( Formatter &rOut, double f ); - Formatter &operator<<( Formatter &rOut, long double f ); - Formatter &operator<<( Formatter &rOut, bool b ); + Formatter &operator<<( Formatter &f, const Formatter::Fmt &fmt ); + Formatter &operator<<( Formatter &f, Formatter::Special s ); + Formatter &operator<<( Formatter &f, const char *sStr ); + Formatter &operator<<( Formatter &f, char *sStr ); + Formatter &operator<<( Formatter &f, const Bu::FString &sStr ); + Formatter &operator<<( Formatter &f, signed char c ); + Formatter &operator<<( Formatter &f, char c ); + Formatter &operator<<( Formatter &f, unsigned char c ); + Formatter &operator<<( Formatter &f, signed short i ); + Formatter &operator<<( Formatter &f, unsigned short i ); + Formatter &operator<<( Formatter &f, signed int i ); + Formatter &operator<<( Formatter &f, unsigned int i ); + Formatter &operator<<( Formatter &f, signed long i ); + Formatter &operator<<( Formatter &f, unsigned long i ); + Formatter &operator<<( Formatter &f, signed long long i ); + Formatter &operator<<( Formatter &f, unsigned long long i ); + Formatter &operator<<( Formatter &f, float flt ); + Formatter &operator<<( Formatter &f, double flt ); + Formatter &operator<<( Formatter &f, long double flt ); + Formatter &operator<<( Formatter &f, bool b ); + + Formatter &operator>>( Formatter &f, Bu::FString &sStr ); template - Formatter &operator<<( Formatter &rOut, const type *p ) + Formatter &operator<<( Formatter &f, const type *p ) { - return rOut << "0x" << Fmt::hex(sizeof(ptrdiff_t)*2) << (ptrdiff_t)(p); + return f << "0x" << Fmt::hex(sizeof(ptrdiff_t)*2) << (ptrdiff_t)(p); } }; diff --git a/src/optparser.cpp b/src/optparser.cpp index f99dd85..2a8e64b 100644 --- a/src/optparser.cpp +++ b/src/optparser.cpp @@ -28,28 +28,48 @@ void Bu::OptParser::parse( int argc, char **argv ) Bu::FString sOpt; int iCount = argc-j; + Bu::FString sExtraParam; if( argv[j][iEPos] == '=' ) { sOpt.set( argv[j]+2, iEPos-2 ); iCount++; + sExtraParam.set( argv[j]+iEPos+1 ); } else { sOpt.set( argv[j]+2 ); } Option *pOpt = hlOption.get( sOpt ); - Bu::StrArray aParams( iCount ); - aParams.append( sOpt ); - if( argv[j][iEPos] == '=' ) + 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++; + } } - if( pOpt->sUsed ) - j += pOpt->sUsed( aParams ); } else { @@ -57,26 +77,45 @@ void Bu::OptParser::parse( int argc, char **argv ) for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ ) { Option *pOpt = hsOption.get( argv[j][iCPos] ); - Bu::StrArray aParams( argc-j+1 ); char buf[2] = {argv[j][iCPos], '\0'}; - aParams.append( buf ); if( pOpt->bShortHasParams ) { - if( argv[j][iCPos+1] != '\0' ) - aParams.append( argv[j]+iCPos+1 ); - for( int k = j+1; k < argc; k++ ) - { - aParams.append( argv[k] ); - } if( pOpt->sUsed ) { + Bu::StrArray aParams( argc-j+1 ); + aParams.append( buf ); + if( argv[j][iCPos+1] != '\0' ) + aParams.append( argv[j]+iCPos+1 ); + for( int k = j+1; k < argc; k++ ) + { + aParams.append( argv[k] ); + } j += pOpt->sUsed( aParams ); + break; + } + else if( pOpt->pProxy ) + { + if( pOpt->sOverride ) + { + pOpt->pProxy->setValue( pOpt->sOverride ); + } + else if( argv[j][iCPos+1] != '\0' ) + { + pOpt->pProxy->setValue( + argv[j]+iCPos+1 + ); + break; + } } - break; } else { - pOpt->sUsed( aParams ); + if( pOpt->sUsed ) + { + Bu::StrArray aParam( 1 ); + aParam.append( buf ); + pOpt->sUsed( aParam ); + } } } } @@ -246,17 +285,45 @@ Bu::FString Bu::OptParser::format( const Bu::FString &sIn, int iWidth, } +// +// Code for Bu::OptParser::_ValueProxy +// + +Bu::OptParser::_ValueProxy::_ValueProxy() +{ +} + +Bu::OptParser::_ValueProxy::~_ValueProxy() +{ +} + // // Code for Bu::OptParser::Option // Bu::OptParser::Option::Option() : cOpt( '\0' ), - bShortHasParams( false ) + bShortHasParams( false ), + pProxy( NULL ) +{ +} + +Bu::OptParser::Option::Option( const Option &rSrc ) : + cOpt( rSrc.cOpt ), + sOpt( rSrc.sOpt ), + sHelp( rSrc.sHelp ), + sUsed( rSrc.sUsed ), + bShortHasParams( rSrc.bShortHasParams ), + pProxy( NULL ), + sOverride( rSrc.sOverride ) { + if( rSrc.pProxy ) + pProxy = rSrc.pProxy->clone(); } Bu::OptParser::Option::~Option() { + delete pProxy; + pProxy = NULL; } diff --git a/src/optparser.h b/src/optparser.h index ed32e45..acfb35d 100644 --- a/src/optparser.h +++ b/src/optparser.h @@ -6,6 +6,8 @@ #include "bu/hash.h" #include "bu/signals.h" #include "bu/array.h" +#include "bu/membuf.h" +#include "bu/formatter.h" namespace Bu { @@ -13,11 +15,51 @@ namespace Bu class OptParser { public: + class _ValueProxy + { + public: + _ValueProxy(); + virtual ~_ValueProxy(); + + virtual void setValue( const Bu::FString & )=0; + virtual _ValueProxy *clone()=0; + }; + + template + class ValueProxy : public _ValueProxy + { + public: + ValueProxy( ptype &v ) : + v( v ) + { + } + + virtual ~ValueProxy() + { + } + + virtual void setValue( const Bu::FString &sVal ) + { + Bu::MemBuf mb( sVal ); + Bu::Formatter f( mb ); + f >> v; + } + + virtual _ValueProxy *clone() + { + return new ValueProxy( v ); + } + + private: + ptype &v; + }; + typedef Signal1 OptionSignal; class Option { public: Option(); + Option( const Option &rSrc ); virtual ~Option(); char cOpt; @@ -25,6 +67,8 @@ namespace Bu Bu::FString sHelp; OptionSignal sUsed; bool bShortHasParams; + _ValueProxy *pProxy; + Bu::FString sOverride; }; public: @@ -34,6 +78,21 @@ namespace Bu void parse( int argc, char **argv ); void addOption( const Option &opt ); + + template + void addOption( char cOpt, const Bu::FString &sOpt, vtype &var, + const Bu::FString &sHelp="", const Bu::FString &sOverride="" ) + { + Option o; + o.cOpt = cOpt; + o.sOpt = sOpt; + o.pProxy = new ValueProxy( var ); + o.bShortHasParams = true; + o.sHelp = sHelp; + o.sOverride = sOverride; + addOption( o ); + } + void addHelpOption( char c, const Bu::FString &s, const Bu::FString &sHelp ); int optHelp( StrArray aParams ); diff --git a/src/signals.h b/src/signals.h index 075e5bf..975f6af 100644 --- a/src/signals.h +++ b/src/signals.h @@ -76,7 +76,7 @@ namespace Bu Signal0() : pCb( NULL ) { } Signal0( _Slot0 *pCb ) : pCb( pCb ) { } Signal0( const Signal0 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal0() { delete pCb; pCb = NULL; } @@ -185,7 +185,7 @@ namespace Bu Signal1() : pCb( NULL ) { } Signal1( _Slot1 *pCb ) : pCb( pCb ) { } Signal1( const Signal1 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal1() { delete pCb; pCb = NULL; } @@ -294,7 +294,7 @@ namespace Bu Signal2() : pCb( NULL ) { } Signal2( _Slot2 *pCb ) : pCb( pCb ) { } Signal2( const Signal2 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal2() { delete pCb; pCb = NULL; } @@ -403,7 +403,7 @@ namespace Bu Signal3() : pCb( NULL ) { } Signal3( _Slot3 *pCb ) : pCb( pCb ) { } Signal3( const Signal3 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal3() { delete pCb; pCb = NULL; } @@ -512,7 +512,7 @@ namespace Bu Signal4() : pCb( NULL ) { } Signal4( _Slot4 *pCb ) : pCb( pCb ) { } Signal4( const Signal4 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal4() { delete pCb; pCb = NULL; } @@ -621,7 +621,7 @@ namespace Bu Signal5() : pCb( NULL ) { } Signal5( _Slot5 *pCb ) : pCb( pCb ) { } Signal5( const Signal5 &rSrc ) : - pCb( rSrc.pCb->clone() ) { } + pCb( (rSrc.pCb)?(rSrc.pCb->clone()):(NULL) ) { } virtual ~Signal5() { delete pCb; pCb = NULL; } diff --git a/src/tests/optparser.cpp b/src/tests/optparser.cpp index ee2ea58..5cf82bd 100644 --- a/src/tests/optparser.cpp +++ b/src/tests/optparser.cpp @@ -23,6 +23,8 @@ public: o2.bShortHasParams = false; 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?"; addOption( o2 ); + + addOption( 's', "str", sVar, "Set a variable, see what it does.", "bob!"); addHelpOption('h', "help", "This help."); } @@ -35,6 +37,7 @@ public: } int iBob; + Bu::FString sVar; }; int main( int argc, char *argv[] ) @@ -42,5 +45,7 @@ int main( int argc, char *argv[] ) Opts o; o.parse( argc, argv ); + + sio << "sVar = \"" << o.sVar << "\"" << sio.nl; } -- cgit v1.2.3