#include <string.h>
#include <stdio.h> // for sprintf()
#include <stdarg.h>
#include <time.h>
#include "CString.h"
#include "PrivateTypes.h"
#pragma mark **** CString Public Instance Methods ****
CString::CString ( int sz )
{
mSize = 0;
mLength = 0;
mData = NULL;
Grow( sz );
}
CString::CString ( const char *str )
{
mSize = 0;
mLength = 0;
mData = NULL;
if ( ( str != NULL ) && *str )
{
Set( str );
}
else
{
Grow();
}
}
CString::CString ( const char *str, int len )
{
mSize = 0;
mLength = 0;
mData = NULL;
if ( ( str != NULL ) && *str && len )
{
Set( str, len );
}
else
{
Grow();
}
}
CString::CString ( const CString& cs )
{
mSize = 0;
mLength = 0;
mData = NULL;
if ( cs.mSize <= 0 ) throw( (SInt32)eParameterError );
Grow( cs.mSize );
if ( !cs.mLength )
{
return;
}
mLength = cs.mLength;
::strcpy( mData, cs.mData );
}
CString::CString ( const char *pattern, va_list args )
{
mSize = 0;
mLength = 0;
mData = NULL;
if ( pattern == nil ) throw((SInt32)eParameterError);
Grow();
Vsprintf( pattern, args );
}
CString::~CString()
{
if ( mData == NULL )
return;
delete mData;
mData = NULL;
mLength = 0;
mSize = 0;
}
int CString::GetLength ( void ) const
{
if ( mData != NULL )
{
return( ::strlen( mData ) );
}
else
{
return( 0 );
}
}
void CString::GetPascal ( unsigned char *pstr ) const
{
if ( pstr == nil ) throw( (SInt32)eParameterError );
if ( mLength > 255 ) throw( (SInt32)eParameterError );
*pstr++ = ( unsigned char ) mLength;
::memcpy( pstr, mData, mLength );
}
void CString::Set ( const char *str )
{
if ( str == nil ) throw((SInt32)eParameterError);
mLength = 0;
if ( !*str )
{
*mData = '\0';
return;
}
register int len = ::strlen ( str );
Grow( len + 1 );
strcpy( mData, str );
mLength = len;
}
void CString::Set ( const char *str, int len )
{
if ( str == nil ) throw( (SInt32)eParameterError );
if ( len < 0 ) throw( (SInt32)eParameterError );
mLength = 0;
if ( !len || !*str )
{
*mData = '\0';
return;
}
Grow( len + 1 );
register int strLen = ::strlen ( str );
mLength = ( ( strLen < len ) ? strLen : len );
::memcpy( mData, str, mLength );
mData[mLength] = '\0';
}
void CString::Set ( const unsigned char *pstr )
{
if ( pstr == nil ) throw((SInt32)eParameterError);
register int len = ( int ) *pstr++;
mLength = 0;
if ( !len )
{
*mData = '\0';
return;
}
Grow( len + 1 );
::memcpy( mData, pstr, len );
mLength = len;
mData[len] = '\0';
}
void CString::Set ( const CString &cs )
{
register int len = cs.mLength;
mLength = 0;
if ( !len )
{
*mData = '\0';
return;
}
Grow( len + 1 );
::strcpy( mData, cs.mData );
mLength = len;
}
void CString::Append ( char inChar )
{
Grow( mLength + 2 );
mData[mLength++] = inChar;
mData[mLength] = '\0';
}
void CString::Append ( const char *str )
{
if ( str == nil ) throw((SInt32)eParameterError);
if ( !*str )
return;
register int len = ::strlen ( str );
Grow( mLength + len + 1 );
::strcpy( &mData[mLength], str );
mLength += len;
}
void CString::Append ( const char *str, int arglen )
{
if ( str == nil ) throw( (SInt32)eParameterError );
if ( arglen < 0 ) throw( (SInt32)eParameterError );
if ( !arglen || !*str )
return;
register int len = ::strlen ( str );
if ( arglen < len )
{
len = arglen;
}
Grow( mLength + len + 1 );
::memcpy( &mData[mLength], str, len );
mLength += len;
mData[mLength] = '\0';
}
void CString::Append ( const unsigned char *pstr )
{
if ( pstr == nil ) throw((SInt32)eParameterError);
register int len = ( int ) *pstr++;
if ( !len )
{
return;
}
Grow( mLength + len + 1 );
::memcpy( &mData[mLength], pstr, len );
mLength += len;
mData[mLength] = '\0';
}
void CString::Append ( const CString &cs )
{
register int len = cs.mLength;
if ( !len )
return;
Grow( mLength + len + 1 );
::strcpy( &mData[mLength], cs.mData );
mLength += len;
}
void CString::Prepend ( const char *str )
{
if ( str == nil ) throw((SInt32)eParameterError);
if ( !*str )
return;
if ( !mLength )
{
Append ( str );
return;
}
register int len = ::strlen ( str );
register int newlen = mLength + len + 1;
if ( newlen > mSize )
{
register int pow2 = 16;
while ( pow2 < newlen )
pow2 <<= 1;
register char *newData = new char [pow2];
if ( newData == nil ) throw((SInt32)eMemoryAllocError);
::strcpy( newData, str );
::strcpy( &newData[len], mData );
delete []mData;
mSize = pow2;
mLength += len;
mData = newData;
}
else
{
register char *cpNew = &mData[--newlen];
register char *cpOld = &mData[( newlen = mLength )];
for ( newlen++; newlen--; )
*cpNew-- = *cpOld--;
::memcpy( mData, str, len );
mLength += len;
}
}
void CString::Clear ( int inNewSize )
{
*mData = '\0';
mLength = 0;
if ( inNewSize != 0 )
{
Grow( inNewSize );
}
}
void CString::Sprintf ( const char *inPattern, ... )
{
va_list args;
va_start ( args, inPattern );
this->Vsprintf( inPattern, args );
}
void CString::Vsprintf ( const char *pattern, va_list args )
{
char caTemp [kCStringDefSize + 32];
register char *cpTemp = caTemp;
UInt32 ulArg;
SInt32 lArg;
double dArg;
int nArg;
char *szpArg;
unsigned char *spArg;
FourCharCode fccArg;
CString *cspArg;
this->Clear();
for ( register const char *p = pattern; *p; p++ )
{
if ( ( cpTemp - caTemp ) > kCStringDefSize )
{
*cpTemp = '\0';
Append ( caTemp );
cpTemp = caTemp;
}
if ( *p != '%' )
{
*cpTemp++ = *p;
}
else
{
switch ( *++p )
{
case 'A':
ulArg = va_arg ( args, UInt32 );
cpTemp += ::sprintf ( cpTemp, "%ld.%ld.%ld.%ld",
((ulArg >> 24) & 0xFF),
((ulArg >> 16) & 0xFF),
((ulArg >> 8) & 0xFF),
(ulArg & 0xFF) );
break;
case 'D':
{
time_t tNow = ::time (NULL) ;
struct tm *tmTime = ::localtime(&tNow) ;
cpTemp += ::sprintf (cpTemp, "%04d-%02d-%02d",
tmTime->tm_year + 1900,
tmTime->tm_mon + 1,
tmTime->tm_mday) ;
}
break;
case 'F':
fccArg = va_arg ( args, FourCharCode );
*cpTemp++ = '\'';
*cpTemp++ = ((fccArg >> 24) & 0xFF);
*cpTemp++ = ((fccArg >> 16) & 0xFF);
*cpTemp++ = ((fccArg >> 8) & 0xFF);
*cpTemp++ = (fccArg & 0xFF);
*cpTemp++ = '\'';
break;
case 'P':
case 'p': spArg = va_arg ( args, unsigned char * );
if ( cpTemp != caTemp )
{
*cpTemp = '\0';
Append ( caTemp );
cpTemp = caTemp;
}
Append ( spArg );
break;
case 'S':
cspArg = va_arg ( args, CString * );
if ( cpTemp != caTemp )
{
*cpTemp = '\0';
Append ( caTemp );
cpTemp = caTemp;
}
if ( cspArg )
Append ( *cspArg );
break;
case 'T':
{
time_t tNow = ::time (NULL) ;
struct tm *tmTime = ::localtime(&tNow) ;
cpTemp += ::sprintf (cpTemp, "%02d:%02d:%02d %s",
tmTime->tm_hour,
tmTime->tm_min,
tmTime->tm_sec,
tmTime->tm_zone) ;
}
break;
case 'G':
{
cpTemp += ::sprintf (cpTemp, "DSDEBUG") ;
}
break;
case 'X':
ulArg = va_arg ( args, UInt32 );
cpTemp += ::sprintf ( cpTemp, "0x%08lX", ulArg );
break;
case 'u':
ulArg = va_arg ( args, UInt32 );
cpTemp += ::sprintf ( cpTemp, "%lu", ulArg );
break;
case 'l':
lArg = va_arg ( args, SInt32 );
cpTemp += ::sprintf ( cpTemp, "%ld", lArg );
break;
case 'c':
*cpTemp++ = va_arg ( args, int );
break;
case 'd':
nArg = va_arg ( args, int );
cpTemp += ::sprintf ( cpTemp, "%d", nArg );
break;
case 's':
szpArg = va_arg ( args, char * );
if ( cpTemp != caTemp )
{
*cpTemp = '\0';
Append ( caTemp );
cpTemp = caTemp;
}
if ( szpArg )
Append ( szpArg );
break;
case 'f':
case 'g':
dArg = va_arg ( args, double );
cpTemp += ::sprintf ( cpTemp, "%f", dArg );
break;
default:
cpTemp += ::sprintf ( cpTemp, " *** bad control string *** " );
}
}
}
if ( cpTemp != caTemp )
{
*cpTemp = '\0';
Append ( caTemp );
}
va_end ( args );
}
#pragma mark **** CString Protected Instance Methods ****
void CString::Grow( int newSize )
{
if ( newSize < 0 ) throw( (SInt32)eParameterError );
if ( !newSize )
{
newSize = kCStringDefSize;
}
if ( newSize <= mSize )
{
return;
}
if ( newSize != kCStringDefSize )
{
register int pow2 = 16;
while ( pow2 < newSize )
pow2 <<= 1;
newSize = pow2;
}
register char *newData = new char [newSize];
if ( newData == nil ) throw((SInt32)eMemoryAllocError);
if ( mLength )
{
::strcpy( newData, mData );
}
else
{
*newData = '\0';
}
if ( mData != NULL )
{
delete mData;
}
mSize = newSize;
mData = newData;
}