Click here to Skip to main content
15,884,353 members
Articles / Desktop Programming / MFC

A simple XML Parser

Rate me:
Please Sign up or sign in to vote.
4.69/5 (13 votes)
28 Jan 2002CPOL 361.4K   5.8K   70  
A class to read and write non validated XML files
// 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);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Retired
United States United States
Began programming in 1968 on a Wang 720. Move to Fortran and began developing FEM (finite element model) applications on an IBM 360 in 1973. Developed custom FEM editors for most of my career until 1995.

Comments and Discussions