strex.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  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. // WINSCP
  12. #include <algorithm>
  13. #define max std::max
  14. #define min std::min
  15. //////////////////////////////////////////////////////////////////////////////
  16. // More sophisticated construction
  17. CString::CString(LPCTSTR lpch, int nLength)
  18. {
  19. Init();
  20. if (nLength != 0)
  21. {
  22. ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  23. AllocBuffer(nLength);
  24. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  25. }
  26. }
  27. /////////////////////////////////////////////////////////////////////////////
  28. // Special conversion constructors
  29. CString::CString(LPCSTR lpsz, int nLength)
  30. {
  31. Init();
  32. if (nLength != 0)
  33. {
  34. AllocBuffer(nLength);
  35. int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
  36. ReleaseBuffer(n >= 0 ? n : -1);
  37. }
  38. }
  39. //////////////////////////////////////////////////////////////////////////////
  40. // Assignment operators
  41. const CString& CString::operator=(TCHAR ch)
  42. {
  43. AssignCopy(1, &ch);
  44. return *this;
  45. }
  46. //////////////////////////////////////////////////////////////////////////////
  47. // less common string expressions
  48. CString AFXAPI operator+(const CString& string1, TCHAR ch)
  49. {
  50. CString s;
  51. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  52. return s;
  53. }
  54. CString AFXAPI operator+(TCHAR ch, const CString& string)
  55. {
  56. CString s;
  57. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  58. return s;
  59. }
  60. //////////////////////////////////////////////////////////////////////////////
  61. // Advanced manipulation
  62. int CString::Delete(int nIndex, int nCount /* = 1 */)
  63. {
  64. if (nIndex < 0)
  65. nIndex = 0;
  66. int nNewLength = GetData()->nDataLength;
  67. if (nCount > 0 && nIndex < nNewLength)
  68. {
  69. CopyBeforeWrite();
  70. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  71. memcpy(m_pchData + nIndex,
  72. m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  73. GetData()->nDataLength = nNewLength - nCount;
  74. }
  75. return nNewLength;
  76. }
  77. int CString::Replace(TCHAR chOld, TCHAR chNew)
  78. {
  79. int nCount = 0;
  80. // short-circuit the nop case
  81. if (chOld != chNew)
  82. {
  83. // otherwise modify each character that matches in the string
  84. CopyBeforeWrite();
  85. LPTSTR psz = m_pchData;
  86. LPTSTR pszEnd = psz + GetData()->nDataLength;
  87. while (psz < pszEnd)
  88. {
  89. // replace instances of the specified character only
  90. if (*psz == chOld)
  91. {
  92. *psz = chNew;
  93. nCount++;
  94. }
  95. psz = _tcsinc(psz);
  96. }
  97. }
  98. return nCount;
  99. }
  100. int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  101. {
  102. // can't have empty or NULL lpszOld
  103. int nSourceLen = SafeStrlen(lpszOld);
  104. if (nSourceLen == 0)
  105. return 0;
  106. int nReplacementLen = SafeStrlen(lpszNew);
  107. // loop once to figure out the size of the result string
  108. int nCount = 0;
  109. LPTSTR lpszStart = m_pchData;
  110. LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  111. LPTSTR lpszTarget;
  112. while (lpszStart < lpszEnd)
  113. {
  114. while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  115. {
  116. nCount++;
  117. lpszStart = lpszTarget + nSourceLen;
  118. }
  119. lpszStart += lstrlen(lpszStart) + 1;
  120. }
  121. // if any changes were made, make them
  122. if (nCount > 0)
  123. {
  124. CopyBeforeWrite();
  125. // if the buffer is too small, just
  126. // allocate a new buffer (slow but sure)
  127. int nOldLength = GetData()->nDataLength;
  128. int nNewLength = nOldLength + (nReplacementLen-nSourceLen)*nCount;
  129. if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  130. {
  131. CStringData* pOldData = GetData();
  132. LPTSTR pstr = m_pchData;
  133. AllocBuffer(nNewLength);
  134. memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  135. CString::Release(pOldData);
  136. }
  137. // else, we just do it in-place
  138. lpszStart = m_pchData;
  139. lpszEnd = m_pchData + GetData()->nDataLength;
  140. // loop again to actually do the work
  141. while (lpszStart < lpszEnd)
  142. {
  143. while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  144. {
  145. int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen);
  146. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
  147. nBalance * sizeof(TCHAR));
  148. memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
  149. lpszStart = lpszTarget + nReplacementLen;
  150. lpszStart[nBalance] = '\0';
  151. nOldLength += (nReplacementLen - nSourceLen);
  152. }
  153. lpszStart += lstrlen(lpszStart) + 1;
  154. }
  155. ASSERT(m_pchData[nNewLength] == '\0');
  156. GetData()->nDataLength = nNewLength;
  157. }
  158. return nCount;
  159. }
  160. //////////////////////////////////////////////////////////////////////////////
  161. // Very simple sub-string extraction
  162. CString CString::Mid(int nFirst) const
  163. {
  164. return Mid(nFirst, GetData()->nDataLength - nFirst);
  165. }
  166. CString CString::Mid(int nFirst, int nCount) const
  167. {
  168. // out-of-bounds requests return sensible things
  169. if (nFirst < 0)
  170. nFirst = 0;
  171. if (nCount < 0)
  172. nCount = 0;
  173. if (nFirst + nCount > GetData()->nDataLength)
  174. nCount = GetData()->nDataLength - nFirst;
  175. if (nFirst > GetData()->nDataLength)
  176. nCount = 0;
  177. ASSERT(nFirst >= 0);
  178. ASSERT(nFirst + nCount <= GetData()->nDataLength);
  179. // optimize case of returning entire string
  180. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  181. return *this;
  182. CString dest;
  183. AllocCopy(dest, nCount, nFirst, 0);
  184. return dest;
  185. }
  186. CString CString::Right(int nCount) const
  187. {
  188. if (nCount < 0)
  189. nCount = 0;
  190. if (nCount >= GetData()->nDataLength)
  191. return *this;
  192. CString dest;
  193. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  194. return dest;
  195. }
  196. CString CString::Left(int nCount) const
  197. {
  198. if (nCount < 0)
  199. nCount = 0;
  200. if (nCount >= GetData()->nDataLength)
  201. return *this;
  202. CString dest;
  203. AllocCopy(dest, nCount, 0, 0);
  204. return dest;
  205. }
  206. //////////////////////////////////////////////////////////////////////////////
  207. // Finding
  208. int CString::ReverseFind(TCHAR ch) const
  209. {
  210. // find last single character
  211. LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
  212. // return -1 if not found, distance from beginning otherwise
  213. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  214. }
  215. // find a sub-string (like strstr)
  216. int CString::Find(LPCTSTR lpszSub) const
  217. {
  218. return Find(lpszSub, 0);
  219. }
  220. int CString::Find(LPCTSTR lpszSub, int nStart) const
  221. {
  222. ASSERT(AfxIsValidString(lpszSub));
  223. int nLength = GetData()->nDataLength;
  224. if (nStart > nLength)
  225. return -1;
  226. // find first matching substring
  227. LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
  228. // return -1 for not found, distance from beginning otherwise
  229. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  230. }
  231. /////////////////////////////////////////////////////////////////////////////
  232. // CString formatting
  233. #define TCHAR_ARG TCHAR
  234. #define WCHAR_ARG WCHAR
  235. #define CHAR_ARG char
  236. #ifdef _X86_
  237. #define DOUBLE_ARG _AFX_DOUBLE
  238. #else
  239. #define DOUBLE_ARG double
  240. #endif
  241. #define FORCE_ANSI 0x10000
  242. #define FORCE_UNICODE 0x20000
  243. #define FORCE_INT64 0x40000
  244. #define _tclen(__a) (1)
  245. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  246. {
  247. ASSERT(AfxIsValidString(lpszFormat));
  248. va_list argListSave = argList;
  249. // make a guess at the maximum length of the resulting string
  250. int nMaxLen = 0;
  251. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  252. {
  253. // handle '%' character, but watch out for '%%'
  254. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  255. {
  256. nMaxLen += _tclen(lpsz);
  257. continue;
  258. }
  259. int nItemLen = 0;
  260. // handle '%' character with format
  261. int nWidth = 0;
  262. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  263. {
  264. // check for valid flags
  265. if (*lpsz == '#')
  266. nMaxLen += 2; // for '0x'
  267. else if (*lpsz == '*')
  268. nWidth = va_arg(argList, int);
  269. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  270. *lpsz == ' ')
  271. ;
  272. else // hit non-flag character
  273. break;
  274. }
  275. // get width and skip it
  276. if (nWidth == 0)
  277. {
  278. // width indicated by
  279. nWidth = _ttoi(lpsz);
  280. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  281. ;
  282. }
  283. ASSERT(nWidth >= 0);
  284. int nPrecision = 0;
  285. if (*lpsz == '.')
  286. {
  287. // skip past '.' separator (width.precision)
  288. lpsz = _tcsinc(lpsz);
  289. // get precision and skip it
  290. if (*lpsz == '*')
  291. {
  292. nPrecision = va_arg(argList, int);
  293. lpsz = _tcsinc(lpsz);
  294. }
  295. else
  296. {
  297. nPrecision = _ttoi(lpsz);
  298. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  299. ;
  300. }
  301. ASSERT(nPrecision >= 0);
  302. }
  303. // should be on type modifier or specifier
  304. int nModifier = 0;
  305. if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  306. {
  307. lpsz += 3;
  308. nModifier = FORCE_INT64;
  309. #if !defined(_X86_) && !defined(_ALPHA_)
  310. // __int64 is only available on X86 and ALPHA platforms
  311. ASSERT(FALSE);
  312. #endif
  313. }
  314. else
  315. {
  316. switch (*lpsz)
  317. {
  318. // modifiers that affect size
  319. case 'h':
  320. nModifier = FORCE_ANSI;
  321. lpsz = _tcsinc(lpsz);
  322. break;
  323. case 'l':
  324. nModifier = FORCE_UNICODE;
  325. lpsz = _tcsinc(lpsz);
  326. break;
  327. // modifiers that do not affect size
  328. case 'F':
  329. case 'N':
  330. case 'L':
  331. lpsz = _tcsinc(lpsz);
  332. break;
  333. }
  334. }
  335. // now should be on specifier
  336. switch (*lpsz | nModifier)
  337. {
  338. // single characters
  339. case 'c':
  340. case 'C':
  341. nItemLen = 2;
  342. va_arg(argList, TCHAR_ARG);
  343. break;
  344. case 'c'|FORCE_ANSI:
  345. case 'C'|FORCE_ANSI:
  346. nItemLen = 2;
  347. va_arg(argList, CHAR_ARG);
  348. break;
  349. case 'c'|FORCE_UNICODE:
  350. case 'C'|FORCE_UNICODE:
  351. nItemLen = 2;
  352. va_arg(argList, WCHAR_ARG);
  353. break;
  354. // strings
  355. case 's':
  356. {
  357. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  358. if (pstrNextArg == NULL)
  359. nItemLen = 6; // "(null)"
  360. else
  361. {
  362. nItemLen = lstrlen(pstrNextArg);
  363. nItemLen = max(1, nItemLen);
  364. }
  365. }
  366. break;
  367. case 'S':
  368. {
  369. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  370. if (pstrNextArg == NULL)
  371. nItemLen = 6; // "(null)"
  372. else
  373. {
  374. nItemLen = lstrlenA(pstrNextArg);
  375. nItemLen = max(1, nItemLen);
  376. }
  377. }
  378. break;
  379. case 's'|FORCE_ANSI:
  380. case 'S'|FORCE_ANSI:
  381. {
  382. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  383. if (pstrNextArg == NULL)
  384. nItemLen = 6; // "(null)"
  385. else
  386. {
  387. nItemLen = lstrlenA(pstrNextArg);
  388. nItemLen = max(1, nItemLen);
  389. }
  390. }
  391. break;
  392. case 's'|FORCE_UNICODE:
  393. case 'S'|FORCE_UNICODE:
  394. {
  395. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  396. if (pstrNextArg == NULL)
  397. nItemLen = 6; // "(null)"
  398. else
  399. {
  400. nItemLen = wcslen(pstrNextArg);
  401. nItemLen = max(1, nItemLen);
  402. }
  403. }
  404. break;
  405. }
  406. // adjust nItemLen for strings
  407. if (nItemLen != 0)
  408. {
  409. if (nPrecision != 0)
  410. nItemLen = min(nItemLen, nPrecision);
  411. nItemLen = max(nItemLen, nWidth);
  412. }
  413. else
  414. {
  415. switch (*lpsz)
  416. {
  417. // integers
  418. case 'd':
  419. case 'i':
  420. case 'u':
  421. case 'x':
  422. case 'X':
  423. case 'o':
  424. if (nModifier & FORCE_INT64)
  425. va_arg(argList, __int64);
  426. else
  427. va_arg(argList, int);
  428. nItemLen = 32;
  429. nItemLen = max(nItemLen, nWidth+nPrecision);
  430. break;
  431. case 'e':
  432. case 'g':
  433. case 'G':
  434. va_arg(argList, DOUBLE_ARG);
  435. nItemLen = 128;
  436. nItemLen = max(nItemLen, nWidth+nPrecision);
  437. break;
  438. case 'f':
  439. va_arg(argList, DOUBLE_ARG);
  440. nItemLen = 128; // width isn't truncated
  441. // 312 == strlen("-1+(309 zeroes).")
  442. // 309 zeroes == max precision of a double
  443. nItemLen = max(nItemLen, 312+nPrecision);
  444. break;
  445. case 'p':
  446. va_arg(argList, void*);
  447. nItemLen = 32;
  448. nItemLen = max(nItemLen, nWidth+nPrecision);
  449. break;
  450. // no output
  451. case 'n':
  452. va_arg(argList, int*);
  453. break;
  454. default:
  455. ASSERT(FALSE); // unknown formatting option
  456. }
  457. }
  458. // adjust nMaxLen for output nItemLen
  459. nMaxLen += nItemLen;
  460. }
  461. GetBuffer(nMaxLen);
  462. VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
  463. ReleaseBuffer();
  464. va_end(argListSave);
  465. }
  466. // formatting (using wsprintf style formatting)
  467. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  468. {
  469. ASSERT(AfxIsValidString(lpszFormat));
  470. va_list argList;
  471. va_start(argList, lpszFormat);
  472. FormatV(lpszFormat, argList);
  473. va_end(argList);
  474. }
  475. void AFX_CDECL CString::Format(UINT nFormatID, ...)
  476. {
  477. CString strFormat;
  478. VERIFY(strFormat.LoadString(nFormatID) != 0);
  479. va_list argList;
  480. va_start(argList, nFormatID);
  481. FormatV(strFormat, argList);
  482. va_end(argList);
  483. }
  484. void CString::TrimRight(LPCTSTR lpszTargetList)
  485. {
  486. // find beginning of trailing matches
  487. // by starting at beginning (DBCS aware)
  488. CopyBeforeWrite();
  489. LPTSTR lpsz = m_pchData;
  490. LPTSTR lpszLast = NULL;
  491. while (*lpsz != '\0')
  492. {
  493. if (_tcschr(lpszTargetList, *lpsz) != NULL)
  494. {
  495. if (lpszLast == NULL)
  496. lpszLast = lpsz;
  497. }
  498. else
  499. lpszLast = NULL;
  500. lpsz = _tcsinc(lpsz);
  501. }
  502. if (lpszLast != NULL)
  503. {
  504. // truncate at left-most matching character
  505. *lpszLast = '\0';
  506. GetData()->nDataLength = lpszLast - m_pchData;
  507. }
  508. }
  509. void CString::TrimRight(TCHAR chTarget)
  510. {
  511. // find beginning of trailing matches
  512. // by starting at beginning (DBCS aware)
  513. CopyBeforeWrite();
  514. LPTSTR lpsz = m_pchData;
  515. LPTSTR lpszLast = NULL;
  516. while (*lpsz != '\0')
  517. {
  518. if (*lpsz == chTarget)
  519. {
  520. if (lpszLast == NULL)
  521. lpszLast = lpsz;
  522. }
  523. else
  524. lpszLast = NULL;
  525. lpsz = _tcsinc(lpsz);
  526. }
  527. if (lpszLast != NULL)
  528. {
  529. // truncate at left-most matching character
  530. *lpszLast = '\0';
  531. GetData()->nDataLength = lpszLast - m_pchData;
  532. }
  533. }
  534. void CString::TrimLeft(LPCTSTR lpszTargets)
  535. {
  536. // if we're not trimming anything, we're not doing any work
  537. if (SafeStrlen(lpszTargets) == 0)
  538. return;
  539. CopyBeforeWrite();
  540. LPCTSTR lpsz = m_pchData;
  541. while (*lpsz != '\0')
  542. {
  543. if (_tcschr(lpszTargets, *lpsz) == NULL)
  544. break;
  545. lpsz = _tcsinc(lpsz);
  546. }
  547. if (lpsz != m_pchData)
  548. {
  549. // fix up data and length
  550. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  551. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  552. GetData()->nDataLength = nDataLength;
  553. }
  554. }
  555. void CString::TrimLeft(TCHAR chTarget)
  556. {
  557. // find first non-matching character
  558. CopyBeforeWrite();
  559. LPCTSTR lpsz = m_pchData;
  560. while (chTarget == *lpsz)
  561. lpsz = _tcsinc(lpsz);
  562. if (lpsz != m_pchData)
  563. {
  564. // fix up data and length
  565. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  566. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  567. GetData()->nDataLength = nDataLength;
  568. }
  569. }
  570. ///////////////////////////////////////////////////////////////////////////////