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.

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