//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1997 // // File: bnstr.cpp // //-------------------------------------------------------------------------- // // BNSTR.CPP // #include #include #include "bnstr.h" SZC BNSTR :: _pmt = "" ; static SZ SzCopy(SZC szc) { SZ szNew = szc ? new char[::strlen(szc) + 1] : NULL; return szNew ? ::strcpy(szNew, szc) : NULL; } BNSTR :: BNSTR ( SZC sz ) : _cchMax( 0 ), _cchStr( 0 ), _sz( const_cast(_pmt) ) { if ( sz ) { Update( sz ) ; } } BNSTR :: BNSTR ( const BNSTR & str ) : _cchMax( str._cchStr ), _cchStr( str._cchStr ), _sz( const_cast(_pmt) ) { if ( str._sz != _pmt ) { _sz = ::SzCopy( str._sz ) ; } } BNSTR :: ~ BNSTR () { Reset() ; } void BNSTR :: Reset () { DeleteSz() ; _sz = const_cast(_pmt) ; _cchStr = 0 ; _cchMax = 0 ; } // Protectively delete either the given string or the // private string. void BNSTR :: DeleteSz () { if ( _sz != NULL && _sz != _pmt ) { delete [] _sz ; _sz = NULL ; } } // Release the current buffer; reset the BNSTR. SZ BNSTR::Transfer () { SZ sz = _sz ; _sz = NULL ; Reset() ; return sz = _pmt ? NULL : sz ; } // Give the current buffer to a new string, reset *this. void BNSTR :: Transfer ( BNSTR & str ) { str.Reset() ; str._sz = _sz ; str._cchMax = _cchMax ; str._cchStr = _cchStr ; _sz = NULL ; Reset() ; } void BNSTR :: Trunc ( UINT cchLen ) { if ( _sz == _pmt ) return ; if ( cchLen < _cchStr ) _sz[cchLen] = 0 ; } // Update the pointed string. Since this routine is // used by the assignment operator, it's written to allow // for the new string being part of the old string. bool BNSTR :: Update ( SZC sz ) { bool bResult = true ; UINT cch = sz ? ::strlen( sz ) : 0 ; if ( cch > _cchMax ) { SZ szNew = ::SzCopy( sz ) ; if ( bResult = szNew != NULL ) { DeleteSz() ; _sz = szNew ; _cchMax = _cchStr = cch ; } } else if ( cch == 0 ) { Reset() ; } else { // REVIEW: this assumes that ::strcpy() handles overlapping regions correctly. ::strcpy( _sz, sz ) ; _cchStr = cch ; } return bResult ; } // Grow the string. if 'cchNewSize' == 0, expand by 50%. // If 'ppszNew' is given, store the new string there (for efficiency in // Prefix); note that this requires that we reallocate. bool BNSTR :: Grow ( UINT cchNewSize, SZ * ppszNew ) { UINT cchNew = cchNewSize == 0 ? (_cchMax + (_cchMax/2)) : cchNewSize ; bool bResult = true ; if ( cchNew > _cchMax || ppszNew ) { SZ sz = new char [cchNew+1] ; if ( bResult = sz != NULL ) { _cchMax = cchNew ; if ( ppszNew ) { *ppszNew = sz ; } else { ::strcpy( sz, _sz ) ; DeleteSz() ; _sz = sz ; } } } return bResult ; } // Expand the string to the given length; make it a blank, null terminated // string. bool BNSTR :: Pad ( UINT cchLength ) { // Expand as necessary if ( ! Grow( cchLength + 1 ) ) return false ; // If expanding, pad the string with spaces. while ( _cchStr < cchLength ) { _sz[_cchStr++] = ' ' ; } // Truncate to proper length _sz[_cchStr = cchLength] = 0 ; return true ; } bool BNSTR :: Assign ( SZC szcData, UINT cchLen ) { if ( ! Grow( cchLen + 1 ) ) return false ; ::memcpy( _sz, szcData, cchLen ) ; _sz[cchLen] = 0 ; _cchMax = _cchStr = cchLen ; return true ; } SZC BNSTR :: Prefix ( SZC szPrefix ) { assert( szPrefix != NULL ) ; UINT cch = ::strlen( szPrefix ) ; SZ sz ; if ( ! Grow( _cchStr + cch + 1, & sz ) ) return NULL ; ::strcpy( sz, szPrefix ) ; ::strcpy( sz + cch, _sz ) ; DeleteSz(); _cchStr += cch ; return _sz = sz ; } SZC BNSTR :: Suffix ( SZC szSuffix ) { if ( szSuffix ) { UINT cch = ::strlen( szSuffix ) ; if ( ! Grow( _cchStr + cch + 1 ) ) return NULL ; ::strcpy( _sz + _cchStr, szSuffix ) ; _cchStr += cch ; } return *this ; } SZC BNSTR :: Suffix ( char chSuffix ) { char rgch[2] ; rgch[0] = chSuffix ; rgch[1] = 0 ; return Suffix( rgch ); } INT BNSTR :: Compare ( SZC szSource, bool bIgnoreCase ) const { return bIgnoreCase ? ::stricmp( _sz, szSource ) : ::strcmp( _sz, szSource ); } // Comparison bool BNSTR :: operator == ( SZC szcSource ) const { return Compare( szcSource ) == 0 ; } bool BNSTR :: operator != ( SZC szSource ) const { return ! ((*this) == szSource) ; } char BNSTR :: operator [] ( UINT iChar ) const { assert( iChar < Length() ) ; return _sz[iChar] ; } bool BNSTR :: Vsprintf ( SZC szcFmt, va_list valist ) { // Attempt to "sprintf" the buffer. If it fails, reallocate // a larger buffer and try again. UINT cbMaxNew = ( _cchMax < 50 ? 50 : _cchMax ) + 1 ; do { if ( ! Grow( cbMaxNew ) ) { Reset() ; return false ; } // Cause buffer to grow by 50% on the next cycle (if necessary) cbMaxNew = 0 ; // Problem: If the buffer is not big enough, _sz may not have a '\0', and Grow() // will subsequently barf on the ::strcpy(). Quick fix: _sz[_cchMax] = '\0'; } while ( ::_vsnprintf( _sz, _cchMax, szcFmt, valist ) < 0 ) ; _sz[ _cchMax ] = '\0' ; // 'cause _vsnprintf, like _strncpy, doesn't always append this // Update the string length member _cchStr = ::strlen( _sz ) ; return true ; } bool BNSTR :: Sprintf ( SZC szcFmt, ... ) { va_list valist; va_start( valist, szcFmt ); bool bOk = Vsprintf( szcFmt, valist ) ; va_end( valist ); return bOk ; } bool BNSTR :: SprintfAppend ( SZC szcFmt, ... ) { BNSTR strTemp ; va_list valist; va_start( valist, szcFmt ); bool bOk = strTemp.Vsprintf( szcFmt, valist ) ; va_end( valist ); if ( bOk ) bOk = Suffix( strTemp ) != NULL ; return bOk ; } // Cr/Lf expansion or contraction bool BNSTR :: ExpandNl () { UINT iCh ; BNSTR str ; Transfer( str ) ; for ( iCh = 0 ; iCh < str.Length() ; iCh++ ) { char ch = str[iCh]; if ( ch == '\n' ) { if ( Suffix( '\r' ) == NULL ) return false ; } if ( Suffix( ch ) == NULL ) return false ; } return true ; } bool BNSTR :: ContractNl () { UINT iCh ; BNSTR str ; Transfer( str ) ; for ( iCh = 0 ; iCh < str.Length() ; iCh++ ) { char ch = str[iCh]; if ( ch != '\r' ) { if ( Suffix( ch ) == NULL ) return false ; } } return true ; } static char rgchEsc [][2] = { { '\a', 'a' }, { '\b', 'b' }, { '\f', 'f' }, { '\n', 'n' }, { '\r', 'r' }, { '\t', 't' }, { '\v', 'v' }, { '\'', '\'' }, { '\"', '\"' }, { '\?', '\?' }, { '\\', '\\' }, { 0, 0 } }; bool BNSTR :: ContractEscaped () { UINT iCh ; BNSTR str ; Transfer( str ) ; for ( iCh = 0 ; iCh < str.Length() ; iCh++ ) { char ch = str[iCh]; if ( ch == '\\' && str.Length() - iCh > 1 ) { char chEsc = 0; for ( UINT ie = 0 ; rgchEsc[ie][0] ; ie++ ) { if ( rgchEsc[ie][1] == ch ) break; } if ( chEsc = rgchEsc[ie][0] ) { iCh++; ch = chEsc; } } if ( Suffix( ch ) == NULL ) return false ; } return true ; } // Convert unprintable characters to their escaped versions bool BNSTR :: ExpandEscaped () { UINT iCh ; BNSTR str ; Transfer( str ) ; for ( iCh = 0 ; iCh < str.Length() ; iCh++ ) { char ch = str[iCh]; if ( ! isalnum(ch) ) { char chEsc = 0; for ( UINT ie = 0 ; rgchEsc[ie][0] ; ie++ ) { if ( rgchEsc[ie][0] == ch ) break; } if ( chEsc = rgchEsc[ie][1] ) { if ( Suffix('\\') == NULL ) return false; ch = chEsc; } } if ( Suffix( ch ) == NULL ) return false ; } return true ; } // Change all alphabetic characters to the given case void BNSTR :: UpCase ( bool bToUpper ) { if ( bToUpper ) ::strupr( _sz ); else ::strlwr( _sz ); } // // If the given expression string contains the symbolic name, // reconstruct it with the replacement name. bool BNSTR :: ReplaceSymName ( SZC szcSymName, SZC szcSymNameNew, bool bCaseInsensitive ) { SZC szcFound ; int cFound = 0 ; UINT cchOffset = 0 ; // Make a working copy of the sought symbolic name BNSTR strSym( szcSymName ); if ( bCaseInsensitive ) strSym.UpCase(); do { BNSTR strTemp( Szc() ); if ( bCaseInsensitive ) strTemp.UpCase() ; // Locate the symbolic name in the temporary copy. szcFound = ::strstr( strTemp.Szc()+cchOffset, strSym ) ; // If not found, we're done if ( szcFound == NULL ) break ; // Check to see if it's really a valid token; i.e., it's delimited. if ( ( szcFound == strTemp.Szc() || ! iscsym(*(szcFound-1)) ) && ( szcFound >= strTemp.Szc()+strTemp.Length()-strSym.Length() || ! iscsym(*(szcFound+strSym.Length())) ) ) { // Build new string from preceding characters, the new sym name // and trailing chars. BNSTR strExprNew ; UINT cchFound = szcFound - strTemp.Szc() ; strExprNew.Assign( Szc(), cchFound ); strExprNew += szcSymNameNew ; cchOffset = strExprNew.Length(); strExprNew += Szc() + cchFound + strSym.Length() ; Assign( strExprNew ); cFound++ ; } else { // It was imbedded in another token. Skip over it. cchOffset = szcFound - strTemp.Szc() + strSym.Length() ; } } while ( true ); return cFound > 0 ; } // Find the next occurrence of the given character in the string; // Return -1 if not found. INT BNSTR :: Index ( char chFind, UINT uiOffset ) const { if ( uiOffset >= _cchStr ) return -1 ; SZC szcFound = ::strchr( _sz, chFind ); return szcFound ? szcFound - _sz : -1 ; } // Convert the string to a floating-point number. double BNSTR :: Atof ( UINT uiOffset ) const { return uiOffset < _cchStr ? ::atof( _sz + uiOffset ) : -1 ; } // End of BNSTR.CXX