strex.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <afxtempl.h>
  12. // WINSCP
  13. #include <algorithm>
  14. #define max std::max
  15. #define min std::min
  16. #ifdef AFX_AUX_SEG
  17. #pragma code_seg(AFX_AUX_SEG)
  18. #endif
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. #define new DEBUG_NEW
  24. //////////////////////////////////////////////////////////////////////////////
  25. // More sophisticated construction
  26. CString::CString(TCHAR ch, int nLength)
  27. {
  28. Init();
  29. if (nLength >= 1)
  30. {
  31. AllocBuffer(nLength);
  32. #ifdef _UNICODE
  33. for (int i = 0; i < nLength; i++)
  34. m_pchData[i] = ch;
  35. #else
  36. memset(m_pchData, ch, nLength);
  37. #endif
  38. }
  39. }
  40. CString::CString(LPCTSTR lpch, int nLength)
  41. {
  42. Init();
  43. if (nLength != 0)
  44. {
  45. ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  46. AllocBuffer(nLength);
  47. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  48. }
  49. }
  50. /////////////////////////////////////////////////////////////////////////////
  51. // Special conversion constructors
  52. #ifdef _UNICODE
  53. CString::CString(LPCSTR lpsz, int nLength)
  54. {
  55. Init();
  56. if (nLength != 0)
  57. {
  58. AllocBuffer(nLength);
  59. int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
  60. ReleaseBuffer(n >= 0 ? n : -1);
  61. }
  62. }
  63. #else //_UNICODE
  64. CString::CString(LPCWSTR lpsz, int nLength)
  65. {
  66. Init();
  67. if (nLength != 0)
  68. {
  69. AllocBuffer(nLength*2);
  70. int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData,
  71. (nLength*2)+1, NULL, NULL);
  72. ReleaseBuffer(n >= 0 ? n : -1);
  73. }
  74. }
  75. #endif //!_UNICODE
  76. //////////////////////////////////////////////////////////////////////////////
  77. // Assignment operators
  78. const CString& CString::operator=(TCHAR ch)
  79. {
  80. AssignCopy(1, &ch);
  81. return *this;
  82. }
  83. //////////////////////////////////////////////////////////////////////////////
  84. // less common string expressions
  85. CString AFXAPI operator+(const CString& string1, TCHAR ch)
  86. {
  87. CString s;
  88. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  89. return s;
  90. }
  91. CString AFXAPI operator+(TCHAR ch, const CString& string)
  92. {
  93. CString s;
  94. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  95. return s;
  96. }
  97. //////////////////////////////////////////////////////////////////////////////
  98. // Advanced manipulation
  99. int CString::Delete(int nIndex, int nCount /* = 1 */)
  100. {
  101. if (nIndex < 0)
  102. nIndex = 0;
  103. int nNewLength = GetData()->nDataLength;
  104. if (nCount > 0 && nIndex < nNewLength)
  105. {
  106. CopyBeforeWrite();
  107. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  108. memcpy(m_pchData + nIndex,
  109. m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  110. GetData()->nDataLength = nNewLength - nCount;
  111. }
  112. return nNewLength;
  113. }
  114. int CString::Insert(int nIndex, TCHAR ch)
  115. {
  116. CopyBeforeWrite();
  117. if (nIndex < 0)
  118. nIndex = 0;
  119. int nNewLength = GetData()->nDataLength;
  120. if (nIndex > nNewLength)
  121. nIndex = nNewLength;
  122. nNewLength++;
  123. if (GetData()->nAllocLength < nNewLength)
  124. {
  125. CStringData* pOldData = GetData();
  126. LPTSTR pstr = m_pchData;
  127. AllocBuffer(nNewLength);
  128. memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
  129. CString::Release(pOldData);
  130. }
  131. // move existing bytes down
  132. memcpy(m_pchData + nIndex + 1,
  133. m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
  134. m_pchData[nIndex] = ch;
  135. GetData()->nDataLength = nNewLength;
  136. return nNewLength;
  137. }
  138. int CString::Insert(int nIndex, LPCTSTR pstr)
  139. {
  140. if (nIndex < 0)
  141. nIndex = 0;
  142. int nInsertLength = SafeStrlen(pstr);
  143. int nNewLength = GetData()->nDataLength;
  144. if (nInsertLength > 0)
  145. {
  146. CopyBeforeWrite();
  147. if (nIndex > nNewLength)
  148. nIndex = nNewLength;
  149. nNewLength += nInsertLength;
  150. if (GetData()->nAllocLength < nNewLength)
  151. {
  152. CStringData* pOldData = GetData();
  153. LPTSTR pstr = m_pchData;
  154. AllocBuffer(nNewLength);
  155. memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
  156. CString::Release(pOldData);
  157. }
  158. // move existing bytes down
  159. memcpy(m_pchData + nIndex + nInsertLength,
  160. m_pchData + nIndex,
  161. (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
  162. memcpy(m_pchData + nIndex,
  163. pstr, nInsertLength*sizeof(TCHAR));
  164. GetData()->nDataLength = nNewLength;
  165. }
  166. return nNewLength;
  167. }
  168. int CString::Replace(TCHAR chOld, TCHAR chNew)
  169. {
  170. int nCount = 0;
  171. // short-circuit the nop case
  172. if (chOld != chNew)
  173. {
  174. // otherwise modify each character that matches in the string
  175. CopyBeforeWrite();
  176. LPTSTR psz = m_pchData;
  177. LPTSTR pszEnd = psz + GetData()->nDataLength;
  178. while (psz < pszEnd)
  179. {
  180. // replace instances of the specified character only
  181. if (*psz == chOld)
  182. {
  183. *psz = chNew;
  184. nCount++;
  185. }
  186. psz = _tcsinc(psz);
  187. }
  188. }
  189. return nCount;
  190. }
  191. int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  192. {
  193. // can't have empty or NULL lpszOld
  194. int nSourceLen = SafeStrlen(lpszOld);
  195. if (nSourceLen == 0)
  196. return 0;
  197. int nReplacementLen = SafeStrlen(lpszNew);
  198. // loop once to figure out the size of the result string
  199. int nCount = 0;
  200. LPTSTR lpszStart = m_pchData;
  201. LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  202. LPTSTR lpszTarget;
  203. while (lpszStart < lpszEnd)
  204. {
  205. while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  206. {
  207. nCount++;
  208. lpszStart = lpszTarget + nSourceLen;
  209. }
  210. lpszStart += lstrlen(lpszStart) + 1;
  211. }
  212. // if any changes were made, make them
  213. if (nCount > 0)
  214. {
  215. CopyBeforeWrite();
  216. // if the buffer is too small, just
  217. // allocate a new buffer (slow but sure)
  218. int nOldLength = GetData()->nDataLength;
  219. int nNewLength = nOldLength + (nReplacementLen-nSourceLen)*nCount;
  220. if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  221. {
  222. CStringData* pOldData = GetData();
  223. LPTSTR pstr = m_pchData;
  224. AllocBuffer(nNewLength);
  225. memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  226. CString::Release(pOldData);
  227. }
  228. // else, we just do it in-place
  229. lpszStart = m_pchData;
  230. lpszEnd = m_pchData + GetData()->nDataLength;
  231. // loop again to actually do the work
  232. while (lpszStart < lpszEnd)
  233. {
  234. while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  235. {
  236. int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen);
  237. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
  238. nBalance * sizeof(TCHAR));
  239. memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
  240. lpszStart = lpszTarget + nReplacementLen;
  241. lpszStart[nBalance] = '\0';
  242. nOldLength += (nReplacementLen - nSourceLen);
  243. }
  244. lpszStart += lstrlen(lpszStart) + 1;
  245. }
  246. ASSERT(m_pchData[nNewLength] == '\0');
  247. GetData()->nDataLength = nNewLength;
  248. }
  249. return nCount;
  250. }
  251. int CString::Remove(TCHAR chRemove)
  252. {
  253. CopyBeforeWrite();
  254. LPTSTR pstrSource = m_pchData;
  255. LPTSTR pstrDest = m_pchData;
  256. LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
  257. while (pstrSource < pstrEnd)
  258. {
  259. if (*pstrSource != chRemove)
  260. {
  261. *pstrDest = *pstrSource;
  262. pstrDest = _tcsinc(pstrDest);
  263. }
  264. pstrSource = _tcsinc(pstrSource);
  265. }
  266. *pstrDest = '\0';
  267. int nCount = pstrSource - pstrDest;
  268. GetData()->nDataLength -= nCount;
  269. return nCount;
  270. }
  271. //////////////////////////////////////////////////////////////////////////////
  272. // Very simple sub-string extraction
  273. CString CString::Mid(int nFirst) const
  274. {
  275. return Mid(nFirst, GetData()->nDataLength - nFirst);
  276. }
  277. CString CString::Mid(int nFirst, int nCount) const
  278. {
  279. // out-of-bounds requests return sensible things
  280. if (nFirst < 0)
  281. nFirst = 0;
  282. if (nCount < 0)
  283. nCount = 0;
  284. if (nFirst + nCount > GetData()->nDataLength)
  285. nCount = GetData()->nDataLength - nFirst;
  286. if (nFirst > GetData()->nDataLength)
  287. nCount = 0;
  288. ASSERT(nFirst >= 0);
  289. ASSERT(nFirst + nCount <= GetData()->nDataLength);
  290. // optimize case of returning entire string
  291. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  292. return *this;
  293. CString dest;
  294. AllocCopy(dest, nCount, nFirst, 0);
  295. return dest;
  296. }
  297. CString CString::Right(int nCount) const
  298. {
  299. if (nCount < 0)
  300. nCount = 0;
  301. if (nCount >= GetData()->nDataLength)
  302. return *this;
  303. CString dest;
  304. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  305. return dest;
  306. }
  307. CString CString::Left(int nCount) const
  308. {
  309. if (nCount < 0)
  310. nCount = 0;
  311. if (nCount >= GetData()->nDataLength)
  312. return *this;
  313. CString dest;
  314. AllocCopy(dest, nCount, 0, 0);
  315. return dest;
  316. }
  317. // strspn equivalent
  318. CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  319. {
  320. ASSERT(AfxIsValidString(lpszCharSet));
  321. return Left(_tcsspn(m_pchData, lpszCharSet));
  322. }
  323. // strcspn equivalent
  324. CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  325. {
  326. ASSERT(AfxIsValidString(lpszCharSet));
  327. return Left(_tcscspn(m_pchData, lpszCharSet));
  328. }
  329. //////////////////////////////////////////////////////////////////////////////
  330. // Finding
  331. int CString::ReverseFind(TCHAR ch) const
  332. {
  333. // find last single character
  334. LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
  335. // return -1 if not found, distance from beginning otherwise
  336. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  337. }
  338. // find a sub-string (like strstr)
  339. int CString::Find(LPCTSTR lpszSub) const
  340. {
  341. return Find(lpszSub, 0);
  342. }
  343. int CString::Find(LPCTSTR lpszSub, int nStart) const
  344. {
  345. ASSERT(AfxIsValidString(lpszSub));
  346. int nLength = GetData()->nDataLength;
  347. if (nStart > nLength)
  348. return -1;
  349. // find first matching substring
  350. LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
  351. // return -1 for not found, distance from beginning otherwise
  352. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  353. }
  354. /////////////////////////////////////////////////////////////////////////////
  355. // CString formatting
  356. #define TCHAR_ARG TCHAR
  357. #define WCHAR_ARG WCHAR
  358. #define CHAR_ARG char
  359. #ifdef _X86_
  360. #define DOUBLE_ARG _AFX_DOUBLE
  361. #else
  362. #define DOUBLE_ARG double
  363. #endif
  364. #define FORCE_ANSI 0x10000
  365. #define FORCE_UNICODE 0x20000
  366. #define FORCE_INT64 0x40000
  367. #define _tclen(__a) (1)
  368. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  369. {
  370. ASSERT(AfxIsValidString(lpszFormat));
  371. va_list argListSave = argList;
  372. // make a guess at the maximum length of the resulting string
  373. int nMaxLen = 0;
  374. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  375. {
  376. // handle '%' character, but watch out for '%%'
  377. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  378. {
  379. nMaxLen += _tclen(lpsz);
  380. continue;
  381. }
  382. int nItemLen = 0;
  383. // handle '%' character with format
  384. int nWidth = 0;
  385. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  386. {
  387. // check for valid flags
  388. if (*lpsz == '#')
  389. nMaxLen += 2; // for '0x'
  390. else if (*lpsz == '*')
  391. nWidth = va_arg(argList, int);
  392. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  393. *lpsz == ' ')
  394. ;
  395. else // hit non-flag character
  396. break;
  397. }
  398. // get width and skip it
  399. if (nWidth == 0)
  400. {
  401. // width indicated by
  402. nWidth = _ttoi(lpsz);
  403. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  404. ;
  405. }
  406. ASSERT(nWidth >= 0);
  407. int nPrecision = 0;
  408. if (*lpsz == '.')
  409. {
  410. // skip past '.' separator (width.precision)
  411. lpsz = _tcsinc(lpsz);
  412. // get precision and skip it
  413. if (*lpsz == '*')
  414. {
  415. nPrecision = va_arg(argList, int);
  416. lpsz = _tcsinc(lpsz);
  417. }
  418. else
  419. {
  420. nPrecision = _ttoi(lpsz);
  421. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  422. ;
  423. }
  424. ASSERT(nPrecision >= 0);
  425. }
  426. // should be on type modifier or specifier
  427. int nModifier = 0;
  428. if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  429. {
  430. lpsz += 3;
  431. nModifier = FORCE_INT64;
  432. #if !defined(_X86_) && !defined(_ALPHA_)
  433. // __int64 is only available on X86 and ALPHA platforms
  434. ASSERT(FALSE);
  435. #endif
  436. }
  437. else
  438. {
  439. switch (*lpsz)
  440. {
  441. // modifiers that affect size
  442. case 'h':
  443. nModifier = FORCE_ANSI;
  444. lpsz = _tcsinc(lpsz);
  445. break;
  446. case 'l':
  447. nModifier = FORCE_UNICODE;
  448. lpsz = _tcsinc(lpsz);
  449. break;
  450. // modifiers that do not affect size
  451. case 'F':
  452. case 'N':
  453. case 'L':
  454. lpsz = _tcsinc(lpsz);
  455. break;
  456. }
  457. }
  458. // now should be on specifier
  459. switch (*lpsz | nModifier)
  460. {
  461. // single characters
  462. case 'c':
  463. case 'C':
  464. nItemLen = 2;
  465. va_arg(argList, TCHAR_ARG);
  466. break;
  467. case 'c'|FORCE_ANSI:
  468. case 'C'|FORCE_ANSI:
  469. nItemLen = 2;
  470. va_arg(argList, CHAR_ARG);
  471. break;
  472. case 'c'|FORCE_UNICODE:
  473. case 'C'|FORCE_UNICODE:
  474. nItemLen = 2;
  475. va_arg(argList, WCHAR_ARG);
  476. break;
  477. // strings
  478. case 's':
  479. {
  480. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  481. if (pstrNextArg == NULL)
  482. nItemLen = 6; // "(null)"
  483. else
  484. {
  485. nItemLen = lstrlen(pstrNextArg);
  486. nItemLen = max(1, nItemLen);
  487. }
  488. }
  489. break;
  490. case 'S':
  491. {
  492. #ifndef _UNICODE
  493. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  494. if (pstrNextArg == NULL)
  495. nItemLen = 6; // "(null)"
  496. else
  497. {
  498. nItemLen = wcslen(pstrNextArg);
  499. nItemLen = max(1, nItemLen);
  500. }
  501. #else
  502. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  503. if (pstrNextArg == NULL)
  504. nItemLen = 6; // "(null)"
  505. else
  506. {
  507. nItemLen = lstrlenA(pstrNextArg);
  508. nItemLen = max(1, nItemLen);
  509. }
  510. #endif
  511. }
  512. break;
  513. case 's'|FORCE_ANSI:
  514. case 'S'|FORCE_ANSI:
  515. {
  516. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  517. if (pstrNextArg == NULL)
  518. nItemLen = 6; // "(null)"
  519. else
  520. {
  521. nItemLen = lstrlenA(pstrNextArg);
  522. nItemLen = max(1, nItemLen);
  523. }
  524. }
  525. break;
  526. case 's'|FORCE_UNICODE:
  527. case 'S'|FORCE_UNICODE:
  528. {
  529. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  530. if (pstrNextArg == NULL)
  531. nItemLen = 6; // "(null)"
  532. else
  533. {
  534. nItemLen = wcslen(pstrNextArg);
  535. nItemLen = max(1, nItemLen);
  536. }
  537. }
  538. break;
  539. }
  540. // adjust nItemLen for strings
  541. if (nItemLen != 0)
  542. {
  543. if (nPrecision != 0)
  544. nItemLen = min(nItemLen, nPrecision);
  545. nItemLen = max(nItemLen, nWidth);
  546. }
  547. else
  548. {
  549. switch (*lpsz)
  550. {
  551. // integers
  552. case 'd':
  553. case 'i':
  554. case 'u':
  555. case 'x':
  556. case 'X':
  557. case 'o':
  558. if (nModifier & FORCE_INT64)
  559. va_arg(argList, __int64);
  560. else
  561. va_arg(argList, int);
  562. nItemLen = 32;
  563. nItemLen = max(nItemLen, nWidth+nPrecision);
  564. break;
  565. case 'e':
  566. case 'g':
  567. case 'G':
  568. va_arg(argList, DOUBLE_ARG);
  569. nItemLen = 128;
  570. nItemLen = max(nItemLen, nWidth+nPrecision);
  571. break;
  572. case 'f':
  573. va_arg(argList, DOUBLE_ARG);
  574. nItemLen = 128; // width isn't truncated
  575. // 312 == strlen("-1+(309 zeroes).")
  576. // 309 zeroes == max precision of a double
  577. nItemLen = max(nItemLen, 312+nPrecision);
  578. break;
  579. case 'p':
  580. va_arg(argList, void*);
  581. nItemLen = 32;
  582. nItemLen = max(nItemLen, nWidth+nPrecision);
  583. break;
  584. // no output
  585. case 'n':
  586. va_arg(argList, int*);
  587. break;
  588. default:
  589. ASSERT(FALSE); // unknown formatting option
  590. }
  591. }
  592. // adjust nMaxLen for output nItemLen
  593. nMaxLen += nItemLen;
  594. }
  595. GetBuffer(nMaxLen);
  596. VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
  597. ReleaseBuffer();
  598. va_end(argListSave);
  599. }
  600. // formatting (using wsprintf style formatting)
  601. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  602. {
  603. ASSERT(AfxIsValidString(lpszFormat));
  604. va_list argList;
  605. va_start(argList, lpszFormat);
  606. FormatV(lpszFormat, argList);
  607. va_end(argList);
  608. }
  609. void AFX_CDECL CString::Format(UINT nFormatID, ...)
  610. {
  611. CString strFormat;
  612. VERIFY(strFormat.LoadString(nFormatID) != 0);
  613. va_list argList;
  614. va_start(argList, nFormatID);
  615. FormatV(strFormat, argList);
  616. va_end(argList);
  617. }
  618. // formatting (using FormatMessage style formatting)
  619. void AFX_CDECL CString::FormatMessage(LPCTSTR lpszFormat, ...)
  620. {
  621. // format message into temporary buffer lpszTemp
  622. va_list argList;
  623. va_start(argList, lpszFormat);
  624. LPTSTR lpszTemp;
  625. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  626. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  627. lpszTemp == NULL)
  628. {
  629. AfxThrowMemoryException();
  630. }
  631. // assign lpszTemp into the resulting string and free the temporary
  632. *this = lpszTemp;
  633. LocalFree(lpszTemp);
  634. va_end(argList);
  635. }
  636. void AFX_CDECL CString::FormatMessage(UINT nFormatID, ...)
  637. {
  638. // get format string from string table
  639. CString strFormat;
  640. VERIFY(strFormat.LoadString(nFormatID) != 0);
  641. // format message into temporary buffer lpszTemp
  642. va_list argList;
  643. va_start(argList, nFormatID);
  644. LPTSTR lpszTemp;
  645. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  646. strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  647. lpszTemp == NULL)
  648. {
  649. AfxThrowMemoryException();
  650. }
  651. // assign lpszTemp into the resulting string and free lpszTemp
  652. *this = lpszTemp;
  653. LocalFree(lpszTemp);
  654. va_end(argList);
  655. }
  656. void CString::TrimRight(LPCTSTR lpszTargetList)
  657. {
  658. // find beginning of trailing matches
  659. // by starting at beginning (DBCS aware)
  660. CopyBeforeWrite();
  661. LPTSTR lpsz = m_pchData;
  662. LPTSTR lpszLast = NULL;
  663. while (*lpsz != '\0')
  664. {
  665. if (_tcschr(lpszTargetList, *lpsz) != NULL)
  666. {
  667. if (lpszLast == NULL)
  668. lpszLast = lpsz;
  669. }
  670. else
  671. lpszLast = NULL;
  672. lpsz = _tcsinc(lpsz);
  673. }
  674. if (lpszLast != NULL)
  675. {
  676. // truncate at left-most matching character
  677. *lpszLast = '\0';
  678. GetData()->nDataLength = lpszLast - m_pchData;
  679. }
  680. }
  681. void CString::TrimRight(TCHAR chTarget)
  682. {
  683. // find beginning of trailing matches
  684. // by starting at beginning (DBCS aware)
  685. CopyBeforeWrite();
  686. LPTSTR lpsz = m_pchData;
  687. LPTSTR lpszLast = NULL;
  688. while (*lpsz != '\0')
  689. {
  690. if (*lpsz == chTarget)
  691. {
  692. if (lpszLast == NULL)
  693. lpszLast = lpsz;
  694. }
  695. else
  696. lpszLast = NULL;
  697. lpsz = _tcsinc(lpsz);
  698. }
  699. if (lpszLast != NULL)
  700. {
  701. // truncate at left-most matching character
  702. *lpszLast = '\0';
  703. GetData()->nDataLength = lpszLast - m_pchData;
  704. }
  705. }
  706. void CString::TrimRight()
  707. {
  708. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  709. CopyBeforeWrite();
  710. LPTSTR lpsz = m_pchData;
  711. LPTSTR lpszLast = NULL;
  712. while (*lpsz != '\0')
  713. {
  714. if (_istspace(*lpsz))
  715. {
  716. if (lpszLast == NULL)
  717. lpszLast = lpsz;
  718. }
  719. else
  720. lpszLast = NULL;
  721. lpsz = _tcsinc(lpsz);
  722. }
  723. if (lpszLast != NULL)
  724. {
  725. // truncate at trailing space start
  726. *lpszLast = '\0';
  727. GetData()->nDataLength = lpszLast - m_pchData;
  728. }
  729. }
  730. void CString::TrimLeft(LPCTSTR lpszTargets)
  731. {
  732. // if we're not trimming anything, we're not doing any work
  733. if (SafeStrlen(lpszTargets) == 0)
  734. return;
  735. CopyBeforeWrite();
  736. LPCTSTR lpsz = m_pchData;
  737. while (*lpsz != '\0')
  738. {
  739. if (_tcschr(lpszTargets, *lpsz) == NULL)
  740. break;
  741. lpsz = _tcsinc(lpsz);
  742. }
  743. if (lpsz != m_pchData)
  744. {
  745. // fix up data and length
  746. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  747. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  748. GetData()->nDataLength = nDataLength;
  749. }
  750. }
  751. void CString::TrimLeft(TCHAR chTarget)
  752. {
  753. // find first non-matching character
  754. CopyBeforeWrite();
  755. LPCTSTR lpsz = m_pchData;
  756. while (chTarget == *lpsz)
  757. lpsz = _tcsinc(lpsz);
  758. if (lpsz != m_pchData)
  759. {
  760. // fix up data and length
  761. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  762. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  763. GetData()->nDataLength = nDataLength;
  764. }
  765. }
  766. void CString::TrimLeft()
  767. {
  768. // find first non-space character
  769. CopyBeforeWrite();
  770. LPCTSTR lpsz = m_pchData;
  771. while (_istspace(*lpsz))
  772. lpsz = _tcsinc(lpsz);
  773. if (lpsz != m_pchData)
  774. {
  775. // fix up data and length
  776. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  777. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  778. GetData()->nDataLength = nDataLength;
  779. }
  780. }
  781. ///////////////////////////////////////////////////////////////////////////////
  782. // CString support for template collections
  783. #if _MSC_VER >= 1100
  784. template<> void AFXAPI ConstructElements<CString> (CString* pElements, int nCount)
  785. #else
  786. void AFXAPI ConstructElements(CString* pElements, int nCount)
  787. #endif
  788. {
  789. ASSERT(nCount == 0 ||
  790. AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  791. for (; nCount--; ++pElements)
  792. memcpy(pElements, &afxEmptyString, sizeof(*pElements));
  793. }
  794. #if _MSC_VER >= 1100
  795. template<> void AFXAPI DestructElements<CString> (CString* pElements, int nCount)
  796. #else
  797. void AFXAPI DestructElements(CString* pElements, int nCount)
  798. #endif
  799. {
  800. ASSERT(nCount == 0 ||
  801. AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  802. for (; nCount--; ++pElements)
  803. pElements->~CString();
  804. }
  805. #if _MSC_VER >= 1100
  806. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, int nCount)
  807. #else
  808. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, int nCount)
  809. #endif
  810. {
  811. ASSERT(nCount == 0 ||
  812. AfxIsValidAddress(pDest, nCount * sizeof(CString)));
  813. ASSERT(nCount == 0 ||
  814. AfxIsValidAddress(pSrc, nCount * sizeof(CString)));
  815. for (; nCount--; ++pDest, ++pSrc)
  816. *pDest = *pSrc;
  817. }
  818. #ifndef OLE2ANSI
  819. #if _MSC_VER >= 1100
  820. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
  821. #else
  822. UINT AFXAPI HashKey(LPCWSTR key)
  823. #endif
  824. {
  825. UINT nHash = 0;
  826. while (*key)
  827. nHash = (nHash<<5) + nHash + *key++;
  828. return nHash;
  829. }
  830. #endif
  831. #if _MSC_VER >= 1100
  832. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
  833. #else
  834. UINT AFXAPI HashKey(LPCSTR key)
  835. #endif
  836. {
  837. UINT nHash = 0;
  838. while (*key)
  839. nHash = (nHash<<5) + nHash + *key++;
  840. return nHash;
  841. }
  842. ///////////////////////////////////////////////////////////////////////////////