| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
- #include "stdafx.h"
- // WINSCP
- #include <algorithm>
- #define max std::max
- #define min std::min
- //////////////////////////////////////////////////////////////////////////////
- // More sophisticated construction
- CString::CString(LPCTSTR lpch, int nLength)
- {
- Init();
- if (nLength != 0)
- {
- ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
- AllocBuffer(nLength);
- memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- // Special conversion constructors
- CString::CString(LPCSTR lpsz, int nLength)
- {
- Init();
- if (nLength != 0)
- {
- AllocBuffer(nLength);
- int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
- ReleaseBuffer(n >= 0 ? n : -1);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- // Assignment operators
- const CString& CString::operator=(TCHAR ch)
- {
- AssignCopy(1, &ch);
- return *this;
- }
- //////////////////////////////////////////////////////////////////////////////
- // less common string expressions
- CString AFXAPI operator+(const CString& string1, TCHAR ch)
- {
- CString s;
- s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
- return s;
- }
- CString AFXAPI operator+(TCHAR ch, const CString& string)
- {
- CString s;
- s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
- return s;
- }
- //////////////////////////////////////////////////////////////////////////////
- // Advanced manipulation
- int CString::Delete(int nIndex, int nCount /* = 1 */)
- {
- if (nIndex < 0)
- nIndex = 0;
- int nNewLength = GetData()->nDataLength;
- if (nCount > 0 && nIndex < nNewLength)
- {
- CopyBeforeWrite();
- int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
- memcpy(m_pchData + nIndex,
- m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
- GetData()->nDataLength = nNewLength - nCount;
- }
- return nNewLength;
- }
- int CString::Replace(TCHAR chOld, TCHAR chNew)
- {
- int nCount = 0;
- // short-circuit the nop case
- if (chOld != chNew)
- {
- // otherwise modify each character that matches in the string
- CopyBeforeWrite();
- LPTSTR psz = m_pchData;
- LPTSTR pszEnd = psz + GetData()->nDataLength;
- while (psz < pszEnd)
- {
- // replace instances of the specified character only
- if (*psz == chOld)
- {
- *psz = chNew;
- nCount++;
- }
- psz = _tcsinc(psz);
- }
- }
- return nCount;
- }
- int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
- {
- // can't have empty or NULL lpszOld
- int nSourceLen = SafeStrlen(lpszOld);
- if (nSourceLen == 0)
- return 0;
- int nReplacementLen = SafeStrlen(lpszNew);
- // loop once to figure out the size of the result string
- int nCount = 0;
- LPTSTR lpszStart = m_pchData;
- LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
- LPTSTR lpszTarget;
- while (lpszStart < lpszEnd)
- {
- while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
- {
- nCount++;
- lpszStart = lpszTarget + nSourceLen;
- }
- lpszStart += lstrlen(lpszStart) + 1;
- }
- // if any changes were made, make them
- if (nCount > 0)
- {
- CopyBeforeWrite();
- // if the buffer is too small, just
- // allocate a new buffer (slow but sure)
- int nOldLength = GetData()->nDataLength;
- int nNewLength = nOldLength + (nReplacementLen-nSourceLen)*nCount;
- if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
- {
- CStringData* pOldData = GetData();
- LPTSTR pstr = m_pchData;
- AllocBuffer(nNewLength);
- memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
- CString::Release(pOldData);
- }
- // else, we just do it in-place
- lpszStart = m_pchData;
- lpszEnd = m_pchData + GetData()->nDataLength;
- // loop again to actually do the work
- while (lpszStart < lpszEnd)
- {
- while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
- {
- int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen);
- memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
- nBalance * sizeof(TCHAR));
- memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
- lpszStart = lpszTarget + nReplacementLen;
- lpszStart[nBalance] = '\0';
- nOldLength += (nReplacementLen - nSourceLen);
- }
- lpszStart += lstrlen(lpszStart) + 1;
- }
- ASSERT(m_pchData[nNewLength] == '\0');
- GetData()->nDataLength = nNewLength;
- }
- return nCount;
- }
- //////////////////////////////////////////////////////////////////////////////
- // Very simple sub-string extraction
- CString CString::Mid(int nFirst) const
- {
- return Mid(nFirst, GetData()->nDataLength - nFirst);
- }
- CString CString::Mid(int nFirst, int nCount) const
- {
- // out-of-bounds requests return sensible things
- if (nFirst < 0)
- nFirst = 0;
- if (nCount < 0)
- nCount = 0;
- if (nFirst + nCount > GetData()->nDataLength)
- nCount = GetData()->nDataLength - nFirst;
- if (nFirst > GetData()->nDataLength)
- nCount = 0;
- ASSERT(nFirst >= 0);
- ASSERT(nFirst + nCount <= GetData()->nDataLength);
- // optimize case of returning entire string
- if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
- return *this;
- CString dest;
- AllocCopy(dest, nCount, nFirst, 0);
- return dest;
- }
- CString CString::Right(int nCount) const
- {
- if (nCount < 0)
- nCount = 0;
- if (nCount >= GetData()->nDataLength)
- return *this;
- CString dest;
- AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
- return dest;
- }
- CString CString::Left(int nCount) const
- {
- if (nCount < 0)
- nCount = 0;
- if (nCount >= GetData()->nDataLength)
- return *this;
- CString dest;
- AllocCopy(dest, nCount, 0, 0);
- return dest;
- }
- //////////////////////////////////////////////////////////////////////////////
- // Finding
- int CString::ReverseFind(TCHAR ch) const
- {
- // find last single character
- LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
- // return -1 if not found, distance from beginning otherwise
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
- }
- // find a sub-string (like strstr)
- int CString::Find(LPCTSTR lpszSub) const
- {
- return Find(lpszSub, 0);
- }
- int CString::Find(LPCTSTR lpszSub, int nStart) const
- {
- ASSERT(AfxIsValidString(lpszSub));
- int nLength = GetData()->nDataLength;
- if (nStart > nLength)
- return -1;
- // find first matching substring
- LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
- // return -1 for not found, distance from beginning otherwise
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CString formatting
- #define TCHAR_ARG TCHAR
- #define WCHAR_ARG WCHAR
- #define CHAR_ARG char
- #ifdef _X86_
- #define DOUBLE_ARG _AFX_DOUBLE
- #else
- #define DOUBLE_ARG double
- #endif
- #define FORCE_ANSI 0x10000
- #define FORCE_UNICODE 0x20000
- #define FORCE_INT64 0x40000
- #define _tclen(__a) (1)
- void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
- {
- ASSERT(AfxIsValidString(lpszFormat));
- va_list argListSave = argList;
- // make a guess at the maximum length of the resulting string
- int nMaxLen = 0;
- for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
- {
- // handle '%' character, but watch out for '%%'
- if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
- {
- nMaxLen += _tclen(lpsz);
- continue;
- }
- int nItemLen = 0;
- // handle '%' character with format
- int nWidth = 0;
- for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
- {
- // check for valid flags
- if (*lpsz == '#')
- nMaxLen += 2; // for '0x'
- else if (*lpsz == '*')
- nWidth = va_arg(argList, int);
- else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
- *lpsz == ' ')
- ;
- else // hit non-flag character
- break;
- }
- // get width and skip it
- if (nWidth == 0)
- {
- // width indicated by
- nWidth = _ttoi(lpsz);
- for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
- ;
- }
- ASSERT(nWidth >= 0);
- int nPrecision = 0;
- if (*lpsz == '.')
- {
- // skip past '.' separator (width.precision)
- lpsz = _tcsinc(lpsz);
- // get precision and skip it
- if (*lpsz == '*')
- {
- nPrecision = va_arg(argList, int);
- lpsz = _tcsinc(lpsz);
- }
- else
- {
- nPrecision = _ttoi(lpsz);
- for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
- ;
- }
- ASSERT(nPrecision >= 0);
- }
- // should be on type modifier or specifier
- int nModifier = 0;
- if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
- {
- lpsz += 3;
- nModifier = FORCE_INT64;
- #if !defined(_X86_) && !defined(_ALPHA_)
- // __int64 is only available on X86 and ALPHA platforms
- ASSERT(FALSE);
- #endif
- }
- else
- {
- switch (*lpsz)
- {
- // modifiers that affect size
- case 'h':
- nModifier = FORCE_ANSI;
- lpsz = _tcsinc(lpsz);
- break;
- case 'l':
- nModifier = FORCE_UNICODE;
- lpsz = _tcsinc(lpsz);
- break;
- // modifiers that do not affect size
- case 'F':
- case 'N':
- case 'L':
- lpsz = _tcsinc(lpsz);
- break;
- }
- }
- // now should be on specifier
- switch (*lpsz | nModifier)
- {
- // single characters
- case 'c':
- case 'C':
- nItemLen = 2;
- va_arg(argList, TCHAR_ARG);
- break;
- case 'c'|FORCE_ANSI:
- case 'C'|FORCE_ANSI:
- nItemLen = 2;
- va_arg(argList, CHAR_ARG);
- break;
- case 'c'|FORCE_UNICODE:
- case 'C'|FORCE_UNICODE:
- nItemLen = 2;
- va_arg(argList, WCHAR_ARG);
- break;
- // strings
- case 's':
- {
- LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
- if (pstrNextArg == NULL)
- nItemLen = 6; // "(null)"
- else
- {
- nItemLen = lstrlen(pstrNextArg);
- nItemLen = max(1, nItemLen);
- }
- }
- break;
- case 'S':
- {
- LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
- if (pstrNextArg == NULL)
- nItemLen = 6; // "(null)"
- else
- {
- nItemLen = lstrlenA(pstrNextArg);
- nItemLen = max(1, nItemLen);
- }
- }
- break;
- case 's'|FORCE_ANSI:
- case 'S'|FORCE_ANSI:
- {
- LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
- if (pstrNextArg == NULL)
- nItemLen = 6; // "(null)"
- else
- {
- nItemLen = lstrlenA(pstrNextArg);
- nItemLen = max(1, nItemLen);
- }
- }
- break;
- case 's'|FORCE_UNICODE:
- case 'S'|FORCE_UNICODE:
- {
- LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
- if (pstrNextArg == NULL)
- nItemLen = 6; // "(null)"
- else
- {
- nItemLen = wcslen(pstrNextArg);
- nItemLen = max(1, nItemLen);
- }
- }
- break;
- }
- // adjust nItemLen for strings
- if (nItemLen != 0)
- {
- if (nPrecision != 0)
- nItemLen = min(nItemLen, nPrecision);
- nItemLen = max(nItemLen, nWidth);
- }
- else
- {
- switch (*lpsz)
- {
- // integers
- case 'd':
- case 'i':
- case 'u':
- case 'x':
- case 'X':
- case 'o':
- if (nModifier & FORCE_INT64)
- va_arg(argList, __int64);
- else
- va_arg(argList, int);
- nItemLen = 32;
- nItemLen = max(nItemLen, nWidth+nPrecision);
- break;
- case 'e':
- case 'g':
- case 'G':
- va_arg(argList, DOUBLE_ARG);
- nItemLen = 128;
- nItemLen = max(nItemLen, nWidth+nPrecision);
- break;
- case 'f':
- va_arg(argList, DOUBLE_ARG);
- nItemLen = 128; // width isn't truncated
- // 312 == strlen("-1+(309 zeroes).")
- // 309 zeroes == max precision of a double
- nItemLen = max(nItemLen, 312+nPrecision);
- break;
- case 'p':
- va_arg(argList, void*);
- nItemLen = 32;
- nItemLen = max(nItemLen, nWidth+nPrecision);
- break;
- // no output
- case 'n':
- va_arg(argList, int*);
- break;
- default:
- ASSERT(FALSE); // unknown formatting option
- }
- }
- // adjust nMaxLen for output nItemLen
- nMaxLen += nItemLen;
- }
- GetBuffer(nMaxLen);
- VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
- ReleaseBuffer();
- va_end(argListSave);
- }
- // formatting (using wsprintf style formatting)
- void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
- {
- ASSERT(AfxIsValidString(lpszFormat));
- va_list argList;
- va_start(argList, lpszFormat);
- FormatV(lpszFormat, argList);
- va_end(argList);
- }
- void AFX_CDECL CString::Format(UINT nFormatID, ...)
- {
- CString strFormat;
- VERIFY(strFormat.LoadString(nFormatID) != 0);
- va_list argList;
- va_start(argList, nFormatID);
- FormatV(strFormat, argList);
- va_end(argList);
- }
- void CString::TrimRight(LPCTSTR lpszTargetList)
- {
- // find beginning of trailing matches
- // by starting at beginning (DBCS aware)
- CopyBeforeWrite();
- LPTSTR lpsz = m_pchData;
- LPTSTR lpszLast = NULL;
- while (*lpsz != '\0')
- {
- if (_tcschr(lpszTargetList, *lpsz) != NULL)
- {
- if (lpszLast == NULL)
- lpszLast = lpsz;
- }
- else
- lpszLast = NULL;
- lpsz = _tcsinc(lpsz);
- }
- if (lpszLast != NULL)
- {
- // truncate at left-most matching character
- *lpszLast = '\0';
- GetData()->nDataLength = lpszLast - m_pchData;
- }
- }
- void CString::TrimRight(TCHAR chTarget)
- {
- // find beginning of trailing matches
- // by starting at beginning (DBCS aware)
- CopyBeforeWrite();
- LPTSTR lpsz = m_pchData;
- LPTSTR lpszLast = NULL;
- while (*lpsz != '\0')
- {
- if (*lpsz == chTarget)
- {
- if (lpszLast == NULL)
- lpszLast = lpsz;
- }
- else
- lpszLast = NULL;
- lpsz = _tcsinc(lpsz);
- }
- if (lpszLast != NULL)
- {
- // truncate at left-most matching character
- *lpszLast = '\0';
- GetData()->nDataLength = lpszLast - m_pchData;
- }
- }
- void CString::TrimLeft(LPCTSTR lpszTargets)
- {
- // if we're not trimming anything, we're not doing any work
- if (SafeStrlen(lpszTargets) == 0)
- return;
- CopyBeforeWrite();
- LPCTSTR lpsz = m_pchData;
- while (*lpsz != '\0')
- {
- if (_tcschr(lpszTargets, *lpsz) == NULL)
- break;
- lpsz = _tcsinc(lpsz);
- }
- if (lpsz != m_pchData)
- {
- // fix up data and length
- int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
- memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
- GetData()->nDataLength = nDataLength;
- }
- }
- void CString::TrimLeft(TCHAR chTarget)
- {
- // find first non-matching character
- CopyBeforeWrite();
- LPCTSTR lpsz = m_pchData;
- while (chTarget == *lpsz)
- lpsz = _tcsinc(lpsz);
- if (lpsz != m_pchData)
- {
- // fix up data and length
- int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
- memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
- GetData()->nDataLength = nDataLength;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
|