CString的源代码

#ifdef   _AFXDLL  
  CString::CString()  
  {  
  Init();  
  }  
  #endif  
   
  CString::CString(const   CString&   stringSrc)  
  {  
  ASSERT(stringSrc.GetData()->nRefs   !=   0);  
  if   (stringSrc.GetData()->nRefs   >=   0)  
  {  
  ASSERT(stringSrc.GetData()   !=   _afxDataNil);  
  m_pchData   =   stringSrc.m_pchData;  
  InterlockedIncrement(&GetData()->nRefs);  
  }  
  else  
  {  
  Init();  
  *this   =   stringSrc.m_pchData;  
  }  
  }  
   
  #ifndef   _DEBUG  
   
  #pragma   warning(disable:   4074)  
  #pragma   init_seg(compiler)  
   
  #define   ROUND(x,y)   (((x)+(y-1))&~(y-1))  
  #define   ROUND4(x)   ROUND(x,   4)  
  AFX_STATIC   CFixedAlloc   _afxAlloc64(ROUND4(65*sizeof(TCHAR)+sizeof(CStringData)));  
  AFX_STATIC   CFixedAlloc   _afxAlloc128(ROUND4(129*sizeof(TCHAR)+sizeof(CStringData)));  
  AFX_STATIC   CFixedAlloc   _afxAlloc256(ROUND4(257*sizeof(TCHAR)+sizeof(CStringData)));  
  AFX_STATIC   CFixedAlloc   _afxAlloc512(ROUND4(513*sizeof(TCHAR)+sizeof(CStringData)));  
   
  #endif   //!_DEBUG  
   
  void   CString::AllocBuffer(int   nLen)  
  //   always   allocate   one   extra   character   for   '/0'   termination  
  //   assumes   [optimistically]   that   data   length   will   equal   allocation   length  
  {  
  ASSERT(nLen   >=   0);  
  ASSERT(nLen   <=   INT_MAX-1);         //   max   size   (enough   room   for   1   extra)  
   
  if   (nLen   ==   0)  
  Init();  
  else  
  {  
  CStringData*   pData;  
  #ifndef   _DEBUG  
  if   (nLen   <=   64)  
  {  
  pData   =   (CStringData*)_afxAlloc64.Alloc();  
  pData->nAllocLength   =   64;  
  }  
  else   if   (nLen   <=   128)  
  {  
  pData   =   (CStringData*)_afxAlloc128.Alloc();  
  pData->nAllocLength   =   128;  
  }  
  else   if   (nLen   <=   256)  
  {  
  pData   =   (CStringData*)_afxAlloc256.Alloc();  
  pData->nAllocLength   =   256;  
  }  
  else   if   (nLen   <=   512)  
  {  
  pData   =   (CStringData*)_afxAlloc512.Alloc();  
  pData->nAllocLength   =   512;  
  }  
  else  
  #endif  
  {  
  pData   =   (CStringData*)  
  new   BYTE[sizeof(CStringData)   +   (nLen+1)*sizeof(TCHAR)];  
  pData->nAllocLength   =   nLen;  
  }  
  pData->nRefs   =   1;  
  pData->data()[nLen]   =   '/0';  
  pData->nDataLength   =   nLen;  
  m_pchData   =   pData->data();  
  }  
  }  
   
  void   FASTCALL   CString::FreeData(CStringData*   pData)  
  {  
  #ifndef   _DEBUG  
  int   nLen   =   pData->nAllocLength;  
  if   (nLen   ==   64)  
  _afxAlloc64.Free(pData);  
  else   if   (nLen   ==   128)  
  _afxAlloc128.Free(pData);  
  else   if   (nLen   ==   256)  
  _afxAlloc256.Free(pData);  
  else     if   (nLen   ==   512)  
  _afxAlloc512.Free(pData);  
  else  
  {  
  ASSERT(nLen   >   512);  
  delete[]   (BYTE*)pData;  
  }  
  #else  
  delete[]   (BYTE*)pData;  
  #endif  
  }  
   
  void   CString::Release()  
  {  
  if   (GetData()   !=   _afxDataNil)  
  {  
  ASSERT(GetData()->nRefs   !=   0);  
  if   (InterlockedDecrement(&GetData()->nRefs)   <=   0)  
  FreeData(GetData());  
  Init();  
  }  
  }  
   
  void   PASCAL   CString::Release(CStringData*   pData)  
  {  
  if   (pData   !=   _afxDataNil)  
  {  
  ASSERT(pData->nRefs   !=   0);  
  if   (InterlockedDecrement(&pData->nRefs)   <=   0)  
  FreeData(pData);  
  }  
  }  
   
  void   CString::Empty()  
  {  
  if   (GetData()->nDataLength   ==   0)  
  return;  
  if   (GetData()->nRefs   >=   0)  
  Release();  
  else  
  *this   =   &afxChNil;  
  ASSERT(GetData()->nDataLength   ==   0);  
  ASSERT(GetData()->nRefs   <   0   ||   GetData()->nAllocLength   ==   0);  
  }  
   
  void   CString::CopyBeforeWrite()  
  {  
  if   (GetData()->nRefs   >   1)  
  {  
  CStringData*   pData   =   GetData();  
  Release();  
  AllocBuffer(pData->nDataLength);  
  memcpy(m_pchData,   pData->data(),   (pData->nDataLength+1)*sizeof(TCHAR));  
  }  
  ASSERT(GetData()->nRefs   <=   1);  
  }  
   
  void   CString::AllocBeforeWrite(int   nLen)  
  {  
  if   (GetData()->nRefs   >   1   ||   nLen   >   GetData()->nAllocLength)  
  {  
  Release();  
  AllocBuffer(nLen);  
  }  
  ASSERT(GetData()->nRefs   <=   1);  
  }  
   
  CString::~CString()  
  //     free   any   attached   data  
  {  
  if   (GetData()   !=   _afxDataNil)  
  {  
  if   (InterlockedDecrement(&GetData()->nRefs)   <=   0)  
  FreeData(GetData());  
  }  
  }  
   
  //  
  //   Helpers   for   the   rest   of   the   implementation  
   
  void   CString::AllocCopy(CString&   dest,   int   nCopyLen,   int   nCopyIndex,  
    int   nExtraLen)   const  
  {  
  //   will   clone   the   data   attached   to   this   string  
  //   allocating   'nExtraLen'   characters  
  //   Places   results   in   uninitialized   string   'dest'  
  //   Will   copy   the   part   or   all   of   original   data   to   start   of   new   string  
   
  int   nNewLen   =   nCopyLen   +   nExtraLen;  
  if   (nNewLen   ==   0)  
  {  
  dest.Init();  
  }  
  else  
  {  
  dest.AllocBuffer(nNewLen);  
  memcpy(dest.m_pchData,   m_pchData+nCopyIndex,   nCopyLen*sizeof(TCHAR));  
  }  
  }  
   
  //  
  //   More   sophisticated   construction  
   
  CString::CString(LPCTSTR   lpsz)  
  {  
  Init();  
  if   (lpsz   !=   NULL   &&   HIWORD(lpsz)   ==   NULL)  
  {  
  UINT   nID   =   LOWORD((DWORD)lpsz);  
  if   (!LoadString(nID))  
  TRACE1("Warning:   implicit   LoadString(%u)   failed/n",   nID);  
  }  
  else  
  {  
  int   nLen   =   SafeStrlen(lpsz);  
  if   (nLen   !=   0)  
  {  
  AllocBuffer(nLen);  
  memcpy(m_pchData,   lpsz,   nLen*sizeof(TCHAR));  
  }  
  }  
  }  
   
  /  
  //   Special   conversion   constructors  
   
  #ifdef   _UNICODE  
  CString::CString(LPCSTR   lpsz)  
  {  
  Init();  
  int   nSrcLen   =   lpsz   !=   NULL   ?   lstrlenA(lpsz)   :   0;  
  if   (nSrcLen   !=   0)  
  {  
  AllocBuffer(nSrcLen);  
  _mbstowcsz(m_pchData,   lpsz,   nSrcLen+1);  
  ReleaseBuffer();  
  }  
  }  
  #else   //_UNICODE  
  CString::CString(LPCWSTR   lpsz)  
  {  
  Init();  
  int   nSrcLen   =   lpsz   !=   NULL   ?   wcslen(lpsz)   :   0;  
  if   (nSrcLen   !=   0)  
  {  
  AllocBuffer(nSrcLen*2);  
  _wcstombsz(m_pchData,   lpsz,   (nSrcLen*2)+1);  
  ReleaseBuffer();  
  }  
  }  
  #endif   //!_UNICODE  
   
  //  
  //   Diagnostic   support  
   
  #ifdef   _DEBUG  
  CDumpContext&   AFXAPI   operator<<(CDumpContext&   dc,   const   CString&   string)  
  {  
  dc   <<   string.m_pchData;  
  return   dc;  
  }  
  #endif   //_DEBUG  
   
  //  
  //   Assignment   operators  
  //     All   assign   a   new   value   to   the   string  
  //             (a)   first   see   if   the   buffer   is   big   enough  
  //             (b)   if   enough   room,   copy   on   top   of   old   buffer,   set   size   and   type  
  //             (c)   otherwise   free   old   string   data,   and   create   a   new   one  
  //  
  //     All   routines   return   the   new   string   (but   as   a   'const   CString&'   so   that  
  //             assigning   it   again   will   cause   a   copy,   eg:   s1   =   s2   =   "hi   there".  
  //  
   
  void   CString::AssignCopy(int   nSrcLen,   LPCTSTR   lpszSrcData)  
  {  
  AllocBeforeWrite(nSrcLen);  
  memcpy(m_pchData,   lpszSrcData,   nSrcLen*sizeof(TCHAR));  
  GetData()->nDataLength   =   nSrcLen;  
  m_pchData[nSrcLen]   =   '/0';  
  }  
   
  const   CString&   CString::operator=(const   CString&   stringSrc)  
  {  
  if   (m_pchData   !=   stringSrc.m_pchData)  
  {  
  if   ((GetData()->nRefs   <   0   &&   GetData()   !=   _afxDataNil)   ||  
  stringSrc.GetData()->nRefs   <   0)  
  {  
  //   actual   copy   necessary   since   one   of   the   strings   is   locked  
  AssignCopy(stringSrc.GetData()->nDataLength,   stringSrc.m_pchData);  
  }  
  else  
  {  
  //   can   just   copy   references   around  
  Release();  
  ASSERT(stringSrc.GetData()   !=   _afxDataNil);  
  m_pchData   =   stringSrc.m_pchData;  
  InterlockedIncrement(&GetData()->nRefs);  
  }  
  }  
  return   *this;  
  }  
   
  const   CString&   CString::operator=(LPCTSTR   lpsz)  
  {  
  ASSERT(lpsz   ==   NULL   ||   AfxIsValidString(lpsz));  
  AssignCopy(SafeStrlen(lpsz),   lpsz);  
  return   *this;  
  }  
   
  /  
  //   Special   conversion   assignment  
   
  #ifdef   _UNICODE  
  const   CString&   CString::operator=(LPCSTR   lpsz)  
  {  
  int   nSrcLen   =   lpsz   !=   NULL   ?   lstrlenA(lpsz)   :   0;  
  AllocBeforeWrite(nSrcLen);  
  _mbstowcsz(m_pchData,   lpsz,   nSrcLen+1);  
  ReleaseBuffer();  
  return   *this;  
  }  
  #else   //!_UNICODE  
  const   CString&   CString::operator=(LPCWSTR   lpsz)  
  {  
  int   nSrcLen   =   lpsz   !=   NULL   ?   wcslen(lpsz)   :   0;  
  AllocBeforeWrite(nSrcLen*2);  
  _wcstombsz(m_pchData,   lpsz,   (nSrcLen*2)+1);  
  ReleaseBuffer();  
  return   *this;  
  }  
  #endif     //!_UNICODE  
   
  //  
  //   concatenation  
   
  //   NOTE:   "operator+"   is   done   as   friend   functions   for   simplicity  
  //             There   are   three   variants:  
  //                     CString   +   CString  
  //   and   for   ?   =   TCHAR,   LPCTSTR  
  //                     CString   +   ?  
  //                     ?   +   CString  
   
  void   CString::ConcatCopy(int   nSrc1Len,   LPCTSTR   lpszSrc1Data,  
  int   nSrc2Len,   LPCTSTR   lpszSrc2Data)  
  {  
      //   --   master   concatenation   routine  
      //   Concatenate   two   sources  
      //   --   assume   that   'this'   is   a   new   CString   object  
   
  int   nNewLen   =   nSrc1Len   +   nSrc2Len;  
  if   (nNewLen   !=   0)  
  {  
  AllocBuffer(nNewLen);  
  memcpy(m_pchData,   lpszSrc1Data,   nSrc1Len*sizeof(TCHAR));  
  memcpy(m_pchData+nSrc1Len,   lpszSrc2Data,   nSrc2Len*sizeof(TCHAR));  
  }  
  }  
   
  CString   AFXAPI   operator+(const   CString&   string1,   const   CString&   string2)  
  {  
  CString   s;  
  s.ConcatCopy(string1.GetData()->nDataLength,   string1.m_pchData,  
  string2.GetData()->nDataLength,   string2.m_pchData);  
  return   s;  
  }  
   
  CString   AFXAPI   operator+(const   CString&   string,   LPCTSTR   lpsz)  
  {  
  ASSERT(lpsz   ==   NULL   ||   AfxIsValidString(lpsz));  
  CString   s;  
  s.ConcatCopy(string.GetData()->nDataLength,   string.m_pchData,  
  CString::SafeStrlen(lpsz),   lpsz);  
  return   s;  
  }  
   
  CString   AFXAPI   operator+(LPCTSTR   lpsz,   const   CString&   string)  
  {  
  ASSERT(lpsz   ==   NULL   ||   AfxIsValidString(lpsz));  
  CString   s;  
  s.ConcatCopy(CString::SafeStrlen(lpsz),   lpsz,   string.GetData()->nDataLength,  
  string.m_pchData);  
  return   s;  
  }  
   
  //  
  //   concatenate   in   place  
   
  void   CString::ConcatInPlace(int   nSrcLen,   LPCTSTR   lpszSrcData)  
  {  
  //     --   the   main   routine   for   +=   operators  
   
  //   concatenating   an   empty   string   is   a   no-op!  
  if   (nSrcLen   ==   0)  
  return;  
   
  //   if   the   buffer   is   too   small,   or   we   have   a   width   mis-match,   just  
  //       allocate   a   new   buffer   (slow   but   sure)  
  if   (GetData()->nRefs   >   1   ||   GetData()->nDataLength   +   nSrcLen   >   GetData()->nAllocLength)  
  {  
  //   we   have   to   grow   the   buffer,   use   the   ConcatCopy   routine  
  CStringData*   pOldData   =   GetData();  
  ConcatCopy(GetData()->nDataLength,   m_pchData,   nSrcLen,   lpszSrcData);  
  ASSERT(pOldData   !=   NULL);  
  CString::Release(pOldData);  
  }  
  else  
  {  
  //   fast   concatenation   when   buffer   big   enough  
  memcpy(m_pchData+GetData()->nDataLength,   lpszSrcData,   nSrcLen*sizeof(TCHAR));  
  GetData()->nDataLength   +=   nSrcLen;  
  ASSERT(GetData()->nDataLength   <=   GetData()->nAllocLength);  
  m_pchData[GetData()->nDataLength]   =   '/0';  
  }  
  }  
   
  const   CString&   CString::operator+=(LPCTSTR   lpsz)  
  {  
  ASSERT(lpsz   ==   NULL   ||   AfxIsValidString(lpsz));  
  ConcatInPlace(SafeStrlen(lpsz),   lpsz);  
  return   *this;  
  }  
   
  const   CString&   CString::operator+=(TCHAR   ch)  
  {  
  ConcatInPlace(1,   &ch);  
  return   *this;  
  }  
   
  const   CString&   CString::operator+=(const   CString&   string)  
  {  
  ConcatInPlace(string.GetData()->nDataLength,   string.m_pchData);  
  return   *this;  
  }  
   
  ///  
  //   Advanced   direct   buffer   access  
   
  LPTSTR   CString::GetBuffer(int   nMinBufLength)  
  {  
  ASSERT(nMinBufLength   >=   0);  
   
  if   (GetData()->nRefs   >   1   ||   nMinBufLength   >   GetData()->nAllocLength)  
  {  
  #ifdef   _DEBUG  
  //   give   a   warning   in   case   locked   string   becomes   unlocked  
  if   (GetData()   !=   _afxDataNil   &&   GetData()->nRefs   <   0)  
  TRACE0("Warning:   GetBuffer   on   locked   CString   creates   unlocked   CString!/n");  
  #endif  
  //   we   have   to   grow   the   buffer  
  CStringData*   pOldData   =   GetData();  
  int   nOldLen   =   GetData()->nDataLength;       //   AllocBuffer   will   tromp   it  
  if   (nMinBufLength   <   nOldLen)  
  nMinBufLength   =   nOldLen;  
  AllocBuffer(nMinBufLength);  
  memcpy(m_pchData,   pOldData->data(),   (nOldLen+1)*sizeof(TCHAR));  
  GetData()->nDataLength   =   nOldLen;  
  CString::Release(pOldData);  
  }  
  ASSERT(GetData()->nRefs   <=   1);  
   
  //   return   a   pointer   to   the   character   storage   for   this   string  
  ASSERT(m_pchData   !=   NULL);  
  return   m_pchData;  
  }  
   
  void   CString::ReleaseBuffer(int   nNewLength)  
  {  
  CopyBeforeWrite();     //   just   in   case   GetBuffer   was   not   called  
   
  if   (nNewLength   ==   -1)  
  nNewLength   =   lstrlen(m_pchData);   //   zero   terminated  
   
  ASSERT(nNewLength   <=   GetData()->nAllocLength);  
  GetData()->nDataLength   =   nNewLength;  
  m_pchData[nNewLength]   =   '/0';  
  }  
   
  LPTSTR   CString::GetBufferSetLength(int   nNewLength)  
  {  
  ASSERT(nNewLength   >=   0);  
   
  GetBuffer(nNewLength);  
  GetData()->nDataLength   =   nNewLength;  
  m_pchData[nNewLength]   =   '/0';  
  return   m_pchData;  
  }  
   
  void   CString::FreeExtra()  
  {  
  ASSERT(GetData()->nDataLength   <=   GetData()->nAllocLength);  
  if   (GetData()->nDataLength   !=   GetData()->nAllocLength)  
  {  
  CStringData*   pOldData   =   GetData();  
  AllocBuffer(GetData()->nDataLength);  
  memcpy(m_pchData,   pOldData->data(),   pOldData->nDataLength*sizeof(TCHAR));  
  ASSERT(m_pchData[GetData()->nDataLength]   ==   '/0');  
  CString::Release(pOldData);  
  }  
  ASSERT(GetData()   !=   NULL);  
  }  
   
  LPTSTR   CString::LockBuffer()  
  {  
  LPTSTR   lpsz   =   GetBuffer(0);  
  GetData()->nRefs   =   -1;  
  return   lpsz;  
  }  
   
  void   CString::UnlockBuffer()  
  {  
  ASSERT(GetData()->nRefs   ==   -1);  
  if   (GetData()   !=   _afxDataNil)  
  GetData()->nRefs   =   1;  
  }  
   
  ///  
  //   Commonly   used   routines   (rarely   used   routines   in   STREX.CPP)  
   
  int   CString::Find(TCHAR   ch)   const  
  {  
  return   Find(ch,   0);  
  }  
   
  int   CString::Find(TCHAR   ch,   int   nStart)   const  
  {  
  int   nLength   =   GetData()->nDataLength;  
  if   (nStart   >=   nLength)  
  return   -1;  
   
  //   find   first   single   character  
  LPTSTR   lpsz   =   _tcschr(m_pchData   +   nStart,   (_TUCHAR)ch);  
   
  //   return   -1   if   not   found   and   index   otherwise  
  return   (lpsz   ==   NULL)   ?   -1   :   (int)(lpsz   -   m_pchData);  
  }  
   
  int   CString::FindOneOf(LPCTSTR   lpszCharSet)   const  
  {  
  ASSERT(AfxIsValidString(lpszCharSet));  
  LPTSTR   lpsz   =   _tcspbrk(m_pchData,   lpszCharSet);  
  return   (lpsz   ==   NULL)   ?   -1   :   (int)(lpsz   -   m_pchData);  
  }  
   
  void   CString::MakeUpper()  
  {  
  CopyBeforeWrite();  
  _tcsupr(m_pchData);  
  }  
   
  void   CString::MakeLower()  
  {  
  CopyBeforeWrite();  
  _tcslwr(m_pchData);  
  }  
   
  void   CString::MakeReverse()  
  {  
  CopyBeforeWrite();  
  _tcsrev(m_pchData);  
  }  
   
  void   CString::SetAt(int   nIndex,   TCHAR   ch)  
  {  
  ASSERT(nIndex   >=   0);  
  ASSERT(nIndex   <   GetData()->nDataLength);  
   
  CopyBeforeWrite();  
  m_pchData[nIndex]   =   ch;  
  }  
   
  #ifndef   _UNICODE  
  void   CString::AnsiToOem()  
  {  
  CopyBeforeWrite();  
  ::AnsiToOem(m_pchData,   m_pchData);  
  }  
  void   CString::OemToAnsi()  
  {  
  CopyBeforeWrite();  
  ::OemToAnsi(m_pchData,   m_pchData);  
  }  
  #endif  
   
  ///  
  //   CString   conversion   helpers   (these   use   the   current   system   locale)  
   
  int   AFX_CDECL   _wcstombsz(char*   mbstr,   const   wchar_t*   wcstr,   size_t   count)  
  {  
  if   (count   ==   0   &&   mbstr   !=   NULL)  
  return   0;  
   
  int   result   =   ::WideCharToMultiByte(CP_ACP,   0,   wcstr,   -1,  
  mbstr,   count,   NULL,   NULL);  
  ASSERT(mbstr   ==   NULL   ||   result   <=   (int)count);  
  if   (result   >   0)  
  mbstr[result-1]   =   0;  
  return   result;  
  }  
   
  int   AFX_CDECL   _mbstowcsz(wchar_t*   wcstr,   const   char*   mbstr,   size_t   count)  
  {  
  if   (count   ==   0   &&   wcstr   !=   NULL)  
  return   0;  
   
  int   result   =   ::MultiByteToWideChar(CP_ACP,   0,   mbstr,   -1,  
  wcstr,   count);  
  ASSERT(wcstr   ==   NULL   ||   result   <=   (int)count);  
  if   (result   >   0)  
  wcstr[result-1]   =   0;  
  return   result;  
  }  
   
  LPWSTR   AFXAPI   AfxA2WHelper(LPWSTR   lpw,   LPCSTR   lpa,   int   nChars)  
  {  
  if   (lpa   ==   NULL)  
  return   NULL;  
  ASSERT(lpw   !=   NULL);  
  //   verify   that   no   illegal   character   present  
  //   since   lpw   was   allocated   based   on   the   size   of   lpa  
  //   don't   worry   about   the   number   of   chars  
  lpw[0]   =   '/0';  
  VERIFY(MultiByteToWideChar(CP_ACP,   0,   lpa,   -1,   lpw,   nChars));  
  return   lpw;  
  }  
   
  LPSTR   AFXAPI   AfxW2AHelper(LPSTR   lpa,   LPCWSTR   lpw,   int   nChars)  
  {  
  if   (lpw   ==   NULL)  
  return   NULL;  
  ASSERT(lpa   !=   NULL);  
  //   verify   that   no   illegal   character   present  
  //   since   lpa   was   allocated   based   on   the   size   of   lpw  
  //   don't   worry   about   the   number   of   chars  
  lpa[0]   =   '/0';  
  VERIFY(WideCharToMultiByte(CP_ACP,   0,   lpw,   -1,   lpa,   nChars,   NULL,   NULL));  
  return   lpa;  
  } 

