strex.cpp 22 KB

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