Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1017 lines
26 KiB

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) Microsoft Corporation, 1992 - 1999
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp and/or WinHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include <stdio.h>
  11. #include <objbase.h>
  12. #include <basetyps.h>
  13. #include "dbg.h"
  14. #include "..\inc\cstr.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // static class data, special inlines
  17. // For an empty string, m_???Data will point here
  18. // (note: avoids a lot of NULL pointer tests when we call standard
  19. // C runtime libraries
  20. TCHAR strChNil = '\0'; // extractstring
  21. // for creating empty key strings
  22. const CStr strEmptyString;
  23. // begin_extractstring
  24. void CStr::Init()
  25. {
  26. m_nDataLength = m_nAllocLength = 0;
  27. m_pchData = (LPTSTR)&strChNil;
  28. }
  29. // declared static
  30. void CStr::SafeDelete(LPTSTR lpch)
  31. {
  32. if (lpch != (LPTSTR)&strChNil)
  33. delete[] lpch;
  34. }
  35. //////////////////////////////////////////////////////////////////////////////
  36. // Construction/Destruction
  37. // begin_extractstring
  38. CStr::CStr()
  39. {
  40. Init();
  41. }
  42. CStr::CStr(const CStr& stringSrc)
  43. {
  44. // if constructing a String from another String, we make a copy of the
  45. // original string data to enforce value semantics (i.e. each string
  46. // gets a copy of its own
  47. stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
  48. }
  49. void CStr::AllocBuffer(int nLen)
  50. // always allocate one extra character for '\0' termination
  51. // assumes [optimistically] that data length will equal allocation length
  52. {
  53. ASSERT(nLen >= 0);
  54. if (nLen == 0)
  55. {
  56. Init();
  57. }
  58. else
  59. {
  60. m_pchData = new TCHAR[nLen+1]; //REVIEW may throw an exception
  61. if (m_pchData != NULL)
  62. {
  63. m_pchData[nLen] = '\0';
  64. m_nDataLength = nLen;
  65. m_nAllocLength = nLen;
  66. }
  67. else
  68. Init();
  69. }
  70. }
  71. void CStr::Empty()
  72. {
  73. SafeDelete(m_pchData);
  74. Init();
  75. ASSERT(m_nDataLength == 0);
  76. ASSERT(m_nAllocLength == 0);
  77. }
  78. CStr::~CStr()
  79. // free any attached data
  80. {
  81. SafeDelete(m_pchData);
  82. }
  83. //////////////////////////////////////////////////////////////////////////////
  84. // Helpers for the rest of the implementation
  85. static inline int SafeStrlen(LPCTSTR lpsz)
  86. {
  87. ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
  88. return (lpsz == NULL) ? 0 : lstrlen(lpsz);
  89. }
  90. void CStr::AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex,
  91. int nExtraLen) const
  92. {
  93. // will clone the data attached to this string
  94. // allocating 'nExtraLen' characters
  95. // Places results in uninitialized string 'dest'
  96. // Will copy the part or all of original data to start of new string
  97. int nNewLen = nCopyLen + nExtraLen;
  98. if (nNewLen == 0)
  99. {
  100. dest.Init();
  101. }
  102. else
  103. {
  104. dest.AllocBuffer(nNewLen);
  105. memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(TCHAR));
  106. }
  107. }
  108. //////////////////////////////////////////////////////////////////////////////
  109. // More sophisticated construction
  110. CStr::CStr(LPCTSTR lpsz)
  111. {
  112. if (lpsz != NULL && (DWORD_PTR)lpsz <= 0xffff)
  113. {
  114. Init();
  115. UINT nID = LOWORD((DWORD_PTR)lpsz);
  116. // REVIEW hInstance for LoadString(hInst, nID);
  117. }
  118. else
  119. {
  120. int nLen;
  121. if ((nLen = SafeStrlen(lpsz)) == 0)
  122. Init();
  123. else
  124. {
  125. AllocBuffer(nLen);
  126. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  127. }
  128. }
  129. }
  130. // end_extractstring
  131. /////////////////////////////////////////////////////////////////////////////
  132. // Special conversion constructors
  133. #ifdef UNICODE
  134. CStr::CStr(LPCSTR lpsz)
  135. {
  136. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  137. if (nSrcLen == 0)
  138. Init();
  139. else
  140. {
  141. AllocBuffer(nSrcLen);
  142. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  143. }
  144. }
  145. #else //UNICODE
  146. CStr::CStr(LPCWSTR lpsz)
  147. {
  148. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  149. if (nSrcLen == 0)
  150. Init();
  151. else
  152. {
  153. AllocBuffer(nSrcLen*2);
  154. mmc_wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  155. ReleaseBuffer();
  156. }
  157. }
  158. #endif //!UNICODE
  159. // begin_extractstring
  160. //////////////////////////////////////////////////////////////////////////////
  161. // Assignment operators
  162. // All assign a new value to the string
  163. // (a) first see if the buffer is big enough
  164. // (b) if enough room, copy on top of old buffer, set size and type
  165. // (c) otherwise free old string data, and create a new one
  166. //
  167. // All routines return the new string (but as a 'const CStr&' so that
  168. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  169. //
  170. void CStr::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  171. {
  172. // check if it will fit
  173. if (nSrcLen > m_nAllocLength)
  174. {
  175. // it won't fit, allocate another one
  176. Empty();
  177. AllocBuffer(nSrcLen);
  178. }
  179. if (nSrcLen != 0)
  180. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  181. m_nDataLength = nSrcLen;
  182. m_pchData[nSrcLen] = '\0';
  183. }
  184. const CStr& CStr::operator=(const CStr& stringSrc)
  185. {
  186. AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
  187. return *this;
  188. }
  189. const CStr& CStr::operator=(LPCTSTR lpsz)
  190. {
  191. ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
  192. AssignCopy(SafeStrlen(lpsz), lpsz);
  193. return *this;
  194. }
  195. // end_extractstring
  196. /////////////////////////////////////////////////////////////////////////////
  197. // Special conversion assignment
  198. #ifdef UNICODE
  199. const CStr& CStr::operator=(LPCSTR lpsz)
  200. {
  201. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  202. // check if it will fit
  203. if (nSrcLen > m_nAllocLength)
  204. {
  205. // it won't fit, allocate another one
  206. Empty();
  207. AllocBuffer(nSrcLen);
  208. }
  209. if (nSrcLen != 0)
  210. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  211. m_nDataLength = nSrcLen;
  212. m_pchData[nSrcLen] = '\0';
  213. return *this;
  214. }
  215. #else //!UNICODE
  216. const CStr& CStr::operator=(LPCWSTR lpsz)
  217. {
  218. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  219. nSrcLen *= 2;
  220. // check if it will fit
  221. if (nSrcLen > m_nAllocLength)
  222. {
  223. // it won't fit, allocate another one
  224. Empty();
  225. AllocBuffer(nSrcLen);
  226. }
  227. if (nSrcLen != 0)
  228. {
  229. mmc_wcstombsz(m_pchData, lpsz, nSrcLen+1);
  230. ReleaseBuffer();
  231. }
  232. return *this;
  233. }
  234. #endif //!UNICODE
  235. //////////////////////////////////////////////////////////////////////////////
  236. // concatenation
  237. // NOTE: "operator+" is done as friend functions for simplicity
  238. // There are three variants:
  239. // String + String
  240. // and for ? = TCHAR, LPCTSTR
  241. // String + ?
  242. // ? + String
  243. void CStr::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  244. int nSrc2Len, LPCTSTR lpszSrc2Data)
  245. {
  246. // -- master concatenation routine
  247. // Concatenate two sources
  248. // -- assume that 'this' is a new String object
  249. int nNewLen = nSrc1Len + nSrc2Len;
  250. AllocBuffer(nNewLen);
  251. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  252. memcpy(&m_pchData[nSrc1Len], lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  253. }
  254. CStr STRAPI operator+(const CStr& string1, const CStr& string2)
  255. {
  256. CStr s;
  257. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData,
  258. string2.m_nDataLength, string2.m_pchData);
  259. return s;
  260. }
  261. CStr STRAPI operator+(const CStr& string, LPCTSTR lpsz)
  262. {
  263. ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
  264. CStr s;
  265. s.ConcatCopy(string.m_nDataLength, string.m_pchData, SafeStrlen(lpsz), lpsz);
  266. return s;
  267. }
  268. CStr STRAPI operator+(LPCTSTR lpsz, const CStr& string)
  269. {
  270. ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
  271. CStr s;
  272. s.ConcatCopy(SafeStrlen(lpsz), lpsz, string.m_nDataLength, string.m_pchData);
  273. return s;
  274. }
  275. //////////////////////////////////////////////////////////////////////////////
  276. // concatenate in place
  277. void CStr::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  278. {
  279. // -- the main routine for += operators
  280. // if the buffer is too small, or we have a width mis-match, just
  281. // allocate a new buffer (slow but sure)
  282. if (m_nDataLength + nSrcLen > m_nAllocLength)
  283. {
  284. // we have to grow the buffer, use the Concat in place routine
  285. LPTSTR lpszOldData = m_pchData;
  286. ConcatCopy(m_nDataLength, lpszOldData, nSrcLen, lpszSrcData);
  287. ASSERT(lpszOldData != NULL);
  288. SafeDelete(lpszOldData);
  289. }
  290. else
  291. {
  292. // fast concatenation when buffer big enough
  293. memcpy(&m_pchData[m_nDataLength], lpszSrcData, nSrcLen*sizeof(TCHAR));
  294. m_nDataLength += nSrcLen;
  295. }
  296. ASSERT(m_nDataLength <= m_nAllocLength);
  297. m_pchData[m_nDataLength] = '\0';
  298. }
  299. const CStr& CStr::operator+=(LPCTSTR lpsz)
  300. {
  301. ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
  302. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  303. return *this;
  304. }
  305. const CStr& CStr::operator+=(TCHAR ch)
  306. {
  307. ConcatInPlace(1, &ch);
  308. return *this;
  309. }
  310. const CStr& CStr::operator+=(const CStr& string)
  311. {
  312. ConcatInPlace(string.m_nDataLength, string.m_pchData);
  313. return *this;
  314. }
  315. ///////////////////////////////////////////////////////////////////////////////
  316. // Advanced direct buffer access
  317. LPTSTR CStr::GetBuffer(int nMinBufLength)
  318. {
  319. ASSERT(nMinBufLength >= 0);
  320. if (nMinBufLength > m_nAllocLength)
  321. {
  322. // we have to grow the buffer
  323. LPTSTR lpszOldData = m_pchData;
  324. int nOldLen = m_nDataLength; // AllocBuffer will tromp it
  325. AllocBuffer(nMinBufLength);
  326. memcpy(m_pchData, lpszOldData, nOldLen*sizeof(TCHAR));
  327. m_nDataLength = nOldLen;
  328. m_pchData[m_nDataLength] = '\0';
  329. SafeDelete(lpszOldData);
  330. }
  331. // return a pointer to the character storage for this string
  332. ASSERT(m_pchData != NULL);
  333. return m_pchData;
  334. }
  335. void CStr::ReleaseBuffer(int nNewLength)
  336. {
  337. if (nNewLength == -1)
  338. nNewLength = lstrlen(m_pchData); // zero terminated
  339. ASSERT(nNewLength <= m_nAllocLength);
  340. m_nDataLength = nNewLength;
  341. m_pchData[m_nDataLength] = '\0';
  342. }
  343. LPTSTR CStr::GetBufferSetLength(int nNewLength)
  344. {
  345. ASSERT(nNewLength >= 0);
  346. GetBuffer(nNewLength);
  347. m_nDataLength = nNewLength;
  348. m_pchData[m_nDataLength] = '\0';
  349. return m_pchData;
  350. }
  351. void CStr::FreeExtra()
  352. {
  353. ASSERT(m_nDataLength <= m_nAllocLength);
  354. if (m_nDataLength != m_nAllocLength)
  355. {
  356. LPTSTR lpszOldData = m_pchData;
  357. AllocBuffer(m_nDataLength);
  358. memcpy(m_pchData, lpszOldData, m_nDataLength*sizeof(TCHAR));
  359. ASSERT(m_pchData[m_nDataLength] == '\0');
  360. SafeDelete(lpszOldData);
  361. }
  362. ASSERT(m_pchData != NULL);
  363. }
  364. ///////////////////////////////////////////////////////////////////////////////
  365. // Commonly used routines (rarely used routines in STREX.CPP)
  366. int CStr::Find(TCHAR ch) const
  367. {
  368. // find first single character
  369. LPTSTR lpsz = _tcschr(m_pchData, ch);
  370. // return -1 if not found and index otherwise
  371. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  372. }
  373. int CStr::FindOneOf(LPCTSTR lpszCharSet) const
  374. {
  375. ASSERT(IsValidString(lpszCharSet, FALSE));
  376. LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  377. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  378. }
  379. ///////////////////////////////////////////////////////////////////////////////
  380. // String conversion helpers (these use the current system locale)
  381. int mmc_wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  382. {
  383. if (count == 0 && mbstr != NULL)
  384. return 0;
  385. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  386. mbstr, count, NULL, NULL);
  387. ASSERT(mbstr == NULL || result <= (int)count);
  388. if (result > 0)
  389. mbstr[result-1] = 0;
  390. return result;
  391. }
  392. int mmc_mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  393. {
  394. if (count == 0 && wcstr != NULL)
  395. return 0;
  396. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  397. wcstr, count);
  398. ASSERT(wcstr == NULL || result <= (int)count);
  399. if (result > 0)
  400. wcstr[result-1] = 0;
  401. return result;
  402. }
  403. /////////////////////////////////////////////////////////////////////////////
  404. // Windows extensions to strings
  405. BOOL CStr::LoadString(HINSTANCE hInst, UINT nID)
  406. {
  407. ASSERT(nID != 0); // 0 is an illegal string ID
  408. // Note: resource strings limited to 511 characters
  409. TCHAR szBuffer[512];
  410. UINT nSize = StrLoadString(hInst, nID, szBuffer);
  411. AssignCopy(nSize, szBuffer);
  412. return nSize > 0;
  413. }
  414. int STRAPI StrLoadString(HINSTANCE hInst, UINT nID, LPTSTR lpszBuf)
  415. {
  416. ASSERT(IsValidAddressz(lpszBuf, 512)); // must be big enough for 512 bytes
  417. #ifdef DBG
  418. // LoadString without annoying warning from the Debug kernel if the
  419. // segment containing the string is not present
  420. if (::FindResource(hInst, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  421. {
  422. lpszBuf[0] = '\0';
  423. return 0; // not found
  424. }
  425. #endif //DBG
  426. int nLen = ::LoadString(hInst, nID, lpszBuf, 511);
  427. if (nLen == 0)
  428. lpszBuf[0] = '\0';
  429. return nLen;
  430. }
  431. BOOL STRAPI IsValidAddressz(const void* lp, UINT nBytes, BOOL bReadWrite)
  432. {
  433. // simple version using Win-32 APIs for pointer validation.
  434. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  435. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  436. }
  437. BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength)
  438. {
  439. if (lpsz == NULL)
  440. return FALSE;
  441. return ::IsBadStringPtrA(lpsz, nLength) == 0;
  442. }
  443. BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength)
  444. {
  445. if (lpsz == NULL)
  446. return FALSE;
  447. return ::IsBadStringPtrW(lpsz, nLength) == 0;
  448. }
  449. #ifdef OLE_AUTOMATION
  450. #ifdef UNICODE
  451. BSTR CStr::AllocSysString()
  452. {
  453. BSTR bstr = ::SysAllocStringLen(m_pchData, m_nDataLength);
  454. if (bstr == NULL)
  455. ;//REVIEW AfxThrowMemoryException();
  456. return bstr;
  457. }
  458. BSTR CStr::SetSysString(BSTR* pbstr)
  459. {
  460. ASSERT(IsValidAddressz(pbstr, sizeof(BSTR)));
  461. if (!::SysReAllocStringLen(pbstr, m_pchData, m_nDataLength))
  462. ; //REVIEW AfxThrowMemoryException();
  463. ASSERT(*pbstr != NULL);
  464. return *pbstr;
  465. }
  466. #endif
  467. #endif // #ifdef OLE_AUTOMATION
  468. ///////////////////////////////////////////////////////////////////////////////
  469. // Orginally from StrEx.cpp
  470. CStr::CStr(TCHAR ch, int nLength)
  471. {
  472. #ifndef UNICODE
  473. ASSERT(!IsDBCSLeadByte(ch)); // can't create a lead byte string
  474. #endif
  475. if (nLength < 1)
  476. {
  477. // return empty string if invalid repeat count
  478. Init();
  479. }
  480. else
  481. {
  482. AllocBuffer(nLength);
  483. #ifdef UNICODE
  484. for (int i = 0; i < nLength; i++)
  485. m_pchData[i] = ch;
  486. #else
  487. memset(m_pchData, ch, nLength);
  488. #endif
  489. }
  490. }
  491. CStr::CStr(LPCTSTR lpch, int nLength)
  492. {
  493. if (nLength == 0)
  494. Init();
  495. else
  496. {
  497. ASSERT(IsValidAddressz(lpch, nLength, FALSE));
  498. AllocBuffer(nLength);
  499. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  500. }
  501. }
  502. //////////////////////////////////////////////////////////////////////////////
  503. // Assignment operators
  504. const CStr& CStr::operator=(TCHAR ch)
  505. {
  506. #ifndef UNICODE
  507. ASSERT(!IsDBCSLeadByte(ch)); // can't set single lead byte
  508. #endif
  509. AssignCopy(1, &ch);
  510. return *this;
  511. }
  512. //////////////////////////////////////////////////////////////////////////////
  513. // less common string expressions
  514. CStr STRAPI operator+(const CStr& string1, TCHAR ch)
  515. {
  516. CStr s;
  517. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData, 1, &ch);
  518. return s;
  519. }
  520. CStr STRAPI operator+(TCHAR ch, const CStr& string)
  521. {
  522. CStr s;
  523. s.ConcatCopy(1, &ch, string.m_nDataLength, string.m_pchData);
  524. return s;
  525. }
  526. //////////////////////////////////////////////////////////////////////////////
  527. // Very simple sub-string extraction
  528. CStr CStr::Mid(int nFirst) const
  529. {
  530. return Mid(nFirst, m_nDataLength - nFirst);
  531. }
  532. CStr CStr::Mid(int nFirst, int nCount) const
  533. {
  534. ASSERT(nFirst >= 0);
  535. ASSERT(nCount >= 0);
  536. // out-of-bounds requests return sensible things
  537. if (nFirst + nCount > m_nDataLength)
  538. nCount = m_nDataLength - nFirst;
  539. if (nFirst > m_nDataLength)
  540. nCount = 0;
  541. CStr dest;
  542. AllocCopy(dest, nCount, nFirst, 0);
  543. return dest;
  544. }
  545. CStr CStr::Right(int nCount) const
  546. {
  547. ASSERT(nCount >= 0);
  548. if (nCount > m_nDataLength)
  549. nCount = m_nDataLength;
  550. CStr dest;
  551. AllocCopy(dest, nCount, m_nDataLength-nCount, 0);
  552. return dest;
  553. }
  554. CStr CStr::Left(int nCount) const
  555. {
  556. ASSERT(nCount >= 0);
  557. if (nCount > m_nDataLength)
  558. nCount = m_nDataLength;
  559. CStr dest;
  560. AllocCopy(dest, nCount, 0, 0);
  561. return dest;
  562. }
  563. // strspn equivalent
  564. CStr CStr::SpanIncluding(LPCTSTR lpszCharSet) const
  565. {
  566. ASSERT(IsValidString(lpszCharSet, FALSE));
  567. return Left(_tcsspn(m_pchData, lpszCharSet));
  568. }
  569. // strcspn equivalent
  570. CStr CStr::SpanExcluding(LPCTSTR lpszCharSet) const
  571. {
  572. ASSERT(IsValidString(lpszCharSet, FALSE));
  573. return Left(_tcscspn(m_pchData, lpszCharSet));
  574. }
  575. //////////////////////////////////////////////////////////////////////////////
  576. // Finding
  577. int CStr::ReverseFind(TCHAR ch) const
  578. {
  579. // find last single character
  580. LPTSTR lpsz = _tcsrchr(m_pchData, ch);
  581. // return -1 if not found, distance from beginning otherwise
  582. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  583. }
  584. // find a sub-string (like strstr)
  585. int CStr::Find(LPCTSTR lpszSub) const
  586. {
  587. ASSERT(IsValidString(lpszSub, FALSE));
  588. // find first matching substring
  589. LPTSTR lpsz = _tcsstr(m_pchData, lpszSub);
  590. // return -1 for not found, distance from beginning otherwise
  591. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  592. }
  593. /////////////////////////////////////////////////////////////////////////////
  594. // String formatting
  595. #define FORCE_ANSI 0x10000
  596. #define FORCE_UNICODE 0x20000
  597. // formatting (using wsprintf style formatting)
  598. void CStr::Format(LPCTSTR lpszFormat, ...)
  599. {
  600. ASSERT(IsValidString(lpszFormat, FALSE));
  601. va_list argList;
  602. va_start(argList, lpszFormat);
  603. FormatV(lpszFormat, argList);
  604. va_end(argList);
  605. }
  606. void CStr::FormatV(LPCTSTR lpszFormat, va_list argList)
  607. {
  608. va_list argListSave = argList;
  609. // make a guess at the maximum length of the resulting string
  610. int nMaxLen = 0;
  611. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  612. {
  613. // handle '%' character, but watch out for '%%'
  614. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  615. {
  616. nMaxLen += _tclen(lpsz);
  617. continue;
  618. }
  619. int nItemLen = 0;
  620. // handle '%' character with format
  621. int nWidth = 0;
  622. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  623. {
  624. // check for valid flags
  625. if (*lpsz == '#')
  626. nMaxLen += 2; // for '0x'
  627. else if (*lpsz == '*')
  628. nWidth = va_arg(argList, int);
  629. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  630. *lpsz == ' ')
  631. ;
  632. else // hit non-flag character
  633. break;
  634. }
  635. // get width and skip it
  636. if (nWidth == 0)
  637. {
  638. // width indicated by
  639. nWidth = _ttoi(lpsz);
  640. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  641. ;
  642. }
  643. ASSERT(nWidth >= 0);
  644. int nPrecision = 0;
  645. if (*lpsz == '.')
  646. {
  647. // skip past '.' separator (width.precision)
  648. lpsz = _tcsinc(lpsz);
  649. // get precision and skip it
  650. if (*lpsz == '*')
  651. {
  652. nPrecision = va_arg(argList, int);
  653. lpsz = _tcsinc(lpsz);
  654. }
  655. else
  656. {
  657. nPrecision = _ttoi(lpsz);
  658. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  659. ;
  660. }
  661. ASSERT(nPrecision >= 0);
  662. }
  663. // should be on type modifier or specifier
  664. int nModifier = 0;
  665. switch (*lpsz)
  666. {
  667. // modifiers that affect size
  668. case 'h':
  669. nModifier = FORCE_ANSI;
  670. lpsz = _tcsinc(lpsz);
  671. break;
  672. case 'l':
  673. nModifier = FORCE_UNICODE;
  674. lpsz = _tcsinc(lpsz);
  675. break;
  676. // modifiers that do not affect size
  677. case 'F':
  678. case 'N':
  679. case 'L':
  680. lpsz = _tcsinc(lpsz);
  681. break;
  682. }
  683. // now should be on specifier
  684. switch (*lpsz | nModifier)
  685. {
  686. // single characters
  687. case 'c':
  688. case 'C':
  689. nItemLen = 2;
  690. va_arg(argList, TCHAR);
  691. break;
  692. case 'c'|FORCE_ANSI:
  693. case 'C'|FORCE_ANSI:
  694. nItemLen = 2;
  695. va_arg(argList, char);
  696. break;
  697. case 'c'|FORCE_UNICODE:
  698. case 'C'|FORCE_UNICODE:
  699. nItemLen = 2;
  700. va_arg(argList, WCHAR);
  701. break;
  702. // strings
  703. case 's':
  704. case 'S':
  705. nItemLen = lstrlen(va_arg(argList, LPCTSTR));
  706. nItemLen = __max(1, nItemLen);
  707. break;
  708. case 's'|FORCE_ANSI:
  709. case 'S'|FORCE_ANSI:
  710. nItemLen = lstrlenA(va_arg(argList, LPCSTR));
  711. nItemLen = __max(1, nItemLen);
  712. break;
  713. #ifndef _MAC
  714. case 's'|FORCE_UNICODE:
  715. case 'S'|FORCE_UNICODE:
  716. nItemLen = wcslen(va_arg(argList, LPWSTR));
  717. nItemLen = __max(1, nItemLen);
  718. break;
  719. #endif
  720. }
  721. // adjust nItemLen for strings
  722. if (nItemLen != 0)
  723. {
  724. nItemLen = __max(nItemLen, nWidth);
  725. if (nPrecision != 0)
  726. nItemLen = __min(nItemLen, nPrecision);
  727. }
  728. else
  729. {
  730. switch (*lpsz)
  731. {
  732. // integers
  733. case 'd':
  734. case 'i':
  735. case 'u':
  736. case 'x':
  737. case 'X':
  738. case 'o':
  739. va_arg(argList, int);
  740. nItemLen = 32;
  741. nItemLen = __max(nItemLen, nWidth+nPrecision);
  742. break;
  743. case 'e':
  744. case 'f':
  745. case 'g':
  746. case 'G':
  747. va_arg(argList, _STR_DOUBLE);
  748. nItemLen = 128;
  749. nItemLen = __max(nItemLen, nWidth+nPrecision);
  750. break;
  751. case 'p':
  752. va_arg(argList, void*);
  753. nItemLen = 32;
  754. nItemLen = __max(nItemLen, nWidth+nPrecision);
  755. break;
  756. // no output
  757. case 'n':
  758. va_arg(argList, int*);
  759. break;
  760. default:
  761. ASSERT(FALSE); // unknown formatting option
  762. }
  763. }
  764. // adjust nMaxLen for output nItemLen
  765. nMaxLen += nItemLen;
  766. }
  767. va_end(argList);
  768. // finally, set the buffer length and format the string
  769. GetBuffer(nMaxLen);
  770. #include "pushwarn.h"
  771. #pragma warning(disable: 4552) // "<=" operator has no effect
  772. VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= nMaxLen);
  773. #include "popwarn.h"
  774. ReleaseBuffer();
  775. va_end(argListSave);
  776. }
  777. #ifndef _MAC
  778. // formatting (using FormatMessage style formatting)
  779. void __cdecl CStr::FormatMessage(LPCTSTR lpszFormat, ...)
  780. {
  781. // format message into temporary buffer lpszTemp
  782. va_list argList;
  783. va_start(argList, lpszFormat);
  784. LPTSTR lpszTemp;
  785. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  786. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  787. lpszTemp == NULL)
  788. {
  789. // AfxThrowMemoryException();
  790. return;
  791. }
  792. // assign lpszTemp into the resulting string and free the temporary
  793. *this = lpszTemp;
  794. LocalFree(lpszTemp);
  795. va_end(argList);
  796. }
  797. #endif //!_MAC
  798. void CStr::TrimRight()
  799. {
  800. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  801. LPTSTR lpsz = m_pchData;
  802. LPTSTR lpszLast = NULL;
  803. while (*lpsz != '\0')
  804. {
  805. if (_istspace(*lpsz))
  806. {
  807. if (lpszLast == NULL)
  808. lpszLast = lpsz;
  809. }
  810. else
  811. lpszLast = NULL;
  812. lpsz = _tcsinc(lpsz);
  813. }
  814. if (lpszLast != NULL)
  815. {
  816. // truncate at trailing space start
  817. *lpszLast = '\0';
  818. m_nDataLength = int(lpszLast - m_pchData);
  819. }
  820. }
  821. void CStr::TrimLeft()
  822. {
  823. // find first non-space character
  824. LPCTSTR lpsz = m_pchData;
  825. while (_istspace(*lpsz))
  826. lpsz = _tcsinc(lpsz);
  827. // fix up data and length
  828. int nDataLength = m_nDataLength - int(lpsz - m_pchData);
  829. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  830. m_nDataLength = nDataLength;
  831. }
  832. #if 0
  833. //
  834. // JonCaves 1/28/02
  835. //
  836. // These function are never used and in any case as there are no proceeding
  837. // template function definition it is illegal: so I am removing them
  838. //
  839. ///////////////////////////////////////////////////////////////////////////////
  840. // String support for template collections
  841. template<>
  842. void STRAPI ConstructElements(CStr* pElements, int nCount)
  843. {
  844. ASSERT(IsValidAddressz(pElements, nCount * sizeof(CStr)));
  845. for (; nCount--; ++pElements)
  846. memcpy(pElements, &strEmptyString, sizeof(*pElements));
  847. }
  848. template<>
  849. void STRAPI DestructElements(CStr* pElements, int nCount)
  850. {
  851. ASSERT(IsValidAddressz(pElements, nCount * sizeof(CStr)));
  852. for (; nCount--; ++pElements)
  853. pElements->Empty();
  854. }
  855. template<>
  856. UINT STRAPI HashKey(LPCTSTR key)
  857. {
  858. UINT nHash = 0;
  859. while (*key)
  860. nHash = (nHash<<5) + nHash + *key++;
  861. return nHash;
  862. }
  863. #endif