Init;GetData;SafeStrlen在vc98/mfc/include/afx.inl中,如下:  
   
  _AFX_INLINE   void   CString::Init()  
  {   m_pchData   =   afxEmptyString.m_pchData;   }  
   
  _AFX_INLINE   CStringData*   CString::GetData()   const  
  {   ASSERT(m_pchData   !=   NULL);   return   ((CStringData*)m_pchData)-1;   }  
   
  _AFX_INLINE   int   PASCAL   CString::SafeStrlen(LPCTSTR   lpsz)  
  {   return   (lpsz   ==   NULL)   ?   0   :   lstrlen(lpsz);   }  

// ============================================================================= // FILE: StdString.h // AUTHOR: Joe O'Leary (with outside help noted in comments) // // If you find any bugs in this code, please let me know: // // jmoleary@earthlink.net // http://www.joeo.net/stdstring.htm (a bit outdated) // // The latest version of this code should always be available at the // following link: // // http://www.joeo.net/code/StdString.zip (Dec 6, 2003) // // // REMARKS: // This header file declares the CStdStr template. This template derives // the Standard C++ Library basic_string<> template and add to it the // the following conveniences: // - The full MFC CString set of functions (including implicit cast) // - writing to/reading from COM IStream interfaces // - Functional objects for use in STL algorithms // // From this template, we intstantiate two classes: CStdStringA and // CStdStringW. The name "CStdString" is just a #define of one of these, // based upone the UNICODE macro setting // // This header also declares our own version of the MFC/ATL UNICODE-MBCS // conversion macros. Our version looks exactly like the Microsoft's to // facilitate portability. // // NOTE: // If you you use this in an MFC or ATL build, you should include either // afx.h or atlbase.h first, as appropriate. // // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS: // // Several people have helped me iron out problems and othewise improve // this class. OK, this is a long list but in my own defense, this code // has undergone two major rewrites. Many of the improvements became // necessary after I rewrote the code as a template. Others helped me // improve the CString facade. // // Anyway, these people are (in chronological order): // // - Pete the Plumber (???) // - Julian Selman // - Chris (of Melbsys) // - Dave Plummer // - John C Sipos // - Chris Sells // - Nigel Nunn // - Fan Xia // - Matthew Williams // - Carl Engman // - Mark Zeren // - Craig Watson // - Rich Zuris // - Karim Ratib // - Chris Conti // - Baptiste Lepilleur // - Greg Pickles // - Jim Cline // - Jeff Kohn // - Todd Heckel // - Ullrich Poll?hne // - Joe Vitaterna // - Joe Woodbury // - Aaron (no last name) // - Joldakowski (???) // - Scott Hathaway // - Eric Nitzche // - Pablo Presedo // - Farrokh Nejadlotfi // - Jason Mills // - Igor Kholodov // - Mike Crusader // - John James // - Wang Haifeng // - Tim Dowty // - Arnt Witteveen // - Glen Maynard // - Paul DeMarco // - Bagira (full name?) // - Ronny Schulz // - Jakko Van Hunen // - Charles Godwin // - Henk Demper // - Greg Marr // - Bill Carducci // - Brian Groose // - MKingman // - Don Beusee // // REVISION HISTORY // // 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping // length-checked formatting functions to non-length-checked // CRT equivalents. Also thanks to him for motivating me to // optimize my implementation of Replace() // // 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for // finally spotting a silly little error in StdCodeCvt that // has been causing me (and users of CStdString) problems for // years in some relatively rare conversions. I had reversed // two length arguments. // // 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many // compiler warnings (and yes, even a couple of actual compiler // errors). These include Henk Demper for figuring out how // to make the Intellisense work on with CStdString on VC6, // something I was never able to do. Greg Marr pointed out // a compiler warning about an unreferenced symbol and a // problem with my version of Load in MFC builds. Bill // Carducci took a lot of time with me to help me figure out // why some implementations of the Standard C++ Library were // returning error codes for apparently successful conversions // between ASCII and UNICODE. Finally thanks to Brian Groose // for helping me fix compiler signed unsigned warnings in // several functions. // // 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg' // fixes had inadvertently broken the DLL-export code (which is // normally commented out. I had to move it up higher. Also // this helped me catch a bug in ssicoll that would prevent // compilation, otherwise. // // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste // bug in one of the overloads of FmtArg. // // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes // to help CStdString build on SGI and for pointing out an // error in placement of my preprocessor macros for ssfmtmsg. // // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of // SpanExcluding was not properly handling the case in which // the string did NOT contain any of the given characters // // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me // get this code working with Borland's free compiler as well // as the Dev-C++ compiler (available free at SourceForge). // // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud // but harmless warnings that were showing up on g++. Glen // also pointed out that some pre-declarations of FmtArg<> // specializations were unnecessary (and no good on G++) // // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using // static_cast<> in a place in which I should have been using // reinterpret_cast<> (the ctor for unsigned char strings). // That's what happens when I don't unit-test properly! // Arnt also noticed that CString was silently correcting the // 'nCount' argument to Left() and Right() where CStdString was // not (and crashing if it was bad). That is also now fixed! // // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix // for) a conversion problem with non-ASCII MBCS characters. // CStdString is now used in my favorite commercial MP3 player! // // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the // assignment operators (for _bstr_t) that would cause compiler // errors when refcounting protection was turned off. // // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators // due to a conflict with the rel_ops operator!=. Thanks to // John James for pointing this out. // // 2001-OCT-29 - Added a minor range checking fix for the Mid function to // make it as forgiving as CString's version is. Thanks to // Igor Kholodov for noticing this. // - Added a specialization of std::swap for CStdString. Thanks // to Mike Crusader for suggesting this! It's commented out // because you're not supposed to inject your own code into the // 'std' namespace. But if you don't care about that, it's // there if you want it // - Thanks to Jason Mills for catching a case where CString was // more forgiving in the Delete() function than I was. // // 2001-JUN-06 - I was violating the Standard name lookup rules stated // in [14.6.2(3)]. None of the compilers I've tried so // far apparently caught this but HP-UX aCC 3.30 did. The // fix was to add 'this->' prefixes in many places. // Thanks to Farrokh Nejadlotfi for this! // // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one // case, not characters. Thanks to Pablo Presedo for this. // // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the // source string was empty. Fixed thanks to Eric Nitzsche. // // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the // ability to build CStdString on Sun Unix systems. He // sent me detailed build reports about what works and what // does not. If CStdString compiles on your Unix box, you // can thank Scott for it. // // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a // range check as CString's does. Now fixed -- thanks! // // 2000-NOV-07 - Aaron pointed out that I was calling static member // functions of char_traits via a temporary. This was not // technically wrong, but it was unnecessary and caused // problems for poor old buggy VC5. Thanks Aaron! // // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match // what the CString::Find code really ends up doing. I was // trying to match the docs. Now I match the CString code // - Joe also caught me truncating strings for GetBuffer() calls // when the supplied length was less than the current length. // // 2000-MAY-25 - Better support for STLPORT's Standard library distribution // - Got rid of the NSP macro - it interfered with Koenig lookup // - Thanks to Joe Woodbury for catching a TrimLeft() bug that // I introduced in January. Empty strings were not getting // trimmed // // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind // is supposed to be a const function. // // 2000-MAR-07 - Thanks to Ullrich Poll?hne for catching a range bug in one // of the overloads of assign. // // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior! // Thanks to Todd Heckel for helping out with this. // // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the // Trim() function more efficient. // - Thanks to Jeff Kohn for prompting me to find and fix a typo // in one of the addition operators that takes _bstr_t. // - Got rid of the .CPP file - you only need StdString.h now! // // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem // with my implementation of CStdString::FormatV in which // resulting string might not be properly NULL terminated. // // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment // bug that MS has not fixed. CStdString did nothing to fix // it either but it does now! The bug was: create a string // longer than 31 characters, get a pointer to it (via c_str()) // and then assign that pointer to the original string object. // The resulting string would be empty. Not with CStdString! // // 1999-OCT-06 - BufferSet was erasing the string even when it was merely // supposed to shrink it. Fixed. Thanks to Chris Conti. // - Some of the Q172398 fixes were not checking for assignment- // to-self. Fixed. Thanks to Baptiste Lepilleur. // // 1999-AUG-20 - Improved Load() function to be more efficient by using // SizeOfResource(). Thanks to Rich Zuris for this. // - Corrected resource ID constructor, again thanks to Rich. // - Fixed a bug that occurred with UNICODE characters above // the first 255 ANSI ones. Thanks to Craig Watson. // - Added missing overloads of TrimLeft() and TrimRight(). // Thanks to Karim Ratib for pointing them out // // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first. // // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros // - Added SS_NO_REFCOUNT macro to allow you to disable any // reference-counting your basic_string<> impl. may do. // - Improved ReleaseBuffer() to be as forgiving as CString. // Thanks for Fan Xia for helping me find this and to // Matthew Williams for pointing it out directly. // // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in // ToLower/ToUpper. They should call GetBuf() instead of // data() in order to ensure the changed string buffer is not // reference-counted (in those implementations that refcount). // // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as // a drop-in replacement for CString. If you find this useful, // you can thank Chris Sells for finally convincing me to give // in and implement it. // - Changed operators << and >> (for MFC CArchive) to serialize // EXACTLY as CString's do. So now you can send a CString out // to a CArchive and later read it in as a CStdString. I have // no idea why you would want to do this but you can. // // 1999-JUN-21 - Changed the CStdString class into the CStdStr template. // - Fixed FormatV() to correctly decrement the loop counter. // This was harmless bug but a bug nevertheless. Thanks to // Chris (of Melbsys) for pointing it out // - Changed Format() to try a normal stack-based array before // using to _alloca(). // - Updated the text conversion macros to properly use code // pages and to fit in better in MFC/ATL builds. In other // words, I copied Microsoft's conversion stuff again. // - Added equivalents of CString::GetBuffer, GetBufferSetLength // - new sscpy() replacement of CStdString::CopyString() // - a Trim() function that combines TrimRight() and TrimLeft(). // // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace() // instead of _isspace() Thanks to Dave Plummer for this. // // 1999-FEB-26 - Removed errant line (left over from testing) that #defined // _MFC_VER. Thanks to John C Sipos for noticing this. // // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that // caused infinite recursion and stack overflow // - Added member functions to simplify the process of // persisting CStdStrings to/from DCOM IStream interfaces // - Added functional objects (e.g. StdStringLessNoCase) that // allow CStdStrings to be used as keys STL map objects with // case-insensitive comparison // - Added array indexing operators (i.e. operator[]). I // originally assumed that these were unnecessary and would be // inherited from basic_string. However, without them, Visual // C++ complains about ambiguous overloads when you try to use // them. Thanks to Julian Selman to pointing this out. // // 1998-FEB-?? - Added overloads of assign() function to completely account // for Q172398 bug. Thanks to "Pete the Plumber" for this // // 1998-FEB-?? - Initial submission // // COPYRIGHT: // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you // want. Rewrite it, restructure it, whatever. If you can write software // that makes money off of it, good for you. I kinda like capitalism. // Please don't blame me if it causes your $30 billion dollar satellite // explode in orbit. If you redistribute it in any form, I'd appreciate it // if you would leave this notice here. // ============
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值