/////////////////////////////////////////////////////////////////////////////
// StrManip.cpp : Implementation of some handy string manipulation routines.
//
#include "pch.h"
#include "..\Inc\TCLib.h"
#include "StrManip.h"
/////////////////////////////////////////////////////////////////////////////
// Group=
/////////////////////////////////////////////////////////////////////////////
// {secret}
int TCReplaceTextImpl(LPCTSTR pszSource, LPCTSTR pszFind, LPCTSTR pszReplace,
LPTSTR pszDest, int cchMaxDest, bool bIgnoreCase, int* pnOccurrences)
{
// Initialize the number of occurrences found
if (pnOccurrences)
*pnOccurrences = 0;
// Count the length of the source string
int cchSource = pszSource ? _tcslen(pszSource) : 0;
// If ignoring case, copy the source string and make it lowercase
LPCTSTR pszSource2;
if (cchSource)
{
if (bIgnoreCase)
{
LPTSTR pszTemp = LPTSTR(_alloca((cchSource + 1) * sizeof TCHAR));
_tcscpy(pszTemp, pszSource);
_tcslwr(pszTemp);
pszSource2 = pszTemp;
}
else
pszSource2 = pszSource;
}
// Count the length of the search phrase
int cchFind = pszFind ? _tcslen(pszFind) : 0;
// If ignoring case, copy the search phrase and make it lowercase
LPCTSTR pszFind2;
if (cchFind)
{
if (bIgnoreCase)
{
LPTSTR pszTemp = LPTSTR(_alloca((cchFind + 1) * sizeof TCHAR));
_tcscpy(pszTemp, pszFind);
_tcslwr(pszTemp);
pszFind2 = pszTemp;
}
else
pszFind2 = pszFind;
}
// Count the length of the replacement string
int cchReplace = pszReplace ? _tcslen(pszReplace) : 0;
// Ensure that cchMaxDest is zero if pszDest is NULL
if (!pszDest)
cchMaxDest = 0;
// Determine if pszDest is equal to pszSource (in-place operation)
else if (pszDest == pszSource)
{
// Ensure that the replacement phrase is no longer than the search phrase
if (cchReplace > cchFind)
return -1;
// If cchMaxDest is negative, use the length of the source string
if (cchMaxDest < 0)
cchMaxDest = cchSource + 1;
// Ensure that cchMaxDest characters will fit into the source string
else if (cchMaxDest > (cchSource + 1))
return -1;
}
// pszDest cannot be within pszSource
else if (pszDest > pszSource && pszDest <= pszSource + cchSource)
return -1;
// Otherwise cchMaxDest must be zero or positive
else if (cchMaxDest < 0)
return -1;
// Loop until search phrase is not found
int nOccurrences = 0, cchNeeded;
if (cchSource && cchFind)
{
LPCTSTR pszBegin = pszSource;
LPCTSTR pszBegin2 = pszSource2;
LPCTSTR pszFound;
while (NULL != (pszFound = _tcsstr(pszBegin2, pszFind2)))
{
// Increment the count of occurrences
++nOccurrences;
// Copy the string up to the first character of the search phrase
int cch = pszFound - pszBegin2;
if (cch < cchMaxDest)
_tcsncpy(pszDest, pszBegin, cch);
else
TC_tcscpyn(pszDest, pszBegin, cchMaxDest);
cchMaxDest = max(0, cchMaxDest - cch);
pszDest += cch;
// Copy the replacement string
if (cchReplace < cchMaxDest)
_tcsncpy(pszDest, pszReplace, cchReplace);
else
TC_tcscpyn(pszDest, pszReplace, cchMaxDest);
cchMaxDest = max(0, cchMaxDest - cchReplace);
pszDest += cchReplace;
// Increment the begining pointers past the search phrase
pszBegin += cch + cchFind;
pszBegin2 += cch + cchFind;
}
// Copy the remaining part of the string and ensure null-termination
TC_tcscpyn(pszDest, pszBegin, cchMaxDest);
// Compute the number of characters needed for the destination string
cchNeeded = nOccurrences * (cchReplace - cchFind) + cchSource;
}
else if (!cchFind)
{
TC_tcscpyn(pszDest, pszReplace, cchMaxDest);
nOccurrences = 1;
cchNeeded = cchReplace;
}
else
{
nOccurrences = 0;
cchNeeded = 0;
TC_tcscpyn(pszDest, NULL, cchMaxDest);
}
// Copy the number of occurrences of the search phrase that were found
if (pnOccurrences)
*pnOccurrences = nOccurrences;
// Return the number of characters needed for the destination string
return cchNeeded;
}
/////////////////////////////////////////////////////////////////////////////
// Description: Replaces occurences of a substring within another string.
//
// This function copies /pszSource/ to /pszDest/, replacing all occurrences
// of /pszFind/ with /pszReplace/.
//
// By specifying *NULL* for /pszDest/ or zero for /cchMaxDest/, the function
// simply counts the number of occurrences of /pszFind/ that are in
// /pszSource/ and computes the number of characters needed for the search
// and replace operation.
//
// Note: The search for /pszFind/ within /pszSource/ is performed sensitive
// to case. For a case-insensitive search and replace, use the
// TCReplaceTextNoCase function.
//
// Parameters:
// pszSource - [in] Points to a null-terminated string from which the
// function copies characters and searches for /pszFind/.
// pszFind - [in] Points to a null-terminated string which is to be
// replaced by /pszReplace/ when copying /pszSource/ to /pszDest/. If
// *NULL* or an empty string, the entire source string is replaced.
// pszReplace - [in] Points to a null-terminated string with which every
// occurrence of /pszFind/ is replaced when copying /pszSource/ to /pszDest/.
// If *NULL* or an empty string, all occurrences of /pszFind/ are removed.
// pszDest - [out] Points to a buffer into which the function copies
// characters. The buffer must be large enough to contain the number of
// characters specified by /cchMaxDest/, including room for a terminating
// null character. This may be *NULL*, in which case the function only counts
// the number of occurrences of /pszFind/ in /pszSource/ and computes the
// number of characters needed for the search and replace operation.
// cchMaxDest - [in] Specifies the maximum number of characters to be
// copied into the buffer pointed to by /pszDest/, including a terminating
// null character. This may be 0, in which case /pszDest/ is ignored and the
// function only counts the number of occurrences of /pszFind/ in
// /pszSource/ and computes the number of characters needed for the search
// and replace operation.
// pnOccurrences - [out] Points to a variable that receives the number of
// occurrences of /pszFind/ that were found in /pszSource/. This defaults to
// *NULL*, which specifies that the caller does not need this information.
//
// Return Value: The number of characters needed to hold the entire output
// string, not including the terminating null character. One of the MFC
// wrapper function overrides returns a *CString* object as the destination
// string.
//
// See Also: TCReplaceTextNoCase
int TCReplaceText(LPCTSTR pszSource, LPCTSTR pszFind, LPCTSTR pszReplace,
LPTSTR pszDest, int cchMaxDest, int* pnOccurrences)
{
// Delegate to TCReplaceTextImpl
return TCReplaceTextImpl(pszSource, pszFind, pszReplace, pszDest,
cchMaxDest, false, pnOccurrences);
}
/////////////////////////////////////////////////////////////////////////////
// Description: Replaces occurences of a substring within another string.
//
// This function copies /pszSource/ to /pszDest/, replacing all occurrences
// of /pszFind/ with /pszReplace/.
//
// By specifying *NULL* for /pszDest/ or zero for /cchMaxDest/, the function
// simply counts the number of occurrences of /pszFind/ that are in
// /pszSource/ and computes the number of characters needed for the search
// and replace operation.
//
// Note: The search for /pszFind/ within /pszSource/ is performed without
// regard to case. For a case-sensitive search and replace, use the
// TCReplaceText function.
//
// Parameters:
// pszSource - [in] Points to a null-terminated string from which the
// function copies characters and searches for /pszFind/.
// pszFind - [in] Points to a null-terminated string which is to be
// replaced by /pszReplace/ when copying /pszSource/ to /pszDest/. If
// *NULL* or an empty string, the entire source string is replaced.
// pszReplace - [in] Points to a null-terminated string with which every
// occurrence of /pszFind/ is replaced when copying /pszSource/ to /pszDest/.
// If *NULL* or an empty string, all occurrences of /pszFind/ are removed.
// pszDest - [out] Points to a buffer into which the function copies
// characters. The buffer must be large enough to contain the number of
// characters specified by /cchMaxDest/, including room for a terminating
// null character. This may be *NULL*, in which case the function only counts
// the number of occurrences of /pszFind/ in /pszSource/ and computes the
// number of characters needed for the search and replace operation.
// cchMaxDest - [in] Specifies the maximum number of characters to be
// copied into the buffer pointed to by /pszDest/, including a terminating
// null character. This may be 0, in which case /pszDest/ is ignored and the
// function only counts the number of occurrences of /pszFind/ in
// /pszSource/ and computes the number of characters needed for the search
// and replace operation.
// pnOccurrences - [out] Points to a variable that receives the number of
// occurrences of /pszFind/ that were found in /pszSource/. This defaults to
// *NULL*, which specifies that the caller does not need this information.
//
// Return Value: The number of characters needed to hold the entire output
// string, not including the terminating null character. One of the MFC
// wrapper function overrides returns a *CString* object as the destination
// string.
//
// See Also: TCReplaceText
int TCReplaceTextNoCase(LPCTSTR pszSource, LPCTSTR pszFind,
LPCTSTR pszReplace, LPTSTR pszDest, int cchMaxDest, int* pnOccurrences)
{
// Delegate to TCReplaceTextImpl
return TCReplaceTextImpl(pszSource, pszFind, pszReplace, pszDest,
cchMaxDest, true, pnOccurrences);
}
/////////////////////////////////////////////////////////////////////////////
// MFC Search and Replace Wrappers
#ifdef _AFX
///////////////////////////////////////////////////////////////////////////
CString TCReplaceText(CString strSource, CString strFind,
CString strReplace, int* pnOccurrences)
{
CString strDest;
TCReplaceText(strSource, strFind, strReplace, strDest, NULL);
return strDest;
}
///////////////////////////////////////////////////////////////////////////
// Parameters:
// strDest - [out] A reference to a *CString* object that receives the
// result of the search and replace operation.
int TCReplaceText(CString strSource, CString strFind, CString strReplace,
CString& strDest, int* pnOccurrences)
{
// Compute the number of characters needed for the destination string
int cchDest = TCReplaceText(strSource, strFind, strReplace, NULL, 0);
// Allocate the buffer in the specified CString
LPTSTR pszDest = strDest.GetBuffer(cchDest + 1);
// Call the non-MFC function overload
int cchDest2 = TCReplaceText(strSource, strFind, strReplace, pszDest,
cchDest + 1, pnOccurrences);
assert(cchDest2 == cchDest);
// Release the CString buffer
strDest.ReleaseBuffer(cchDest);
// Return the number of characters needed for the destination string
return cchDest;
}
///////////////////////////////////////////////////////////////////////////
CString TCReplaceTextNoCase(CString strSource, CString strFind,
CString strReplace, int* pnOccurrences)
{
CString strDest;
TCReplaceTextNoCase(strSource, strFind, strReplace, strDest, NULL);
return strDest;
}
///////////////////////////////////////////////////////////////////////////
// Parameters:
// strDest - [out] A reference to a *CString* object that receives the
// result of the search and replace operation.
int TCReplaceTextNoCase(CString strSource, CString strFind,
CString strReplace, CString& strDest, int* pnOccurrences)
{
// Compute the number of characters needed for the destination string
int cchDest = TCReplaceTextNoCase(strSource, strFind, strReplace, NULL,
0);
// Allocate the buffer in the specified CString
LPTSTR pszDest = strDest.GetBuffer(cchDest + 1);
// Call the non-MFC function overload
int cchDest2 = TCReplaceTextNoCase(strSource, strFind, strReplace,
pszDest, cchDest + 1, pnOccurrences);
assert(cchDest2 == cchDest);
// Release the CString buffer
strDest.ReleaseBuffer(cchDest);
// Return the number of characters needed for the destination string
return cchDest;
}
#endif // _AFX