home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / STRCORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  15.1 KB  |  600 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE1_SEG
  14. #pragma code_seg(AFX_CORE1_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // static class data, special inlines
  26.  
  27. // afxChNil is left for backward compatibility
  28. AFX_DATADEF TCHAR afxChNil = '\0';
  29.  
  30. // For an empty string, m_pchData will point here
  31. // (note: avoids special case of checking for NULL m_pchData)
  32. // empty string data (and locked)
  33. static int rgInitData[] = { -1, 0, 0, 0 };
  34. static AFX_DATADEF CStringData* afxDataNil = (CStringData*)&rgInitData;
  35. static LPCTSTR afxPchNil = (LPCTSTR)(((BYTE*)&rgInitData)+sizeof(CStringData));
  36. // special function to make afxEmptyString work even during initialization
  37. const CString& AFXAPI AfxGetEmptyString()
  38.     { return *(CString*)&afxPchNil; }
  39.  
  40. //////////////////////////////////////////////////////////////////////////////
  41. // Construction/Destruction
  42.  
  43. CString::CString()
  44. {
  45.     Init();
  46. }
  47.  
  48. CString::CString(const CString& stringSrc)
  49. {
  50.     ASSERT(stringSrc.GetData()->nRefs != 0);
  51.     if (stringSrc.GetData()->nRefs >= 0)
  52.     {
  53.         ASSERT(stringSrc.GetData() != afxDataNil);
  54.         m_pchData = stringSrc.m_pchData;
  55.         InterlockedIncrement(&GetData()->nRefs);
  56.     }
  57.     else
  58.     {
  59.         Init();
  60.         *this = stringSrc.m_pchData;
  61.     }
  62. }
  63.  
  64. void CString::AllocBuffer(int nLen)
  65. // always allocate one extra character for '\0' termination
  66. // assumes [optimistically] that data length will equal allocation length
  67. {
  68.     ASSERT(nLen >= 0);
  69.     ASSERT(nLen <= INT_MAX-1);    // max size (enough room for 1 extra)
  70.  
  71.     if (nLen == 0)
  72.         Init();
  73.     else
  74.     {
  75.         CStringData* pData =
  76.             (CStringData*)new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
  77.         pData->nRefs = 1;
  78.         pData->data()[nLen] = '\0';
  79.         pData->nDataLength = nLen;
  80.         pData->nAllocLength = nLen;
  81.         m_pchData = pData->data();
  82.     }
  83. }
  84.  
  85. void CString::Release()
  86. {
  87.     if (GetData() != afxDataNil)
  88.     {
  89.         ASSERT(GetData()->nRefs != 0);
  90.         if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  91.             delete[] (BYTE*)GetData();
  92.         Init();
  93.     }
  94. }
  95.  
  96. void PASCAL CString::Release(CStringData* pData)
  97. {
  98.     if (pData != afxDataNil)
  99.     {
  100.         ASSERT(pData->nRefs != 0);
  101.         if (InterlockedDecrement(&pData->nRefs) <= 0)
  102.             delete[] (BYTE*)pData;
  103.     }
  104. }
  105.  
  106. void CString::Empty()
  107. {
  108.     if (GetData()->nDataLength == 0)
  109.         return;
  110.     if (GetData()->nRefs >= 0)
  111.         Release();
  112.     else
  113.         *this = &afxChNil;
  114.     ASSERT(GetData()->nDataLength == 0);
  115.     ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  116. }
  117.  
  118. void CString::CopyBeforeWrite()
  119. {
  120.     if (GetData()->nRefs > 1)
  121.     {
  122.         CStringData* pData = GetData();
  123.         Release();
  124.         AllocBuffer(pData->nDataLength);
  125.         memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  126.     }
  127.     ASSERT(GetData()->nRefs <= 1);
  128. }
  129.  
  130. void CString::AllocBeforeWrite(int nLen)
  131. {
  132.     if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  133.     {
  134.         Release();
  135.         AllocBuffer(nLen);
  136.     }
  137.     ASSERT(GetData()->nRefs <= 1);
  138. }
  139.  
  140. CString::~CString()
  141. //  free any attached data
  142. {
  143.     if (GetData() != afxDataNil)
  144.     {
  145.         if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  146.             delete[] (BYTE*)GetData();
  147.     }
  148. }
  149.  
  150. //////////////////////////////////////////////////////////////////////////////
  151. // Helpers for the rest of the implementation
  152.  
  153. void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  154.      int nExtraLen) const
  155. {
  156.     // will clone the data attached to this string
  157.     // allocating 'nExtraLen' characters
  158.     // Places results in uninitialized string 'dest'
  159.     // Will copy the part or all of original data to start of new string
  160.  
  161.     int nNewLen = nCopyLen + nExtraLen;
  162.     if (nNewLen == 0)
  163.     {
  164.         dest.Init();
  165.     }
  166.     else
  167.     {
  168.         dest.AllocBuffer(nNewLen);
  169.         memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  170.     }
  171. }
  172.  
  173. //////////////////////////////////////////////////////////////////////////////
  174. // More sophisticated construction
  175.  
  176. CString::CString(LPCTSTR lpsz)
  177. {
  178.     Init();
  179.     if (lpsz != NULL && HIWORD(lpsz) == NULL)
  180.     {
  181.         UINT nID = LOWORD((DWORD)lpsz);
  182.         if (!LoadString(nID))
  183.             TRACE1("Warning: implicit LoadString(%u) failed\n", nID);
  184.     }
  185.     else
  186.     {
  187.         int nLen = SafeStrlen(lpsz);
  188.         if (nLen != 0)
  189.         {
  190.             AllocBuffer(nLen);
  191.             memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  192.         }
  193.     }
  194. }
  195.  
  196. /////////////////////////////////////////////////////////////////////////////
  197. // Special conversion constructors
  198.  
  199. #ifdef _UNICODE
  200. CString::CString(LPCSTR lpsz)
  201. {
  202.     Init();
  203.     int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  204.     if (nSrcLen != 0)
  205.     {
  206.         AllocBuffer(nSrcLen);
  207.         _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  208.         ReleaseBuffer();
  209.     }
  210. }
  211. #else //_UNICODE
  212. CString::CString(LPCWSTR lpsz)
  213. {
  214.     Init();
  215.     int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  216.     if (nSrcLen != 0)
  217.     {
  218.         AllocBuffer(nSrcLen*2);
  219.         _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  220.         ReleaseBuffer();
  221.     }
  222. }
  223. #endif //!_UNICODE
  224.  
  225. //////////////////////////////////////////////////////////////////////////////
  226. // Diagnostic support
  227.  
  228. #ifdef _DEBUG
  229. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString& string)
  230. {
  231.     dc << string.m_pchData;
  232.     return dc;
  233. }
  234. #endif //_DEBUG
  235.  
  236. //////////////////////////////////////////////////////////////////////////////
  237. // Assignment operators
  238. //  All assign a new value to the string
  239. //      (a) first see if the buffer is big enough
  240. //      (b) if enough room, copy on top of old buffer, set size and type
  241. //      (c) otherwise free old string data, and create a new one
  242. //
  243. //  All routines return the new string (but as a 'const CString&' so that
  244. //      assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  245. //
  246.  
  247. void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  248. {
  249.     AllocBeforeWrite(nSrcLen);
  250.     memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  251.     GetData()->nDataLength = nSrcLen;
  252.     m_pchData[nSrcLen] = '\0';
  253. }
  254.  
  255. const CString& CString::operator=(const CString& stringSrc)
  256. {
  257.     if (m_pchData != stringSrc.m_pchData)
  258.     {
  259.         if ((GetData()->nRefs < 0 && GetData() != afxDataNil) ||
  260.             stringSrc.GetData()->nRefs < 0)
  261.         {
  262.             // actual copy necessary since one of the strings is locked
  263.             AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  264.         }
  265.         else
  266.         {
  267.             // can just copy references around
  268.             Release();
  269.             ASSERT(stringSrc.GetData() != afxDataNil);
  270.             m_pchData = stringSrc.m_pchData;
  271.             InterlockedIncrement(&GetData()->nRefs);
  272.         }
  273.     }
  274.     return *this;
  275. }
  276.  
  277. const CString& CString::operator=(LPCTSTR lpsz)
  278. {
  279.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  280.     AssignCopy(SafeStrlen(lpsz), lpsz);
  281.     return *this;
  282. }
  283.  
  284. /////////////////////////////////////////////////////////////////////////////
  285. // Special conversion assignment
  286.  
  287. #ifdef _UNICODE
  288. const CString& CString::operator=(LPCSTR lpsz)
  289. {
  290.     int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  291.     AllocBeforeWrite(nSrcLen);
  292.     _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  293.     ReleaseBuffer();
  294.     return *this;
  295. }
  296. #else //!_UNICODE
  297. const CString& CString::operator=(LPCWSTR lpsz)
  298. {
  299.     int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  300.     AllocBeforeWrite(nSrcLen*2);
  301.     _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  302.     ReleaseBuffer();
  303.     return *this;
  304. }
  305. #endif  //!_UNICODE
  306.  
  307. //////////////////////////////////////////////////////////////////////////////
  308. // concatenation
  309.  
  310. // NOTE: "operator+" is done as friend functions for simplicity
  311. //      There are three variants:
  312. //          CString + CString
  313. // and for ? = TCHAR, LPCTSTR
  314. //          CString + ?
  315. //          ? + CString
  316.  
  317. void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  318.     int nSrc2Len, LPCTSTR lpszSrc2Data)
  319. {
  320.   // -- master concatenation routine
  321.   // Concatenate two sources
  322.   // -- assume that 'this' is a new CString object
  323.  
  324.     int nNewLen = nSrc1Len + nSrc2Len;
  325.     if (nNewLen != 0)
  326.     {
  327.         AllocBuffer(nNewLen);
  328.         memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  329.         memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  330.     }
  331. }
  332.  
  333. CString AFXAPI operator+(const CString& string1, const CString& string2)
  334. {
  335.     CString s;
  336.     s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  337.         string2.GetData()->nDataLength, string2.m_pchData);
  338.     return s;
  339. }
  340.  
  341. CString AFXAPI operator+(const CString& string, LPCTSTR lpsz)
  342. {
  343.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  344.     CString s;
  345.     s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  346.         CString::SafeStrlen(lpsz), lpsz);
  347.     return s;
  348. }
  349.  
  350. CString AFXAPI operator+(LPCTSTR lpsz, const CString& string)
  351. {
  352.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  353.     CString s;
  354.     s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  355.         string.m_pchData);
  356.     return s;
  357. }
  358.  
  359. //////////////////////////////////////////////////////////////////////////////
  360. // concatenate in place
  361.  
  362. void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  363. {
  364.     //  -- the main routine for += operators
  365.  
  366.     // concatenating an empty string is a no-op!
  367.     if (nSrcLen == 0)
  368.         return;
  369.  
  370.     // if the buffer is too small, or we have a width mis-match, just
  371.     //   allocate a new buffer (slow but sure)
  372.     if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  373.     {
  374.         // we have to grow the buffer, use the ConcatCopy routine
  375.         CStringData* pOldData = GetData();
  376.         ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  377.         ASSERT(pOldData != NULL);
  378.         CString::Release(pOldData);
  379.     }
  380.     else
  381.     {
  382.         // fast concatenation when buffer big enough
  383.         memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  384.         GetData()->nDataLength += nSrcLen;
  385.         ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  386.         m_pchData[GetData()->nDataLength] = '\0';
  387.     }
  388. }
  389.  
  390. const CString& CString::operator+=(LPCTSTR lpsz)
  391. {
  392.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  393.     ConcatInPlace(SafeStrlen(lpsz), lpsz);
  394.     return *this;
  395. }
  396.  
  397. const CString& CString::operator+=(TCHAR ch)
  398. {
  399.     ConcatInPlace(1, &ch);
  400.     return *this;
  401. }
  402.  
  403. const CString& CString::operator+=(const CString& string)
  404. {
  405.     ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  406.     return *this;
  407. }
  408.  
  409. ///////////////////////////////////////////////////////////////////////////////
  410. // Advanced direct buffer access
  411.  
  412. LPTSTR CString::GetBuffer(int nMinBufLength)
  413. {
  414.     ASSERT(nMinBufLength >= 0);
  415.  
  416.     if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  417.     {
  418.         // we have to grow the buffer
  419.         CStringData* pOldData = GetData();
  420.         int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
  421.         if (nMinBufLength < nOldLen)
  422.             nMinBufLength = nOldLen;
  423.         AllocBuffer(nMinBufLength);
  424.         memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  425.         GetData()->nDataLength = nOldLen;
  426.         CString::Release(pOldData);
  427.     }
  428.     ASSERT(GetData()->nRefs <= 1);
  429.  
  430.     // return a pointer to the character storage for this string
  431.     ASSERT(m_pchData != NULL);
  432.     return m_pchData;
  433. }
  434.  
  435. void CString::ReleaseBuffer(int nNewLength)
  436. {
  437.     CopyBeforeWrite();  // just in case GetBuffer was not called
  438.  
  439.     if (nNewLength == -1)
  440.         nNewLength = lstrlen(m_pchData); // zero terminated
  441.  
  442.     ASSERT(nNewLength <= GetData()->nAllocLength);
  443.     GetData()->nDataLength = nNewLength;
  444.     m_pchData[nNewLength] = '\0';
  445. }
  446.  
  447. LPTSTR CString::GetBufferSetLength(int nNewLength)
  448. {
  449.     ASSERT(nNewLength >= 0);
  450.  
  451.     GetBuffer(nNewLength);
  452.     GetData()->nDataLength = nNewLength;
  453.     m_pchData[nNewLength] = '\0';
  454.     return m_pchData;
  455. }
  456.  
  457. void CString::FreeExtra()
  458. {
  459.     ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  460.     if (GetData()->nDataLength != GetData()->nAllocLength)
  461.     {
  462.         CStringData* pOldData = GetData();
  463.         AllocBuffer(GetData()->nDataLength);
  464.         memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  465.         ASSERT(m_pchData[GetData()->nDataLength] == '\0');
  466.         CString::Release(pOldData);
  467.     }
  468.     ASSERT(GetData() != NULL);
  469. }
  470.  
  471. LPTSTR CString::LockBuffer()
  472. {
  473.     LPTSTR lpsz = GetBuffer(0);
  474.     GetData()->nRefs = -1;
  475.     return lpsz;
  476. }
  477.  
  478. void CString::UnlockBuffer()
  479. {
  480.     ASSERT(GetData()->nRefs == -1);
  481.     if (GetData() != afxDataNil)
  482.         GetData()->nRefs = 1;
  483. }
  484.  
  485. ///////////////////////////////////////////////////////////////////////////////
  486. // Commonly used routines (rarely used routines in STREX.CPP)
  487.  
  488. int CString::Find(TCHAR ch) const
  489. {
  490.     // find first single character
  491.     LPTSTR lpsz = _tcschr(m_pchData, (_TUCHAR)ch);
  492.  
  493.     // return -1 if not found and index otherwise
  494.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  495. }
  496.  
  497. int CString::FindOneOf(LPCTSTR lpszCharSet) const
  498. {
  499.     ASSERT(AfxIsValidString(lpszCharSet, FALSE));
  500.     LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  501.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  502. }
  503.  
  504. void CString::MakeUpper()
  505. {
  506.     CopyBeforeWrite();
  507.     _tcsupr(m_pchData);
  508. }
  509.  
  510. void CString::MakeLower()
  511. {
  512.     CopyBeforeWrite();
  513.     _tcslwr(m_pchData);
  514. }
  515.  
  516. void CString::MakeReverse()
  517. {
  518.     CopyBeforeWrite();
  519.     _tcsrev(m_pchData);
  520. }
  521.  
  522. void CString::SetAt(int nIndex, TCHAR ch)
  523. {
  524.     ASSERT(nIndex >= 0);
  525.     ASSERT(nIndex < GetData()->nDataLength);
  526.  
  527.     CopyBeforeWrite();
  528.     m_pchData[nIndex] = ch;
  529. }
  530.  
  531. #ifndef _UNICODE
  532. void CString::AnsiToOem()
  533. {
  534.     CopyBeforeWrite();
  535.     ::AnsiToOem(m_pchData, m_pchData);
  536. }
  537. void CString::OemToAnsi()
  538. {
  539.     CopyBeforeWrite();
  540.     ::OemToAnsi(m_pchData, m_pchData);
  541. }
  542. #endif
  543.  
  544. ///////////////////////////////////////////////////////////////////////////////
  545. // CString conversion helpers (these use the current system locale)
  546.  
  547. int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  548. {
  549.     if (count == 0 && mbstr != NULL)
  550.         return 0;
  551.  
  552.     int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  553.         mbstr, count, NULL, NULL);
  554.     ASSERT(mbstr == NULL || result <= (int)count);
  555.     if (result > 0)
  556.         mbstr[result-1] = 0;
  557.     return result;
  558. }
  559.  
  560. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  561. {
  562.     if (count == 0 && wcstr != NULL)
  563.         return 0;
  564.  
  565.     int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  566.         wcstr, count);
  567.     ASSERT(wcstr == NULL || result <= (int)count);
  568.     if (result > 0)
  569.         wcstr[result-1] = 0;
  570.     return result;
  571. }
  572.  
  573. LPWSTR AFXAPI AfxA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
  574. {
  575.     if (lpa == NULL)
  576.         return NULL;
  577.     ASSERT(lpw != NULL);
  578.     // verify that no illegal character present
  579.     // since lpw was allocated based on the size of lpa
  580.     // don't worry about the number of chars
  581.     lpw[0] = '\0';
  582.     VERIFY(MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars));
  583.     return lpw;
  584. }
  585.  
  586. LPSTR AFXAPI AfxW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
  587. {
  588.     if (lpw == NULL)
  589.         return NULL;
  590.     ASSERT(lpa != NULL);
  591.     // verify that no illegal character present
  592.     // since lpa was allocated based on the size of lpw
  593.     // don't worry about the number of chars
  594.     lpa[0] = '\0';
  595.     VERIFY(WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL));
  596.     return lpa;
  597. }
  598.  
  599. ///////////////////////////////////////////////////////////////////////////////
  600.