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.

559 lines
14 KiB

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (c) 1992-2001 Microsoft Corporation, All Rights Reserved
  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 "precomp.h"
  11. #include <provstd.h>
  12. #include <provtempl.h>
  13. #include <provstr.h>
  14. #include <strsafe.h>
  15. //////////////////////////////////////////////////////////////////////////////
  16. // More sophisticated construction
  17. CString::CString(TCHAR ch, int nLength)
  18. {
  19. Init();
  20. if (nLength >= 1)
  21. {
  22. AllocBuffer(nLength);
  23. #ifdef _UNICODE
  24. for (int i = 0; i < nLength; i++)
  25. m_pchData[i] = ch;
  26. #else
  27. memset(m_pchData, ch, nLength);
  28. #endif
  29. }
  30. }
  31. CString::CString(LPCTSTR lpch, int nLength)
  32. {
  33. Init();
  34. if (nLength != 0)
  35. {
  36. AllocBuffer(nLength);
  37. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  38. }
  39. }
  40. //////////////////////////////////////////////////////////////////////////////
  41. // Assignment operators
  42. const CString& CString::operator=(TCHAR ch)
  43. {
  44. AssignCopy(1, &ch);
  45. return *this;
  46. }
  47. //////////////////////////////////////////////////////////////////////////////
  48. // less common string expressions
  49. CString AFXAPI operator+(const CString& string1, TCHAR ch)
  50. {
  51. CString s;
  52. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  53. return s;
  54. }
  55. CString AFXAPI operator+(TCHAR ch, const CString& string)
  56. {
  57. CString s;
  58. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  59. return s;
  60. }
  61. //////////////////////////////////////////////////////////////////////////////
  62. // Very simple sub-string extraction
  63. CString CString::Mid(int nFirst) const
  64. {
  65. return Mid(nFirst, GetData()->nDataLength - nFirst);
  66. }
  67. CString CString::Mid(int nFirst, int nCount) const
  68. {
  69. // out-of-bounds requests return sensible things
  70. if (nFirst < 0)
  71. nFirst = 0;
  72. if (nCount < 0)
  73. nCount = 0;
  74. if (nFirst + nCount > GetData()->nDataLength)
  75. nCount = GetData()->nDataLength - nFirst;
  76. if (nFirst > GetData()->nDataLength)
  77. nCount = 0;
  78. CString dest;
  79. AllocCopy(dest, nCount, nFirst, 0);
  80. return dest;
  81. }
  82. CString CString::Right(int nCount) const
  83. {
  84. if (nCount < 0)
  85. nCount = 0;
  86. else if (nCount > GetData()->nDataLength)
  87. nCount = GetData()->nDataLength;
  88. CString dest;
  89. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  90. return dest;
  91. }
  92. CString CString::Left(int nCount) const
  93. {
  94. if (nCount < 0)
  95. nCount = 0;
  96. else if (nCount > GetData()->nDataLength)
  97. nCount = GetData()->nDataLength;
  98. CString dest;
  99. AllocCopy(dest, nCount, 0, 0);
  100. return dest;
  101. }
  102. // strspn equivalent
  103. CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  104. {
  105. return Left(_tcsspn(m_pchData, lpszCharSet));
  106. }
  107. // strcspn equivalent
  108. CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  109. {
  110. return Left(_tcscspn(m_pchData, lpszCharSet));
  111. }
  112. //////////////////////////////////////////////////////////////////////////////
  113. // Finding
  114. int CString::ReverseFind(TCHAR ch) const
  115. {
  116. // find last single character
  117. LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR)ch);
  118. // return -1 if not found, distance from beginning otherwise
  119. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  120. }
  121. // find a sub-string (like strstr)
  122. int CString::Find(LPCTSTR lpszSub) const
  123. {
  124. // find first matching substring
  125. LPTSTR lpsz = _tcsstr(m_pchData, lpszSub);
  126. // return -1 for not found, distance from beginning otherwise
  127. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  128. }
  129. /////////////////////////////////////////////////////////////////////////////
  130. // CString formatting
  131. #ifdef _MAC
  132. #define TCHAR_ARG int
  133. #define WCHAR_ARG unsigned
  134. #define CHAR_ARG int
  135. #else
  136. #define TCHAR_ARG TCHAR
  137. #define WCHAR_ARG WCHAR
  138. #define CHAR_ARG char
  139. #endif
  140. #if defined(_68K_) || defined(_X86_)
  141. #define DOUBLE_ARG _AFX_DOUBLE
  142. #else
  143. #define DOUBLE_ARG double
  144. #endif
  145. #define FORCE_ANSI 0x10000
  146. #define FORCE_UNICODE 0x20000
  147. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  148. {
  149. va_list argListSave = argList;
  150. // make a guess at the maximum length of the resulting string
  151. int nMaxLen = 0;
  152. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  153. {
  154. // handle '%' character, but watch out for '%%'
  155. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  156. {
  157. nMaxLen += _tclen(lpsz);
  158. continue;
  159. }
  160. int nItemLen = 0;
  161. // handle '%' character with format
  162. int nWidth = 0;
  163. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  164. {
  165. // check for valid flags
  166. if (*lpsz == '#')
  167. nMaxLen += 2; // for '0x'
  168. else if (*lpsz == '*')
  169. nWidth = va_arg(argList, int);
  170. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  171. *lpsz == ' ')
  172. ;
  173. else // hit non-flag character
  174. break;
  175. }
  176. // get width and skip it
  177. if (nWidth == 0)
  178. {
  179. // width indicated by
  180. nWidth = _ttoi(lpsz);
  181. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  182. ;
  183. }
  184. int nPrecision = 0;
  185. if (*lpsz == '.')
  186. {
  187. // skip past '.' separator (width.precision)
  188. lpsz = _tcsinc(lpsz);
  189. // get precision and skip it
  190. if (*lpsz == '*')
  191. {
  192. nPrecision = va_arg(argList, int);
  193. lpsz = _tcsinc(lpsz);
  194. }
  195. else
  196. {
  197. nPrecision = _ttoi(lpsz);
  198. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  199. ;
  200. }
  201. }
  202. // should be on type modifier or specifier
  203. int nModifier = 0;
  204. switch (*lpsz)
  205. {
  206. // modifiers that affect size
  207. case 'h':
  208. nModifier = FORCE_ANSI;
  209. lpsz = _tcsinc(lpsz);
  210. break;
  211. case 'l':
  212. nModifier = FORCE_UNICODE;
  213. lpsz = _tcsinc(lpsz);
  214. break;
  215. // modifiers that do not affect size
  216. case 'F':
  217. case 'N':
  218. case 'L':
  219. lpsz = _tcsinc(lpsz);
  220. break;
  221. }
  222. // now should be on specifier
  223. switch (*lpsz | nModifier)
  224. {
  225. // single characters
  226. case 'c':
  227. case 'C':
  228. nItemLen = 2;
  229. va_arg(argList, TCHAR_ARG);
  230. break;
  231. case 'c'|FORCE_ANSI:
  232. case 'C'|FORCE_ANSI:
  233. nItemLen = 2;
  234. va_arg(argList, CHAR_ARG);
  235. break;
  236. case 'c'|FORCE_UNICODE:
  237. case 'C'|FORCE_UNICODE:
  238. nItemLen = 2;
  239. va_arg(argList, WCHAR_ARG);
  240. break;
  241. // strings
  242. case 's':
  243. {
  244. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  245. if (pstrNextArg == NULL)
  246. nItemLen = 6; // "(null)"
  247. else
  248. {
  249. nItemLen = lstrlen(pstrNextArg);
  250. nItemLen = max(1, nItemLen);
  251. }
  252. break;
  253. }
  254. case 'S':
  255. {
  256. #ifndef _UNICODE
  257. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  258. if (pstrNextArg == NULL)
  259. nItemLen = 6; // "(null)"
  260. else
  261. {
  262. nItemLen = wcslen(pstrNextArg);
  263. nItemLen = max(1, nItemLen);
  264. }
  265. #else
  266. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  267. if (pstrNextArg == NULL)
  268. nItemLen = 6; // "(null)"
  269. else
  270. {
  271. nItemLen = lstrlenA(pstrNextArg);
  272. nItemLen = max(1, nItemLen);
  273. }
  274. #endif
  275. break;
  276. }
  277. case 's'|FORCE_ANSI:
  278. case 'S'|FORCE_ANSI:
  279. {
  280. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  281. if (pstrNextArg == NULL)
  282. nItemLen = 6; // "(null)"
  283. else
  284. {
  285. nItemLen = lstrlenA(pstrNextArg);
  286. nItemLen = max(1, nItemLen);
  287. }
  288. break;
  289. }
  290. #ifndef _MAC
  291. case 's'|FORCE_UNICODE:
  292. case 'S'|FORCE_UNICODE:
  293. {
  294. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  295. if (pstrNextArg == NULL)
  296. nItemLen = 6; // "(null)"
  297. else
  298. {
  299. nItemLen = wcslen(pstrNextArg);
  300. nItemLen = max(1, nItemLen);
  301. }
  302. break;
  303. }
  304. #endif
  305. }
  306. // adjust nItemLen for strings
  307. if (nItemLen != 0)
  308. {
  309. nItemLen = max(nItemLen, nWidth);
  310. if (nPrecision != 0)
  311. nItemLen = min(nItemLen, nPrecision);
  312. }
  313. else
  314. {
  315. switch (*lpsz)
  316. {
  317. // integers
  318. case 'd':
  319. case 'i':
  320. case 'u':
  321. case 'x':
  322. case 'X':
  323. case 'o':
  324. va_arg(argList, int);
  325. nItemLen = 32;
  326. nItemLen = max(nItemLen, nWidth+nPrecision);
  327. break;
  328. case 'e':
  329. case 'f':
  330. case 'g':
  331. case 'G':
  332. va_arg(argList, DOUBLE_ARG);
  333. nItemLen = 128;
  334. nItemLen = max(nItemLen, nWidth+nPrecision);
  335. break;
  336. case 'p':
  337. va_arg(argList, void*);
  338. nItemLen = 32;
  339. nItemLen = max(nItemLen, nWidth+nPrecision);
  340. break;
  341. // no output
  342. case 'n':
  343. va_arg(argList, int*);
  344. break;
  345. default:
  346. break ;
  347. }
  348. }
  349. // adjust nMaxLen for output nItemLen
  350. nMaxLen += nItemLen;
  351. }
  352. GetBuffer(nMaxLen);
  353. StringCchVPrintf(m_pchData, nMaxLen,lpszFormat, argListSave);
  354. ReleaseBuffer();
  355. va_end(argListSave);
  356. }
  357. // formatting (using wsprintf style formatting)
  358. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  359. {
  360. va_list argList;
  361. va_start(argList, lpszFormat);
  362. FormatV(lpszFormat, argList);
  363. va_end(argList);
  364. }
  365. #ifndef _MAC
  366. // formatting (using FormatMessage style formatting)
  367. void AFX_CDECL CString::FormatMessage(LPCTSTR lpszFormat, ...)
  368. {
  369. // format message into temporary buffer lpszTemp
  370. va_list argList;
  371. va_start(argList, lpszFormat);
  372. LPTSTR lpszTemp;
  373. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  374. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  375. lpszTemp == NULL)
  376. {
  377. throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR) ;
  378. }
  379. // assign lpszTemp into the resulting string and free the temporary
  380. *this = lpszTemp;
  381. LocalFree(lpszTemp);
  382. va_end(argList);
  383. }
  384. #endif //!_MAC
  385. void CString::TrimRight()
  386. {
  387. CopyBeforeWrite();
  388. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  389. LPTSTR lpsz = m_pchData;
  390. LPTSTR lpszLast = NULL;
  391. while (*lpsz != '\0')
  392. {
  393. if (_istspace(*lpsz))
  394. {
  395. if (lpszLast == NULL)
  396. lpszLast = lpsz;
  397. }
  398. else
  399. lpszLast = NULL;
  400. lpsz = _tcsinc(lpsz);
  401. }
  402. if (lpszLast != NULL)
  403. {
  404. // truncate at trailing space start
  405. *lpszLast = '\0';
  406. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  407. }
  408. }
  409. void CString::TrimLeft()
  410. {
  411. CopyBeforeWrite();
  412. // find first non-space character
  413. LPCTSTR lpsz = m_pchData;
  414. while (_istspace(*lpsz))
  415. lpsz = _tcsinc(lpsz);
  416. // fix up data and length
  417. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  418. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  419. GetData()->nDataLength = nDataLength;
  420. }
  421. ///////////////////////////////////////////////////////////////////////////////
  422. // CString support for template collections
  423. #if _MSC_VER >= 1100
  424. template<> void AFXAPI ConstructElements<CString> (CString* pElements, int nCount)
  425. #else
  426. void AFXAPI ConstructElements(CString* pElements, int nCount)
  427. #endif
  428. {
  429. for (; nCount--; ++pElements)
  430. memcpy(pElements, &afxEmptyString, sizeof(*pElements));
  431. }
  432. #if _MSC_VER >= 1100
  433. template<> void AFXAPI DestructElements<CString> (CString* pElements, int nCount)
  434. #else
  435. void AFXAPI DestructElements(CString* pElements, int nCount)
  436. #endif
  437. {
  438. for (; nCount--; ++pElements)
  439. pElements->~CString();
  440. }
  441. #if _MSC_VER >= 1100
  442. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, int nCount)
  443. #else
  444. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, int nCount)
  445. #endif
  446. {
  447. for (; nCount--; ++pDest, ++pSrc)
  448. *pDest = *pSrc;
  449. }
  450. /*
  451. #ifndef OLE2ANSI
  452. #if _MSC_VER >= 1100
  453. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
  454. #else
  455. UINT AFXAPI HashKey(LPCWSTR key)
  456. #endif
  457. {
  458. UINT nHash = 0;
  459. while (*key)
  460. nHash = (nHash<<5) + nHash + *key++;
  461. return nHash;
  462. }
  463. #endif
  464. #if _MSC_VER >= 1100
  465. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
  466. #else
  467. UINT AFXAPI HashKey(LPCSTR key)
  468. #endif
  469. {
  470. UINT nHash = 0;
  471. while (*key)
  472. nHash = (nHash<<5) + nHash + *key++;
  473. return nHash;
  474. }
  475. */
  476. UINT AFXAPI HashKeyLPCWSTR(LPCWSTR key)
  477. {
  478. UINT nHash = 0;
  479. while (*key)
  480. nHash = (nHash<<5) + nHash + *key++;
  481. return nHash;
  482. }
  483. UINT AFXAPI HashKeyLPCSTR(LPCSTR key)
  484. {
  485. UINT nHash = 0;
  486. while (*key)
  487. nHash = (nHash<<5) + nHash + *key++;
  488. return nHash;
  489. }
  490. ///////////////////////////////////////////////////////////////////////////////