From 469bbcf0701e1eb8a6670c23145b0da87357e178 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 25 Mar 2012 20:00:08 +0000 Subject: Code is all reorganized. We're about ready to release. I should write up a little explenation of the arrangement. --- src/stable/optparser.cpp | 492 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 src/stable/optparser.cpp (limited to 'src/stable/optparser.cpp') diff --git a/src/stable/optparser.cpp b/src/stable/optparser.cpp new file mode 100644 index 0000000..050232c --- /dev/null +++ b/src/stable/optparser.cpp @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/optparser.h" +#include "bu/sio.h" +using namespace Bu; + +#include + +Bu::OptParser::OptParser() +{ +} + +Bu::OptParser::~OptParser() +{ +} + +void Bu::OptParser::parse( int argc, char **argv ) +{ + for( int j = 1; j < argc; j++ ) + { + if( argv[j][0] == '-' ) + { + // Now we're on to something, which kind is it? + if( argv[j][1] == '-' ) + { + int iEPos; + for( iEPos = 2; argv[j][iEPos] != '\0' && + argv[j][iEPos] != '='; iEPos++ ) { } + + Bu::String sOpt; + int iCount = argc-j; + Bu::String 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 ); + } + if( !hlOption.has( sOpt ) ) + { + optionError( "--" + sOpt ); + } + else + { + // Long param, cool, that's easy, first search for = + Option *pOpt = hlOption.get( sOpt ); + if( pOpt->sUsed ) + { + Bu::StrArray aParams( iCount ); + aParams.append( sOpt ); + if( sExtraParam.isSet() ) + { + aParams.append( argv[j]+iEPos+1 ); + } + for( int k = j+1; k < argc; k++ ) + { + aParams.append( argv[k] ); + } + j += pOpt->sUsed( aParams ); + } + else if( pOpt->pProxy ) + { + if( pOpt->sOverride.isSet() ) + { + pOpt->pProxy->setValue( pOpt->sOverride ); + } + else if( sExtraParam.isSet() ) + { + pOpt->pProxy->setValueFromStr( sExtraParam ); + } + else if( argv[j+1] != '\0' ) + { + pOpt->pProxy->setValueFromStr( argv[j+1] ); + j++; + } + } + } + } + else + { + int iCPos; + for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ ) + { + if( !hsOption.has( argv[j][iCPos] ) ) + { + Bu::String sOpt("-"); + sOpt += argv[j][iCPos]; + optionError( sOpt ); + } + else + { + Option *pOpt = hsOption.get( argv[j][iCPos] ); + char buf[2] = {argv[j][iCPos], '\0'}; + if( pOpt->sUsed ) + { + Bu::StrArray aParams( argc-j+1 ); + aParams.append( buf ); + int iMod = 0; + if( argv[j][iCPos+1] != '\0' ) + { + aParams.append( argv[j]+iCPos+1 ); + iMod = -1; + } + for( int k = j+1; k < argc; k++ ) + { + aParams.append( argv[k] ); + } + int iUsed = pOpt->sUsed( aParams ); + if( iUsed > 0 ) + { + j += iUsed + iMod; + break; + } + } + else if( pOpt->pProxy ) + { + if( pOpt->sOverride.isSet() ) + { + pOpt->pProxy->setValue( pOpt->sOverride ); + } + else if( argv[j][iCPos+1] != '\0' ) + { + pOpt->pProxy->setValueFromStr( + argv[j]+iCPos+1 + ); + break; + } + else if( argv[j+1] ) + { + pOpt->pProxy->setValueFromStr( + argv[j+1] + ); + j++; + break; + } + } + } + } + } + } + else + { + if( !sNonOption ) + { + optionError( argv[j] ); + } + else + { + int iCount = argc-j; + Bu::StrArray aParams( iCount ); + for( int k = j; k < argc; k++ ) + { + aParams.append( argv[k] ); + } + j += sNonOption( aParams ); + } + } + } +} + +void Bu::OptParser::parse( const Bu::String &sLine ) +{ + Bu::String sCmd = sLine.clone(); + int iParams = 0; + bool bInGap = true; + bool bInQuote = false; + for( Bu::String::iterator i = sCmd.begin(); i; i++ ) + { + if( bInQuote == false && (*i == ' ' || *i == '\t') ) + { + if( bInGap == false ) + { + bInGap = true; + } + } + else if( *i == '"' ) + { + bInQuote = !bInQuote; + } + else + { + if( bInGap ) + { + iParams++; + bInGap = false; + } + } + } + + bInQuote = false; + bInGap = true; + char **asParam = new char*[iParams]; + iParams = 0; + for( char *i = sCmd.getStr(); *i; i++ ) + { + if( bInQuote == false && (*i == ' ' || *i == '\t') ) + { + if( bInGap == false ) + { + bInGap = true; + *i = '\0'; + } + } + else if( *i == '"' ) + { + bInQuote = !bInQuote; + } + else + { + if( bInGap ) + { + asParam[iParams++] = i; + bInGap = false; + } + } + } + + parse( iParams, asParam ); + + delete[] asParam; +} + +void Bu::OptParser::addOption( const Option &opt ) +{ + lOption.append( opt ); + if( opt.cOpt != '\0' ) + hsOption.insert( opt.cOpt, &lOption.last() ); + if( opt.sOpt.isSet() ) + hlOption.insert( opt.sOpt, &lOption.last() ); +} + +void Bu::OptParser::setOverride( char cOpt, const Bu::Variant &sOverride ) +{ + hsOption.get( cOpt )->sOverride = sOverride; +} + +void Bu::OptParser::setOverride( const Bu::String &sOpt, const Bu::Variant &sOverride ) +{ + hlOption.get( sOpt )->sOverride = sOverride; +} + +void Bu::OptParser::setHelpDefault( const Bu::String &sOpt, const Bu::String &sTxt ) +{ + hlOption.get( sOpt )->sHelpDefault = sTxt; +} + +void Bu::OptParser::addHelpOption( char c, const Bu::String &s, const Bu::String &sHelp ) +{ + Option o; + o.sUsed = slot( this, &OptParser::optHelp ); + o.cOpt = c; + o.sOpt = s; + o.sHelp = sHelp; + addOption( o ); +} + +void Bu::OptParser::addHelpBanner( const Bu::String &sText, bool bFormatted ) +{ + Banner b; + b.sText = sText; + b.bFormatted = bFormatted; + if( lOption.getSize() > 0 ) + { + for( b.iAfter = lOption.begin(); b.iAfter+1; b.iAfter++ ) { } + } + lBanner.append( b ); +} + +int Bu::OptParser::optHelp( StrArray /*aParams*/ ) +{ + bool bHasShort = false; + int iMaxWidth = 0; + int iScrWidth = 80; + char *env = getenv("COLUMNS"); + if( env ) + iScrWidth = strtol( env, NULL, 10 ); + for( OptionList::iterator i = lOption.begin(); i; i++ ) + { + if( (*i).cOpt != '\0' ) + bHasShort = true; + int lOptSize = (*i).sOpt.getSize() + (*i).sHelpDefault.getSize(); + if( (*i).sOpt.isSet() && iMaxWidth < lOptSize ) + iMaxWidth = lOptSize; + } + int iIndent = 4; + if( bHasShort ) + iIndent += 4; + if( iMaxWidth > 0 ) + iIndent += 4 + iMaxWidth; + + BannerList::iterator iBanner; + for( iBanner = lBanner.begin(); iBanner; iBanner++ ) + { + if( (*iBanner).iAfter ) + break; + + if( (*iBanner).bFormatted ) + sio << format( (*iBanner).sText, iScrWidth-1, 0 ); + else + sio << (*iBanner).sText; + sio << sio.nl; + } + for( OptionList::iterator i = lOption.begin(); i; i++ ) + { + sio << " "; + if( bHasShort ) + { + if( (*i).cOpt == '\0' ) + sio << " "; + else + sio << "-" << (*i).cOpt; + sio << " "; + } + if( iMaxWidth > 0 ) + { + if( (*i).sOpt.isSet() ) + { + sio << "--" << Fmt(iMaxWidth, Fmt::Left) + << (*i).sOpt + (*i).sHelpDefault; + } + else + { + sio << " " << Fmt(iMaxWidth) << ""; + } + sio << " "; + } + sio << format( (*i).sHelp, iScrWidth-iIndent-1, iIndent ); + sio << sio.nl; + + for( ; iBanner; iBanner++ ) + { + if( (*iBanner).iAfter != i ) + break; + + if( (*iBanner).bFormatted ) + sio << format( (*iBanner).sText, iScrWidth-1, 0 ); + else + sio << (*iBanner).sText; + sio << sio.nl; + } + } + exit( 0 ); + return 0; +} + +void Bu::OptParser::optionError( const Bu::String &sOption ) +{ + sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl; + exit( 1 ); +} + +void Bu::OptParser::setNonOption( OptionSignal sSignal ) +{ + sNonOption = sSignal; +} + +Bu::String Bu::OptParser::format( const Bu::String &sIn, int iWidth, + int iIndent ) +{ + Bu::String sOut; + Bu::String sIndent; + for( int j = 0; j < iIndent; j++ ) + sIndent.append(" ", 1); + bool bFirst = true; + int iSpaceCount = 0; + bool bSpace = false; + int iPrevLineLen; + int iLineLen = 0; + Bu::String::const_iterator iLastSpace, iStart; + for( Bu::String::const_iterator i = iLastSpace = iStart = sIn.begin(); i; i++ ) + { + if( *i == ' ' ) + { + if( bSpace == false ) + { + iLastSpace = i; + iSpaceCount++; + bSpace = true; + iPrevLineLen = iLineLen; + } + } + else + { + bSpace = false; + } + iLineLen++; + + if( iLineLen >= iWidth ) + { + iSpaceCount--; + if( bFirst == true ) + bFirst = false; + else + sOut += sIndent; + int iExtraSpaces = iWidth-iPrevLineLen; + bSpace = false; + float fFill = 0.0; + int iSubSpaceCount = 0; + float fAdd = ((float)iExtraSpaces/(float)iSpaceCount); + for( Bu::String::const_iterator k = iStart; k != iLastSpace; k++ ) + { + sOut += *k; + if( *k == ' ' ) + { + if( bSpace == false && iExtraSpaces > 0 ) + { + bSpace = true; + fFill += fAdd; + iSubSpaceCount++; + for( int sp = 0; sp < (int)(fFill); sp++ ) + { + sOut += ' '; + iExtraSpaces--; + } + fFill -= (int)fFill; + if( iSubSpaceCount == iSpaceCount && iExtraSpaces > 0 ) + { + for(; iExtraSpaces > 0; iExtraSpaces-- ) + { + sOut += ' '; + } + } + } + } + else + bSpace = false; + } + //sOut.append( iStart, iLastSpace ); + sOut.append("\n"); + for(; iLastSpace && *iLastSpace == ' '; iLastSpace++ ) { } + iStart = i = iLastSpace; + bSpace = false; + iLineLen = 1; + iSpaceCount = 0; + } + } + if( !bFirst ) + sOut += sIndent; + sOut.append( iStart ); + return sOut; +} + + +// +// Code for Bu::OptParser::_ValueProxy +// + +Bu::OptParser::_ValueProxy::_ValueProxy() +{ +} + +Bu::OptParser::_ValueProxy::~_ValueProxy() +{ +} + +// +// Code for Bu::OptParser::Option +// + +Bu::OptParser::Option::Option() : + cOpt( '\0' ), + pProxy( NULL ) +{ +} + +Bu::OptParser::Option::Option( const Option &rSrc ) : + cOpt( rSrc.cOpt ), + sOpt( rSrc.sOpt ), + sHelp( rSrc.sHelp ), + sUsed( rSrc.sUsed ), + pProxy( NULL ), + sOverride( rSrc.sOverride ) +{ + if( rSrc.pProxy ) + pProxy = rSrc.pProxy->clone(); +} + +Bu::OptParser::Option::~Option() +{ + delete pProxy; + pProxy = NULL; +} + -- cgit v1.2.3