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.

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