/************************************************************************
*
* Description : String handling utility functions.
*
* (c) Copyright 2000-2008 by Anna-Jayne Metcalfe (anna@riverblade.co.uk)
* and Beth Mackenzie (beth@riverblade.co.uk) / Riverblade Limited
*
* Licence Terms:
*
* This code may be freely reused, subject to the licence terms below.
* Please do let us know of any bugs you find or improvements you make,
* so that we can pass them on to the rest of the development community.
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the Code Project Open License (CPOL)
* version 1.0 (http://www.codeproject.com/info/cpol10.aspx).
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Code Project Open Licence for further details.
*
************************************************************************
* $Archive: /Projects/Applications/LintProject/Development/Shared/StringUtils.cpp $
* $Revision: 7 $
* $Date: 22/02/08 20:50 $
* $Author: Anna $
*
* $Nokeywords: $
************************************************************************/
/// \file
/// \brief String handling utility functions implementation.
#include "StdAfx.h"
#include "StringUtils.h"
/// \brief Non-exported implementation function to strip trailing decimal points from numeric strings.
///
/// \param sTarget A reference to the string which should be checked.
///
static void StripPeriod(CString& sTarget)
{
if (_T(".") == sTarget.Right(1) )
{
sTarget = Riverblade::Libraries::Utils::Before(sTarget, _T(".") );
}
}
namespace Riverblade
{
namespace Libraries
{
/// \brief Return the source string up to, but not including, the target.
///
/// \param sSource A reference to the source string.
/// \param pszTarget A NULL terminated string containing the string to search for.
/// \return The contents of the source string up to, but not including, the target.
///
CString Utils::Before(const CString& sSource, LPCTSTR const pszTarget)
{
const int nTargetPos = sSource.Find(pszTarget);
if (-1 == nTargetPos)
{
return sSource; // target not present; return all
}
return sSource.Left(nTargetPos);
}
/// \brief Return the source string up to, but not including, the target (case insensitive).
///
/// \param sSource A reference to the source string.
/// \param pszTarget A NULL terminated string containing the string to search for.
/// \return The contents of the source string up to, but not including, the target.
///
CString Utils::BeforeNoCase(const CString& sSource, LPCTSTR const pszTarget)
{
CString sTemp(sSource);
CString sTarget(pszTarget);
sTemp.MakeLower();
sTarget.MakeLower();
const int nTargetPos = sTemp.Find(sTarget);
if (-1 == nTargetPos)
{
return sSource; // target not present; return all
}
return sSource.Left(nTargetPos);
}
/// \brief Return the source string after, but not including, the target.
///
/// \param sSource A reference to the source string.
/// \param pszTarget A NULL terminated string containing the string to search for.
/// \return The contents of the source string after, but not including, the target.
///
CString Utils::After(const CString& sSource, LPCTSTR const pszTarget)
{
const int nTargetPos = sSource.Find(pszTarget);
if (-1 != nTargetPos) // Found?
{
const int nChars = sSource.GetLength() - (nTargetPos + lstrlen(pszTarget));
if (nChars > 0) // Something after the target...
return (sSource.Right(nChars));
}
return _T(""); // Nowt after target
}
/// \brief Return the source string after, but not including, the target (case insensitive).
///
/// \param sSource A reference to the source string.
/// \param pszTarget A NULL terminated string containing the string to search for.
/// \return The contents of the source string after, but not including, the target.
///
CString Utils::AfterNoCase(const CString& sSource, LPCTSTR const pszTarget)
{
CString sTemp(sSource);
CString sTarget(pszTarget);
sTemp.MakeLower();
sTarget.MakeLower();
const int nTargetPos = sTemp.Find(sTarget);
if (-1 != nTargetPos) // Found?
{
const int nChars = sSource.GetLength() - (nTargetPos + ::lstrlen(pszTarget) );
if (nChars > 0) // Something after the target...
{
return (sSource.Right(nChars) );
}
}
return _T(""); // Nowt after target
}
/// \brief Return the source string between two target strings.
///
/// \param sSource A reference to the source string.
/// \param pszStartAfter A NULL terminated string containing the string to start after.
/// \param pszStopBefore A NULL terminated string containing the string to stop before.
/// \return The contents of the source string between the two targets.
///
CString Utils::Between(const CString& sSource, LPCTSTR const pszStartAfter, LPCTSTR const pszStopBefore)
{
return Before(After(sSource, pszStartAfter), pszStopBefore);
}
/// \brief Chomp the next parameter out of the given string, consuming it in the process.
///
/// \param rsSource A reference to the source string (this will be consumed by repeated calls).
/// \param pszDelimiter A NULL terminated string containing the delimiter to search for.
/// \param bSkipEmptyFields \em true if empty fields should be skipped; false otherwise.
/// \return The next parameter from the source string.
///
CString Utils::Chomp(CString& rsSource, LPCTSTR const pszDelimiter /*= _T(",")*/, const bool bSkipEmptyFields /*= true*/)
{
CString sParam;
// Loop until we either found a non-null parameter or we run out of string
while (!rsSource.IsEmpty() )
{
// Extract the string up to, but not including, the delimiter
sParam = Before(rsSource, pszDelimiter);
// Remove the parameter and delimiter from the original string
rsSource = After(rsSource, sParam + pszDelimiter);
if (!sParam.IsEmpty() || !bSkipEmptyFields)
{
break;
}
}
return sParam;
}
/// \brief Simple and easy method to convert an integer value to a string.
///
/// \param nValue The value to convert.
/// \return A string representation of nValue.
///
CString Utils::IntToStr(int nValue)
{
#if (_MSC_VER >= 1400)
const int nBufferSize = 15;
CString sResult;
LPTSTR pszValue = sResult.GetBuffer(nBufferSize);
::_itot_s(nValue, pszValue, nBufferSize, 10);
sResult.ReleaseBuffer();
#else
TCHAR chTemp[15];
CString sResult = ::_itot(nValue, chTemp, 10);
#endif
::StripPeriod(sResult);
return sResult;
}
/// \brief Convert the given string to an array.
///
/// \param sText A reference to a string containing the (newline delimited) text.
/// \param rarrayText A reference to the array to copy the text into.
/// \return The number of items in the array on completion.
///
CString Utils::ArrayToStr( const CAtlArray<CString>& arrayText, const CString& sDelimiter /*= _T("\r\n")*/)
{
CString sText;
for (size_t uLine = 0; uLine < arrayText.GetCount(); ++uLine)
{
sText += (arrayText[uLine] + sDelimiter);
}
return sText;
}
/// \brief Convert the given string to an array.
///
/// \param sText A reference to a string containing the (newline delimited) text.
/// \param rarrayText A reference to the array to copy the text into.
/// \return The number of items in the array on completion.
///
size_t Utils::StrToArray(const CString& sText, CAtlArray<CString>& rarrayText)
{
ATLVERIFY(rarrayText.SetCount(0, 100) );
if (!sText.IsEmpty() )
{
const TCHAR chDelim = _T('\n');
const int nLength = sText.GetLength();
int nPosLineStart = 0;
CString sLine;
while (nPosLineStart < nLength)
{
const int nPosLineEnd = sText.Find(chDelim, nPosLineStart);
if (nPosLineEnd >= 0)
{
sLine = sText.Mid(nPosLineStart, nPosLineEnd - nPosLineStart);
}
else
{
sLine = sText.Mid(nPosLineStart);
}
(void)sLine.TrimRight( _T("\r") ); // Strip any trailing \r
(void)rarrayText.Add(sLine);
if (nPosLineEnd < 0)
{
break;
}
nPosLineStart = nPosLineEnd + 1;
}
}
return rarrayText.GetCount();
}
/// \brief Replaces tabs with spaces in the list
///
CString Utils::ExpandTabs(const CString& sSrc, const int nTabSize /*= 4*/)
{
CString sResult;
for (int n = 0; n < sSrc.GetLength(); n++)
{
const TCHAR ch = sSrc[n];
if ( _T('\t') == ch)
{
const int nLen = sResult.GetLength();
const int nSpaces = (nTabSize - (nLen % nTabSize) );
sResult += CString( _T(' '), nSpaces);
}
else
{
sResult += ch;
}
}
return sResult;
}
}; // namespace Libraries
}; // namespace Riverblade