// CMabString.cpp : implementation file
//
// CMabString Implementation
//
// Portions Written by Michael A. Barnhart <mabtech@swbell.net>
// Copyright (c) MAB Tech 1995,1996,2000,2001
//
// Portions Written by Zafir Anjum
// Copyright (c) 1998
// http://www.codeguru.com
//
// Portions Written by Paul E. Bible <pbible@littlefishsoftware.com>
// Copyright (c) 2000. All Rights Reserved.
// http://www.codeproject.com
//
// This class is a merging of the code from the above authors.
// My original code had numeric conversion in c functions,
// which handled a controled field length and switch formats for maximum
// acuracy.
// Zafir's code added enhancements to the CString class which enhanced
// the parsing of numeric entries in a single line.
// Paul's coding style was very inline with Zafir's.
// This allowed a very easy merging of the two classes and thus the
// dependancy on CString to be removed.
// This eliminated problems with the migration of the CString class out
// of the MFC class in MFC version 7.
// Mixed into all of this was some evolution of functions as needed.
//
// My thanks to both of the above for sharing there work. Mike
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// HISTORY
// 12 Feb 2001 - Initial code merging.
//
/////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include <TCHAR.H>
#include <stdio.h>
#include "MabFString.h"
#include "math.h"
#include "float.h"
CMabString CMabString::m_csNAN("NaN");
CMabString CMabString::m_csNINF("-Inf");
CMabString CMabString::m_csPINF("+Inf");
//////////////////////////////////////////////////////////////////////
//
// Constructors/Destructor
//
//////////////////////////////////////////////////////////////////////
CMabString::CMabString()
{
m_pszString = NULL;
m_pszField = NULL;
AllocString(0);
}
CMabString::CMabString(CMabString& str)
{
m_pszString = NULL;
m_pszField = NULL;
int nLen = str.GetLength();
AllocString(nLen);
_tcsncpy(m_pszString, (LPCTSTR) str, nLen);
}
CMabString::CMabString(CString& str)
{
m_pszString = NULL;
m_pszField = NULL;
int nLen = str.GetLength();
AllocString(nLen);
_tcsncpy(m_pszString, (LPCTSTR) str, nLen);
}
CMabString::CMabString(LPCTSTR pszString)
{
m_pszString = NULL;
m_pszField = NULL;
int nLen = _tcslen(pszString);
AllocString(nLen);
_tcsncpy(m_pszString, pszString, nLen);
}
CMabString::CMabString(LPCTSTR pszString, int leng)
{
m_pszString = NULL;
m_pszField = NULL;
AllocString(leng);
_tcsncpy(m_pszString, pszString, leng);
}
CMabString::CMabString(BSTR bstrString)
{
m_pszString = NULL;
m_pszField = NULL;
USES_CONVERSION;
int nLen = _tcslen(OLE2T(bstrString));
AllocString(nLen);
_tcsncpy(m_pszString, OLE2T(bstrString), nLen);
}
CMabString::CMabString(TCHAR ch, int nRepeat)
{
m_pszString = NULL;
m_pszField = NULL;
if (nRepeat > 0)
{
AllocString(nRepeat);
#ifdef _UNICODE
for (int i=0; i < nRepeat; i++)
m_pszString[i] = ch;
#else
memset(m_pszString, ch, nRepeat);
#endif
}
}
CMabString::~CMabString()
{
if(m_pszString!=NULL) delete m_pszString;
}
//////////////////////////////////////////////////////////////////////
//
// Memory Manipulation
//
//////////////////////////////////////////////////////////////////////
void CMabString::AllocString(int nLen)
{
if(m_pszString!=NULL) delete m_pszString;
m_pszString = NULL;
if(nLen < 0) nLen=0;
m_iStrLen=nLen;
m_pszString = new char[nLen+1];//(TCHAR*) malloc((nLen+1) * sizeof(TCHAR));
ATLASSERT(m_pszString != NULL);
m_pszString[nLen] = '\0';
}
void CMabString::ReAllocString(int nLen)
{
// AllocString(nLen);
ATLASSERT(nLen >= 0);
m_pszString = (TCHAR*) realloc(m_pszString, (nLen+1) * sizeof(TCHAR));
ATLASSERT(m_pszString != NULL);
m_pszString[nLen] = '\0';
}
void CMabString::StringCopy(int nSrcLen, LPCTSTR lpszSrcData)
{
AllocString(nSrcLen);
memcpy(m_pszString, lpszSrcData, nSrcLen * sizeof(TCHAR));
m_pszString[nSrcLen] = '\0';
}
void CMabString::StringCopy(CMabString &str, int nLen, int nIndex, int nExtra) const
{
int nNewLen = nLen + nExtra;
if (nNewLen != 0)
{
str.AllocString(nNewLen);
memcpy(str.GetString(), m_pszString+nIndex, nLen * sizeof(TCHAR));
}
}
void CMabString::ConcatCopy(LPCTSTR lpszData)
{
ATLASSERT(lpszData != NULL);
// Save the existing string
int nLen = GetLength();
TCHAR* pszTemp = (TCHAR*) malloc((nLen+1) * sizeof(TCHAR));
memcpy(pszTemp, m_pszString, nLen * sizeof(TCHAR));
pszTemp[nLen] = '\0';
// Calculate the new string length and realloc memory
int nDataLen = _tcslen(lpszData);
int nNewLen = nLen + nDataLen;
ReAllocString(nNewLen);
// Copy the strings into the new buffer
memcpy(m_pszString, pszTemp, nLen * sizeof(TCHAR));
memcpy(m_pszString+nLen, lpszData, nDataLen * sizeof(TCHAR));
// Cleanup
free(pszTemp);
}
void CMabString::ConcatCopy(TCHAR ch)
{
// Save the existing string
int nLen = GetLength();
TCHAR* pszTemp = (TCHAR*) malloc((nLen+1) * sizeof(TCHAR));
memcpy(pszTemp, m_pszString, nLen * sizeof(TCHAR));
pszTemp[nLen] = '\0';
// Calculate the new string length and realloc memory
int nNewLen = nLen + 1;
ReAllocString(nNewLen);
// Copy the strings into the new buffer
memcpy(m_pszString, pszTemp, nLen * sizeof(TCHAR));
m_pszString[nNewLen-1] = ch;
// Cleanup
free(pszTemp);
}
void CMabString::ConcatCopy(LPCTSTR lpszData1, LPCTSTR lpszData2)
{
ATLASSERT(lpszData1 != NULL);
ATLASSERT(lpszData2 != NULL);
int nLen1 = _tcslen(lpszData1);
int nLen2 = _tcslen(lpszData2);
int nLen = nLen1 + nLen2;
AllocString(nLen);
memcpy(m_pszString, lpszData1, nLen1 * sizeof(TCHAR));
memcpy(m_pszString+nLen1, lpszData2, nLen2 * sizeof(TCHAR));
}
BSTR CMabString::AllocSysString()
{
#ifdef _UNICODE
BSTR bstr = ::SysAllocStringLen(m_pszString, GetLength());
if (bstr == NULL)
{
ATLASSERT(0);
return NULL;
}
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pszString, GetLength(), NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if (bstr == NULL)
{
ATLASSERT(0);
return NULL;
}
MultiByteToWideChar(CP_ACP, 0, m_pszString, GetLength(), bstr, nLen);
#endif
return bstr;
}
//////////////////////////////////////////////////////////////////////
//
// Accessors for the String as an Array
//
//////////////////////////////////////////////////////////////////////
void CMabString::Empty()
{
if (_tcslen(m_pszString) > 0)
m_pszString[0] = '\0';
}
TCHAR CMabString::GetAt(int nIndex)
{
int nLen = _tcslen(m_pszString);
ATLASSERT(nIndex >= 0);
ATLASSERT(nIndex < nLen);
return m_pszString[nIndex];
}
TCHAR CMabString::operator[] (int nIndex)
{
int nLen = _tcslen(m_pszString);
ATLASSERT(nIndex >= 0);
ATLASSERT(nIndex < nLen);
return m_pszString[nIndex];
}
void CMabString::SetAt(int nIndex, TCHAR ch)
{
int nLen = _tcslen(m_pszString);
ATLASSERT(nIndex >= 0);
ATLASSERT(nIndex < nLen);
m_pszString[nIndex] = ch;
}
int CMabString::GetLength() const
{
return _tcslen(m_pszString);
}
bool CMabString::IsEmpty() const
{
return (GetLength() > 0) ? false : true;
}
//////////////////////////////////////////////////////////////////////
//
// Conversions
//
//////////////////////////////////////////////////////////////////////
void CMabString::MakeUpper()
{
_tcsupr(m_pszString);
}
void CMabString::MakeLower()
{
_tcslwr(m_pszString);
}
void CMabString::MakeReverse()
{
_tcsrev(m_pszString);
}
void CMabString::TrimLeft()
{
LPTSTR lpsz = m_pszString;
while (_istspace(*lpsz))
lpsz = _tcsinc(lpsz);
if (lpsz != m_pszString)
{
memmove(m_pszString, lpsz, (GetLength()+1) * sizeof(TCHAR));
}
}
void CMabString::TrimRight()
{
LPTSTR lpsz = m_pszString;
LPTSTR lpszLast = NULL;
while (*lpsz != '\0')
{
if (_istspace(*lpsz))
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
lpszLast = NULL;
lpsz = _tcsinc(lpsz);
}
if (lpszLast != NULL)
*lpszLast = '\0';
}
//////////////////////////////////////////////////////////////////////
//
// Searching
//
//////////////////////////////////////////////////////////////////////
int CMabString::Find(TCHAR ch) const
{
return Find(ch, 0);
}
int CMabString::ReverseFind(TCHAR ch) const
{
int leng=GetLength();
while(leng>0)
{
leng--;
if(m_pszString[leng]==ch) return leng;
}
return -1;
}
int CMabString::Find(TCHAR ch, int nStart) const
{
if (nStart >= GetLength())
return -1;
LPTSTR lpsz = _tcschr(m_pszString + nStart, (_TUCHAR) ch);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pszString);
}
int CMabString::Find(LPCTSTR lpszSub)
{
return Find(lpszSub, 0);
}
int CMabString::Find(LPCTSTR lpszSub, int nStart)
{
ATLASSERT(_tcslen(lpszSub) > 0);
if (nStart > GetLength())
return -1;
LPTSTR lpsz = _tcsstr(m_pszString + nStart, lpszSub);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pszString);
}
int CMabString::FindOneOf(LPCTSTR lpszCharSet) const
{
LPTSTR lpsz = _tcspbrk(m_pszString, lpszCharSet);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pszString);
}
//////////////////////////////////////////////////////////////////////
//
// Assignment Operations
//
//////////////////////////////////////////////////////////////////////
const CMabString& CMabString::operator=(CMabString& strSrc)
{
if (m_pszString != strSrc.GetString())
StringCopy(strSrc.GetLength(), strSrc.GetString());
return *this;
}
const CMabString& CMabString::operator=(LPCTSTR lpsz)
{
ATLASSERT(lpsz != NULL);
StringCopy(_tcslen(lpsz), lpsz);
return *this;
}
const CMabString& CMabString::operator=(BSTR bstrStr)
{
USES_CONVERSION;
int nLen = _tcslen(OLE2T(bstrStr));
StringCopy(nLen, OLE2T(bstrStr));
return *this;
}
//////////////////////////////////////////////////////////////////////
//
// Concatenation
//
//////////////////////////////////////////////////////////////////////
CMabString operator+(CMabString& strSrc1, CMabString& strSrc2)
{
CMabString s;
s.ConcatCopy((LPCTSTR) strSrc1, (LPCTSTR) strSrc2);
return s;
}
CMabString operator+(CMabString& strSrc, LPCTSTR lpsz)
{
CMabString s;
s.ConcatCopy((LPCTSTR) strSrc, lpsz);
return s;
}
CMabString operator+(LPCTSTR lpsz, CMabString& strSrc)
{
CMabString s;
s.ConcatCopy(lpsz, (LPCTSTR) strSrc);
return s;
}
CMabString operator+(CMabString& strSrc, BSTR bstrStr)
{
USES_CONVERSION;
CMabString s;
s.ConcatCopy((LPCTSTR) strSrc, OLE2T(bstrStr));
return s;
}
CMabString operator+(BSTR bstrStr, CMabString& strSrc)
{
USES_CONVERSION;
CMabString s;
s.ConcatCopy(OLE2T(bstrStr), (LPCTSTR) strSrc);
return s;
}
const CMabString& CMabString::operator+=(CMabString& strSrc)
{
ConcatCopy((LPCTSTR) strSrc);
return *this;
}
const CMabString& CMabString::operator+=(LPCTSTR lpsz)
{
ConcatCopy(lpsz);
return *this;
}
const CMabString& CMabString::operator+=(BSTR bstrStr)
{
USES_CONVERSION;
ConcatCopy(OLE2T(bstrStr));
return *this;
}
const CMabString& CMabString::operator+=(TCHAR ch)
{
USES_CONVERSION;
ConcatCopy(ch);
return *this;
}
//////////////////////////////////////////////////////////////////////
//
// Extraction
//
//////////////////////////////////////////////////////////////////////
CMabString CMabString::Mid(int nFirst) const
{
return Mid(nFirst, GetLength() - nFirst);
}
CMabString CMabString::Mid(int nFirst, int nCount) const
{
if (nFirst < 0)
nFirst = 0;
if (nCount < 0)
nCount = 0;
if (nFirst + nCount > GetLength())
nCount = GetLength() - nFirst;
if (nFirst > GetLength())
nCount = 0;
ATLASSERT(nFirst >= 0);
ATLASSERT(nFirst + nCount <= GetLength());
if (nFirst == 0 && nFirst + nCount == GetLength())
return *this;
CMabString newStr;
StringCopy(newStr, nCount, nFirst, 0);
return newStr;
}
CMabString CMabString::Left(int nCount) const
{
if (nCount < 0)
nCount = 0;
if (nCount >= GetLength())
return *this;
CMabString newStr;
StringCopy(newStr, nCount, 0, 0);
return newStr;
}
CMabString CMabString::Right(int nCount) const
{
if (nCount < 0)
nCount = 0;
if (nCount >= GetLength())
return *this;
CMabString newStr;
StringCopy(newStr, nCount, GetLength() - nCount, 0);
return newStr;
}
CMabString CMabString::SpanIncluding(LPCTSTR lpszCharSet) const
{
ATLASSERT(lpszCharSet != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpszCharSet, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpszCharSet, -1) == 0);
#endif
return Left(_tcsspn(m_pszString, lpszCharSet));
}
CMabString CMabString::SpanExcluding(LPCTSTR lpszCharSet) const
{
ATLASSERT(lpszCharSet != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpszCharSet, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpszCharSet, -1) == 0);
#endif
return Left(_tcscspn(m_pszString, lpszCharSet));
}
//////////////////////////////////////////////////////////////////////
//
// Comparison
//
//////////////////////////////////////////////////////////////////////
int CMabString::Compare(CMabString& str) const
{
ATLASSERT((LPCTSTR) str != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW((LPCTSTR) str, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA((LPCTSTR) str, -1) == 0);
#endif
return _tcscmp(m_pszString, (LPCTSTR) str);
}
int CMabString::Compare(LPCTSTR lpsz) const
{
ATLASSERT(lpsz != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpsz, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpsz, -1) == 0);
#endif
return _tcscmp(m_pszString, lpsz);
}
int CMabString::CompareNoCase(CMabString& str) const
{
ATLASSERT((LPCTSTR) str != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW((LPCTSTR) str, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA((LPCTSTR) str, -1) == 0);
#endif
return _tcsicmp(m_pszString, (LPCTSTR) str);
}
int CMabString::CompareNoCase(LPCTSTR lpsz) const
{
ATLASSERT(lpsz != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpsz, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpsz, -1) == 0);
#endif
return _tcsicmp(m_pszString, lpsz);
}
int CMabString::Collate(LPCTSTR lpsz) const
{
ATLASSERT(lpsz != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpsz, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpsz, -1) == 0);
#endif
return _tcscoll(m_pszString, lpsz);
}
int CMabString::Collate(CMabString &str) const
{
ATLASSERT((LPCTSTR) str != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW((LPCTSTR) str, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA((LPCTSTR) str, -1) == 0);
#endif
return _tcscoll(m_pszString, (LPCTSTR) str);
}
int CMabString::CollateNoCase(LPCTSTR lpsz) const
{
ATLASSERT(lpsz != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW(lpsz, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA(lpsz, -1) == 0);
#endif
return _tcsicoll(m_pszString, lpsz);
}
int CMabString::CollateNoCase(CMabString &str) const
{
ATLASSERT((LPCTSTR) str != NULL);
#ifdef _UNICODE
ATLASSERT(::IsBadStringPtrW((LPCTSTR) str, -1) == 0);
#else
ATLASSERT(::IsBadStringPtrA((LPCTSTR) str, -1) == 0);
#endif
return _tcsicoll(m_pszString, (LPCTSTR) str);
}
//////////////////////////////////////////////////////////////////////
//
// Formatting
//
//////////////////////////////////////////////////////////////////////
void CMabString::Format(LPCTSTR pszCharSet, ...)
{
va_list vl;
va_start(vl, pszCharSet);
TCHAR* pszTemp = NULL;
int nBufferSize = 0;
int nRetVal = -1;
do {
nBufferSize += 100;
delete [] pszTemp;
pszTemp = new TCHAR[nBufferSize];
nRetVal = _vstprintf(pszTemp, pszCharSet, vl);
} while (nRetVal < 0);
int nNewLen = _tcslen(pszTemp);
AllocString(nNewLen);
_tcscpy(m_pszString, pszTemp);
delete [] pszTemp;
va_end(vl);
}
//////////////////////////////////////////////////////////////////////
//
// Replacing
//
//////////////////////////////////////////////////////////////////////
int CMabString::Replace(TCHAR chOld, TCHAR chNew)
{
int nCount = 0;
if (chOld != chNew)
{
LPTSTR psz = m_pszString;
LPTSTR pszEnd = psz + GetLength();
while(psz < pszEnd)
{
if (*psz == chOld)
{
*psz = chNew;
nCount++;
}
psz = _tcsinc(psz);
}
}
return nCount;
}
int CMabString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
{
int nSourceLen = _tcslen(lpszOld);
if (nSourceLen == 0)
return 0;
int nReplaceLen = _tcslen(lpszNew);
int nCount = 0;
LPTSTR lpszStart = m_pszString;
LPTSTR lpszEnd = lpszStart + GetLength();
LPTSTR lpszTarget;
// Check to see if any changes need to be made
while (lpszStart < lpszEnd)
{
while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
{
lpszStart = lpszTarget + nSourceLen;
nCount++;
}
lpszStart += _tcslen(lpszStart) + 1;
}
// Do the actual work
if (nCount > 0)
{
int nOldLen = GetLength();
int nNewLen = nOldLen + (nReplaceLen - nSourceLen) * nCount;
if (GetLength() < nNewLen)
{
CMabString szTemp = m_pszString;
ReAllocString(nNewLen);
memcpy(m_pszString, (LPCTSTR) szTemp, nOldLen * sizeof(TCHAR));
}
lpszStart = m_pszString;
lpszEnd = lpszStart + GetLength();
while (lpszStart < lpszEnd)
{
while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
{
int nBalance = nOldLen - (lpszTarget - m_pszString + nSourceLen);
memmove(lpszTarget + nReplaceLen, lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));
memcpy(lpszTarget, lpszNew, nReplaceLen * sizeof(TCHAR));
lpszStart = lpszTarget + nReplaceLen;
lpszStart[nBalance] = '\0';
nOldLen += (nReplaceLen - nSourceLen);
}
lpszStart += _tcslen(lpszStart) + 1;
}
ATLASSERT(m_pszString[GetLength()] == '\0');
}
return nCount;
}
LPTSTR CMabString::GetBuffer(int minlen)
{
// while(GetLength()<minlen) ConcatCopy(' ');
if(GetLength()<minlen) ReAllocString(minlen);
return m_pszString;
}
void CMabString::ReleaseBuffer(int minlen)
{
int minl = GetLength();
int m=minl;
if(minl<minlen) minl=minlen;
ReAllocString(minl);
// LPTSTR lpsz = m_pszString;
// m_pszString = (TCHAR*) malloc((minl+1) * sizeof(TCHAR));
// ATLASSERT(m_pszString != NULL);
// memset(m_pszString,'\0',minl+1);
// strncpy(m_pszString,lpsz,m);
// free(lpsz);
}
// Base operator fucntions
void CMabString::operator=(double val)
{
this->PutDouble(val);
}
void CMabString::operator=(float val)
{
this->PutFloat(val);
}
void CMabString::operator=(int val)
{
this->PutInt(val);
}
void CMabString::operator=(long val)
{
this->PutLong(val);
}
// Insert - Inserts a sub string into the string
// Returns - Reference to the same string object
// pos - Position to insert at. Extends the string with spaces if needed
// s - Sub string to insert
CMabString& CMabString::Insert(int pos, LPCTSTR s)
{
int len = lstrlen(s);
if ( len == 0 )
return *this;
int oldlen = GetLength();
int newlen = oldlen + len;
LPTSTR str;
if ( pos >= oldlen )
{
// insert after end of string
newlen += pos - oldlen ;
str = GetBuffer( newlen );
_tcsnset( str+oldlen, _T(' '), pos-oldlen );
_tcsncpy( str+pos, s, len );
}
else
{
// normal insert
str = GetBuffer( newlen );
memmove( str+pos+len, str+pos, sizeof(_T(' ')) *(oldlen-pos) );
_tcsncpy( str+pos, s, len );
}
ReleaseBuffer( newlen );
return *this;
}
// Insert - Inserts a character into the string
// Returns - Reference to the same string object
// pos - Position to insert at. Extends the string with spaces if needed
// c - Char to insert
CMabString& CMabString::Insert(int pos, TCHAR c)
{
TCHAR buf[2];
buf[0] = c;
buf[1] = _T('\0');
return Insert( pos, buf );
}
// Delete - Deletes a segment of the string and resizes it
// Returns - Reference to the same string object
// pos - Position of the string segment to remove
// len - Number of characters to remove
CMabString& CMabString::Delete(int pos, int len)
{
int strLen = GetLength();
if( pos >= strLen)
return *this;
if(len < 0 ||len > strLen - pos)
len = strLen - pos;
LPTSTR str = GetBuffer( strLen );
memmove(str+pos, str+pos+len, sizeof(_T(' ')) *(strLen-pos));
ReleaseBuffer( strLen - len );
return *this;
}
// Replace - Replaces a substring with another
// Returns - Reference to the same string object
// pos - Position of the substring
// len - Length of substring to be replaced
// s - New substring
CMabString& CMabString::Replace(int pos, int len, LPCTSTR s)
{
Delete(pos, len);
Insert(pos, s);
return *this;
}
// Find - Finds the position of a character in a string
// Returns - A zero-based index
// ch - Character to look for
// startpos - Position to start looking from
//int CMabString::Find( TCHAR ch, int startpos /*= 0*/ ) const
//{
// // find first single character
// LPTSTR lpsz = _tcschr(m_pszString + startpos, (_TUCHAR)ch);
//
// // return -1 if not found and index otherwise
// return (lpsz == NULL) ? -1 : (int)(lpsz - m_pszString);
//}
// Find - Finds the position of a substring in a string
// Returns - A zero-based index
// lpszSub - Substring to look for
// startpos - Position to start looking from
int CMabString::Find( LPCTSTR lpszSub, int startpos /*= 0*/ ) const
{
ASSERT(AfxIsValidString(lpszSub, FALSE));
// find first matching substring
LPTSTR lpsz = _tcsstr(m_pszString+startpos, lpszSub);
// return -1 for not found, distance from beginning otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pszString);
}
// FindNoCase - Case insensitive find
// Returns - A zero-based index
// ch - Char to search for
// startpos - Position to start looking from
int CMabString::FindNoCase( TCHAR ch, int startpos /*= 0*/ ) const
{
unsigned int locase = Find( tolower( ch ), startpos );
unsigned int upcase = Find( toupper( ch ), startpos );
return locase < upcase ? locase : upcase;
}
// FindNoCase - Case insensitive find
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from
int CMabString::FindNoCase( LPCTSTR lpszSub, int startpos /*= 0*/ ) const
{
CMabString sLowerThis = *this;
sLowerThis.MakeLower();
CMabString sLowerSub = lpszSub;
sLowerSub.MakeLower();
return sLowerThis.Find( sLowerSub, startpos );
}
// FindReplace - Find a substring and replace with another
// Returns - Number of instances replaced
// lpszSub - Substring to look for
// lpszReplaceWith - Substring to replace with
// bGlobal - Flag to indicate whether all occurances
// should be replaced
int CMabString::FindReplace( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith,
BOOL bGlobal /*= TRUE*/ )
{
int iReplaced = 0;
// find first matching substring
LPTSTR lpsz;
int pos = 0;
int lenSub = lstrlen( lpszSub );
int lenReplaceWith = lstrlen( lpszReplaceWith );
while( (lpsz = _tcsstr(m_pszString + pos, lpszSub)) != NULL )
{
pos = (int)(lpsz - m_pszString);
Replace( pos, lenSub, lpszReplaceWith );
pos += lenReplaceWith;
iReplaced++;
if( !bGlobal ) break;
}
return iReplaced;
}
// FindReplaceNoCase - Find a substring and replace with another
// Does case insensitive search
// Returns - Number of instances replaced
// lpszSub - Substring to look for
// lpszReplaceWith - Substring to replace with
// bGlobal - Flag to indicate whether all occurances
// should be replaced
int CMabString::FindReplaceNoCase( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith,
BOOL bGlobal /*= TRUE*/ )
{
CMabString sLowerThis = *this;
sLowerThis.MakeLower();
CMabString sLowerSub = lpszSub;
sLowerSub.MakeLower();
int iReplaced = 0;
// find first matching substring
LPTSTR lpsz;
int pos = 0, offset = 0;
int lenSub = lstrlen( lpszSub );
int lenReplaceWith = lstrlen( lpszReplaceWith );
while( (lpsz = _tcsstr(sLowerThis.m_pszString + pos, sLowerSub.m_pszString))
!= NULL )
{
pos = (int)(lpsz - sLowerThis.m_pszString);
Replace( pos+offset, lenSub, lpszReplaceWith );
offset += lenReplaceWith - lenSub;
pos += lenSub;
iReplaced++;
if( !bGlobal ) break;
}
return iReplaced;
}
// ReverseFind - Searches for the last match of a substring
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from, in reverse dir
int CMabString::ReverseFind( LPCTSTR lpszSub, int startpos /*= -1*/ ) const
{
int lenSub = lstrlen( lpszSub );
int len = lstrlen( m_pszString );
if(0 < lenSub && 0 < len)
{
if( startpos == -1 || startpos >= len ) startpos = len - 1;
for ( LPTSTR lpszReverse = m_pszString + startpos ;
lpszReverse != m_pszString ; --lpszReverse)
if (_tcsncmp(lpszSub, lpszReverse, lenSub ) == 0)
return (lpszReverse - m_pszString);
}
return -1;
}
// ReverseFindNoCase - Searches for the last match of a substring
// Search is case insensitive
// Returns - A zero-based index
// lpszSub - Character to search for
// startpos - Position to start looking from, in reverse dir
int CMabString::ReverseFindNoCase(TCHAR ch, int startpos /*= -1*/ ) const
{
TCHAR a[2];
a[1] = ch;
a[2] = 0;
return ReverseFindNoCase( a, startpos );
}
// ReverseFindNoCase - Searches for the last match of a substring
// Search is case insensitive
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from, in reverse dir
int CMabString::ReverseFindNoCase( LPCTSTR lpszSub, int startpos /*= -1*/ )
const
{
//LPTSTR lpszEnd = m_pszString + lstrlen
int lenSub = lstrlen( lpszSub );
int len = lstrlen( m_pszString );
if(0 < lenSub && 0 < len)
{
if( startpos == -1 || startpos >= len ) startpos = len - 1;
for ( LPTSTR lpszReverse = m_pszString + startpos ;
lpszReverse >= m_pszString ; --lpszReverse)
if (_tcsnicmp(lpszSub, lpszReverse, lenSub ) == 0)
return (lpszReverse - m_pszString);
}
return -1;
}
// GetField - Gets a delimited field
// Returns - A CMabString object that contains a copy of
// the specified field
// delim - The delimiter string
// fieldnum - The field index - zero is the first
// NOTE - Returns the whole string for field zero
// if delim not found
// Returns empty string if # of delim found
// is less than fieldnum
CMabString CMabString::GetField( LPCTSTR delim, int fieldnum)
{
LPTSTR lpsz, lpszRemainder = m_pszString, lpszret;
int retlen, lenDelim = lstrlen( delim );
while( fieldnum-- >= 0 )
{
lpszret = lpszRemainder;
lpsz = _tcsstr(lpszRemainder, delim);
if( lpsz )
{
// We did find the delim
retlen = lpsz - lpszRemainder;
lpszRemainder = lpsz + lenDelim;
}
else
{
retlen = lstrlen( lpszRemainder );
lpszRemainder += retlen; // change to empty string
}
}
return Mid( lpszret - m_pszString, retlen );
}
// GetField - Gets a delimited field
// Returns - A CMabString object that contains a copy of
// the specified field
// delim - The delimiter char
// fieldnum - The field index - zero is the first
// NOTE - Returns the whole string for field zero
// if delim not found
// Returns empty string if # of delim found
// is less than fieldnum
CMabString CMabString::GetField( TCHAR delim, int fieldnum)
{
LPTSTR lpsz, lpszRemainder = m_pszString, lpszret;
int retlen;
while( fieldnum-- >= 0 )
{
lpszret = lpszRemainder;
lpsz = _tcschr(lpszRemainder, (_TUCHAR)delim);
if( lpsz )
{
// We did find the delim
retlen = lpsz - lpszRemainder;
lpszRemainder = lpsz + 1;
}
else
{
retlen = lstrlen( lpszRemainder );
lpszRemainder += retlen; // change to empty string
}
}
return Mid( lpszret - m_pszString, retlen );
}
// GetFieldCount - Get number of fields in a string
// Returns - The number of fields
// Is always greater than zero
// delim - The delimiter character
int CMabString::GetFieldCount( TCHAR delim )
{
TCHAR a[2];
a[0] = delim;
a[1] = 0;
return GetFieldCount( a );
}
// GetFieldCount - Get number of fields in a string
// Returns - The number of fields
// Is always greater than zero
// delim - The delimiter string
int CMabString::GetFieldCount( LPCTSTR delim )
{
LPTSTR lpsz, lpszRemainder = m_pszString;
int lenDelim = lstrlen( delim );
int iCount = 1;
while( (lpsz = _tcsstr(lpszRemainder, delim)) != NULL )
{
lpszRemainder = lpsz + lenDelim;
iCount++;
}
return iCount;
}
// GetDelimitedField - Finds a field delimited on both ends
// Returns - A CMabString object that contains a copy of
// the specified field
// delimStart - Delimiter at the start of the field
// delimEnd - Delimiter at the end of the field
CMabString CMabString::GetDelimitedField( LPCTSTR delimStart, LPCTSTR delimEnd, int fieldnum /*= 0*/)
{
LPTSTR lpsz, lpszEnd, lpszRet, lpszRemainder = m_pszString ;
int lenDelimStart = lstrlen( delimStart ), lenDelimEnd = lstrlen( delimEnd );
while( fieldnum-- >= 0 )
{
lpsz = _tcsstr(lpszRemainder, delimStart);
if( lpsz )
{
// We did find the Start delim
lpszRet = lpszRemainder = lpsz + lenDelimStart;
lpszEnd = _tcsstr(lpszRemainder, delimEnd);
if( lpszEnd == NULL ) return"";
lpszRemainder = lpsz + lenDelimEnd;
}
else return "";
}
return Mid( lpszRet - m_pszString, lpszEnd - lpszRet );
}
// IsFLoat - test to see if a '.' exists (assumes you know it is a number)
// return - TRUE/FALSE
BOOL CMabString::IsFloat()
{
if(!Find(".")) return FALSE;
return TRUE;
}
// IsFLoat - test to see if a '.' does not exists (assumes you know it is a number)
// return - TRUE/FALSE
BOOL CMabString::IsInt()
{
if(Find(".")) return FALSE;
return TRUE;
}
// PutFloat - writes a floating point number into the test field with the specified length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutFloat(float value, int len, char ExpChar)
{
switch (_fpclass(value))
{
case _FPCLASS_SNAN:
case _FPCLASS_QNAN:
Format("%s", m_csNAN); // "NaN"
return;
case _FPCLASS_NINF:
Format("%s", m_csNINF);// "-Inf"
return;
case _FPCLASS_PINF:
Format("%s", m_csPINF);// "+Inf"
return;
}
if(!_finite(value))
{
Format("ERR");
return;
}
PutDouble((double)value, len, ExpChar);
// have we exceeded our acuracy?
int acc = 8;
if(len< acc+1) return;
Accuracy(acc,(int)ExpChar);
}
void CMabString::Accuracy(int acc,int ExpAscii)
{
int len = GetLength();
int i=0,i1;
if(GetAt(i)==35) return;
while(GetAt(i)==48 || GetAt(i)==45 || GetAt(i)==46)
{
if (GetAt(i)==ExpAscii) return;
i++;
if (i>=len) break;
}
i1=i-1;
if(acc+i1+1>len) i1=len-acc-1;
while(i<=acc+i1)
{
if(GetAt(i)==ExpAscii) return;
i++;
}
if(Find('.') > i-acc && Find('.') < i) i++;
for(;i<len;i++)
{
if(GetAt(i)==ExpAscii) return;
if(GetAt(i)!=46) SetAt(i,'0');
}
}
// PutFloat - writes a floating point number into the test field with
// the specified length of significant digits rather than total length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutFloatS(float value, int nsignificands, char ExpChar)
{
// Code From
// Copyright SOCABIM 1999
// Pierre Caussin
// Jean-Paul Retru
switch (_fpclass(value))
{
case _FPCLASS_SNAN:
case _FPCLASS_QNAN:
Format("%s", m_csNAN); // "NaN"
return;
case _FPCLASS_NINF:
Format("%s", m_csNINF);// "-Inf"
return;
case _FPCLASS_PINF:
Format("%s", m_csPINF);// "+Inf"
return;
}
if(!_finite(value))
{
Format("ERR");
return;
}
PutDoubleS((double) value, nsignificands, ExpChar);
int acc = 8;
if(nsignificands< acc+1) return;
Accuracy(acc,(int)ExpChar);
return;
}
// PutDoubleS - writes a double floating point number into the test field with
// the specified length of significant digits rather than total length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutDoubleS(double value, int nsignificands, char ExpChar)
{
Empty( );
// Code From
// Copyright SOCABIM 1999
// Pierre Caussin
// Jean-Paul Retru
CString fmt;
int nk;
switch (_fpclass(value))
{
case _FPCLASS_SNAN:
case _FPCLASS_QNAN:
Format("%s", m_csNAN); // "NaN"
return;
case _FPCLASS_NINF:
Format("%s", m_csNINF);// "-Inf"
return;
case _FPCLASS_PINF:
Format("%s", m_csPINF);// "+Inf"
return;
case _FPCLASS_NN:
case _FPCLASS_PN:
nk = (int)log10(fabs(value));
if (fabs(value)<1) nk--;
if (nk > nsignificands-1 || nk < -2)
{
fmt.Format("%%.%df%c%d",nsignificands-1,ExpChar,nk);
Format(fmt,value/pow(10.,nk));
}
else
{
if (nk == nsignificands-1 && nk>1)
fmt.Format("%%.%df.",0);
else
fmt.Format("%%.%df",nsignificands>nk+1?nsignificands-nk-1:0);
Format(fmt,value);
}
return;
default:
fmt.Format("%%.%df",nsignificands);
Format(fmt,0.);
}
int acc = 16;
Accuracy(acc,(int)ExpChar);
return;
}
// PutDouble - writes a double floating point number into the test field with
// the specified total length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutDouble(double value, int len, char ExpChar)
{
Empty( );
switch (_fpclass(value))
{
case _FPCLASS_SNAN:
case _FPCLASS_QNAN:
Format("%s", m_csNAN); // "NaN"
return;
case _FPCLASS_NINF:
Format("%s", m_csNINF);// "-Inf"
return;
case _FPCLASS_PINF:
Format("%s", m_csPINF);// "+Inf"
return;
}
if(!_finite(value))
{
Format("ERR");
return;
}
dtoan(GetBuffer(len),value,len);
ReleaseBuffer(len);
// have we exceeded our acuracy?
// This line replaces the "E" with the users exponent definition.
if(Find('E')>0 && ExpChar!=69) SetAt(Find('E')-1,ExpChar);
int acc = 16;
if(len< acc+1) return;
Accuracy(acc,(int)ExpChar);
}
// PutLong - writes a long integer number into the test field with
// the specified total length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutLong(long i, int len)
{
Empty( );
if(i>=0)
{
if(ltoan(GetBuffer(len),i,len))
ReleaseBuffer(len);
else
{
ReleaseBuffer(len);
Format("Error");
}
}
else
{
ltoan(GetBuffer(len),abs(i),len);
ReleaseBuffer(len);
i=0;
while(GetAt(i)==32) i++;
if(i>0) SetAt(i-1,'-');
else Format("Error");
}
}
// PutInt - writes a integer number into the test field with
// the specified total length
// Returns nothing
// Previous contents are destroyed
void CMabString::PutInt(int i, int len)
{
PutLong((long)i,len);
}
// GetFloat - read a floating point number from the field
// Returns float
// Previous contents are unchanged
float CMabString::GetFloat()
{
TestExp();
float f;
f = atofn(GetBuffer(GetLength()),GetLength());
return f;
}
// GetDouble - read a double floating point number from the field
// Returns double
// Previous contents are unchanged
double CMabString::GetDouble()
{
TestExp();
double f;
f = atodn(GetBuffer(GetLength()),GetLength());
return f;
}
// GetLong - read a long number from the field
// Returns long
// Previous contents are unchanged
long CMabString::GetLong()
{
long f;
f = atoln(GetBuffer(GetLength()),GetLength());
return f;
}
// GetInt - read an integer number from the field
// Returns int
// Previous contents are unchanged
int CMabString::GetInt()
{
return atoin(GetBuffer(GetLength()),GetLength());
}
// atodn - read a double floating point number from the field
// Returns double
// Previous contents are unchanged
inline double CMabString::atodn(char alpha[],int n)
{
double val;
char format[16];
char string[32];
sprintf(format,"%c%df",'%',n);
if(n>32) n=32;
strncpy(string,alpha,n);
string[n]='\0';
val=atof(string);
return (val);
}
// atofn - read a floating point number from the field
// Returns float
// Previous contents are unchanged
inline float CMabString::atofn(char *alpha,int n)
{
float val;
char format[16];
char string[32];
sprintf(format,"%c%df",'%',n);
if(n>32) n=32;
strncpy(string,alpha,n);
string[n]='\0';
val=(float)0.;
sscanf(string,format,&val);
return (val);
}
// atoin - read an integer number from the field
// Returns int
// Previous contents are unchanged
inline int CMabString::atoin(char *alpha,int n)
{
int val;
char format[32];
char string[32];
sprintf(format,"%c%dd",'%',n);
val=0;
if(n>32)n=32;
strncpy(string,alpha,n);
string[n]='\0';
sscanf(string,format,&val);
return (val);
}
// atoln - read a long number from the field
// Returns long
// Previous contents are unchanged
inline long int CMabString::atoln(char alpha[],int n)
{
long int val;
char string[32];
if(n>31) return(0);
strncpy(string,alpha,n);
string[n]='\0';
val=atol(string);
return (val);
}
// dtoan - write a double into a character field
// Returns nothing
// Previous contents are destroyed
inline void CMabString::dtoan(char *alpha,double val,int len)
{
if(len<4)
{
AfxMessageBox("Minimum String Length is 4 for error handling!");
return;
}
char format[16];
int exp,i;
unsigned int lenx;
char *temp;
// do we need to use exponential
if(val < 0.0) sprintf(format,"%9.2E",val);
else sprintf(format,"%9.2E",val);
exp=strlen(&format[6]);
exp=abs(atoin(&format[6],exp));
if( (val>=0 && exp+3 >len) || (val<0 && exp+4 >len) || (exp>2 && fabs(val)<1.0))
{ // use E format
lenx=len+11;
i=sizeof(char);
temp=(char near *)calloc(lenx,i);
if(val < 0.0) sprintf(format,"%c%d.%dE",'%',len-1,len-5);
else sprintf(format,"%c%d.%dE",'%',len,len-4);
sprintf(temp,format,val);
lenx=strlen(temp);
i=lenx-3;
do {
if(temp[i]=='0') strcpy(&temp[i],&temp[i+1]);
} while(i<(int)strlen(temp) && temp[i]=='0');
do {
i--;
} while(i>0 && temp[i]!='E');
if(temp[i]=='E' && temp[i+1]=='+') strcpy(&temp[i+1],&temp[i+2]);
while (len < (int) strlen(temp) && i>3)
{
i--;
strcpy(&temp[i],&temp[i+1]);
}
if((int)strlen(temp)>len) strcpy(alpha,"ERR");
else strcpy(alpha,temp);
free(temp);
}
else
{ // use f format
if(val < 0.0f) sprintf(format,"%c%d.%df",'%',len-1,len-3-exp);
else if (val< 0.) sprintf(format,"%c%d.%df",'%',len,len-3);
else if (val< 1.) sprintf(format,"%c%d.%df",'%',len,len-2);
else sprintf(format,"%c%d.%df",'%',len,len-2-exp);
sprintf(alpha,format,val);
}
return;
}
// itoan - write an integer character field
// Returns nothing
// Previous contents are destroyed
inline void CMabString::itoan(char alpha[],int n,int l)
{
int val;
int count;
char item;
for (count=1;count<=l;count++)
{
val=n-(n/10)*10;
itoa(val,&item,10);
alpha[l-count]=item;
n=n/10;
}
count=0;
while ((int)alpha[count]==48 && count<l-1)
{
alpha[count]=' ';
count++;
}
return;
}
// ltoan - write a long into a character field
// Returns bool
// Previous contents are destroyed
inline BOOL CMabString::ltoan(char alpha[],long int n,int l)
{
long int val;
int count;
char item;
BOOL ret=FALSE;
for (count=1;count<=l;count++)
{
val=n-(n/10)*10;
ltoa(val,&item,10);
alpha[l-count]=item;
n=n/10;
}
if(n==0) ret=TRUE;
count=0;
while ((int)alpha[count]==48 && count<l-1)
{
alpha[count]=' ';
count++;
}
return ret;
}
// TestExp - Cleanup the exponent in the scientific format string
// Returns nothing
// Previous contents are destroyed
void CMabString::TestExp()
{
int pos;
pos = max(ReverseFind('-'),ReverseFind('+'));
if(pos<2) return;
if(GetAt(pos-1)==32) return;
if(GetAt(pos-1)==69 || GetAt(pos-1)==101) return;
Insert(pos-1,'E');
}
// UsCur - formats the string to 2 sig digits.
// Returns nothing
// Previous contents are destroyed
void CMabString::UsCur()
{
double d;
d=GetDouble()+0.001;// round off?
if(d<0.01)
{
Empty();
return;
}
Format("%14.2f",d);
Trim();
}
// Fill - fills the string with specifed number of single chars
// Returns nothing
// Previous contents are destroyed
void CMabString::Fill(int len, char c)
{
int i;
int oldlen = GetLength();
char *buf;
buf = GetBuffer(len);
for(i=oldlen;i<len;i++) buf[i]=c;
buf[i] = (char) 0;
ReleaseBuffer();
}
// Trim - Trims both sides of string
// Returns nothing
// Previous contents are modified
void CMabString::Trim()
{
TrimLeft();
TrimRight();
}
// NoDoubleSpace - reomves all double spaces from the string
// Returns nothing
// Previous contents are modified
void CMabString::NoDoubleSpace()
{
while(Find(" ")>=0)
{
FindReplace(" "," ",TRUE);
}
}
// NoControlChar - replaces all control chars with blanks
// Returns nothing
// Previous contents are modififed
void CMabString::NoControlChar()
{
int i,j;
j=GetLength();
for(i=0;i<j;i++)
{
if(GetAt(i)<32) SetAt(i,' ');
}
}
// The following two functions of code assist in reading large strings that are
// really a collection of fields. The first field is read with the StepField
// fucntions that initalizes the reading. Subsequent fields are read with the
// next field functions that uses the previous location to start from. This has
// given me an order of magnitude increase in reading some blocks. (Specifically
// VRML-200X files.
CMabString CMabString::StepField(TCHAR delim)
{
m_pszField = m_pszString;
return NextField(delim);
}
CMabString CMabString::FirstField(TCHAR delim)
{
m_pszField = m_pszString;
return NextField(delim);
}
CMabString CMabString::NextField(TCHAR delim)
{
CMabString RetStr;
if(long(m_pszField-m_pszString) > m_iStrLen)
{
return RetStr;
}
long retlen;
LPTSTR lpsz = _tcschr(m_pszField, (_TUCHAR)delim);
if(lpsz)
{
retlen = lpsz-m_pszField;
RetStr.AllocString(retlen);
memcpy(RetStr.m_pszString,m_pszField,retlen);
m_pszField += retlen+1;
}
else if(m_pszField)
{
retlen = strlen(m_pszField);
RetStr.AllocString(retlen);
memcpy(RetStr.m_pszString,m_pszField,retlen);
m_pszField += retlen+1;
m_pszField=NULL;
}
return RetStr;
}
void CMabString::Remove(char c)
{
int pos = Find(c);
LPSTR lpsz;
int nLen = GetLength();
lpsz = (TCHAR*) malloc((nLen+1) * sizeof(TCHAR));
while(pos>=0)
{
memset((void*)lpsz,0,nLen+1);
_tcsncpy(lpsz, &m_pszString[pos+1], nLen-pos);
m_pszString[pos]=(char)0;
ConcatCopy(lpsz);
pos = Find(c);
}
free(lpsz);
}