Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

513 lines
9.5 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1997
//
// File: bnstr.cpp
//
//--------------------------------------------------------------------------
//
// BNSTR.CPP
//
#include <stdarg.h>
#include <ctype.h>
#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<SZ>(_pmt) )
{
if ( sz )
{
Update( sz ) ;
}
}
BNSTR :: BNSTR ( const BNSTR & str )
: _cchMax( str._cchStr ),
_cchStr( str._cchStr ),
_sz( const_cast<SZ>(_pmt) )
{
if ( str._sz != _pmt )
{
_sz = ::SzCopy( str._sz ) ;
}
}
BNSTR :: ~ BNSTR ()
{
Reset() ;
}
void BNSTR :: Reset ()
{
DeleteSz() ;
_sz = const_cast<SZ>(_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