home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / strex.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  21.8 KB  |  976 lines

  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.  
  11. #include "stdafx.h"
  12. #include <afxtempl.h>
  13.  
  14. #ifdef AFX_AUX_SEG
  15. #pragma code_seg(AFX_AUX_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. //////////////////////////////////////////////////////////////////////////////
  26. // More sophisticated construction
  27.  
  28. CString::CString(TCHAR ch, int nLength)
  29. {
  30.     Init();
  31.     if (nLength >= 1)
  32.     {
  33.         AllocBuffer(nLength);
  34. #ifdef _UNICODE
  35.         for (int i = 0; i < nLength; i++)
  36.             m_pchData[i] = ch;
  37. #else
  38.         memset(m_pchData, ch, nLength);
  39. #endif
  40.     }
  41. }
  42.  
  43. CString::CString(LPCTSTR lpch, int nLength)
  44. {
  45.     Init();
  46.     if (nLength != 0)
  47.     {
  48.         ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  49.         AllocBuffer(nLength);
  50.         memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  51.     }
  52. }
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // Special conversion constructors
  56.  
  57. #ifdef _UNICODE
  58. CString::CString(LPCSTR lpsz, int nLength)
  59. {
  60.     Init();
  61.     if (nLength != 0)
  62.     {
  63.         AllocBuffer(nLength);
  64.         int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
  65.         ReleaseBuffer(n >= 0 ? n : -1);
  66.     }
  67. }
  68. #else //_UNICODE
  69. CString::CString(LPCWSTR lpsz, int nLength)
  70. {
  71.     Init();
  72.     if (nLength != 0)
  73.     {
  74.         AllocBuffer(nLength*2);
  75.         int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, 
  76.             (nLength*2)+1, NULL, NULL);
  77.         ReleaseBuffer(n >= 0 ? n : -1);
  78.     }
  79. }
  80. #endif //!_UNICODE
  81.  
  82. //////////////////////////////////////////////////////////////////////////////
  83. // Assignment operators
  84.  
  85. const CString& CString::operator=(TCHAR ch)
  86. {
  87.     AssignCopy(1, &ch);
  88.     return *this;
  89. }
  90.  
  91. //////////////////////////////////////////////////////////////////////////////
  92. // less common string expressions
  93.  
  94. CString AFXAPI operator+(const CString& string1, TCHAR ch)
  95. {
  96.     CString s;
  97.     s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  98.     return s;
  99. }
  100.  
  101. CString AFXAPI operator+(TCHAR ch, const CString& string)
  102. {
  103.     CString s;
  104.     s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  105.     return s;
  106. }
  107.  
  108. //////////////////////////////////////////////////////////////////////////////
  109. // Advanced manipulation
  110.  
  111. int CString::Delete(int nIndex, int nCount /* = 1 */)
  112. {
  113.     if (nIndex < 0)
  114.         nIndex = 0;
  115.     int nNewLength = GetData()->nDataLength;
  116.     if (nCount > 0 && nIndex < nNewLength)
  117.     {
  118.         CopyBeforeWrite();
  119.         int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  120.  
  121.         memcpy(m_pchData + nIndex,
  122.             m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  123.         GetData()->nDataLength = nNewLength - nCount;
  124.     }
  125.  
  126.     return nNewLength;
  127. }
  128.  
  129. int CString::Insert(int nIndex, TCHAR ch)
  130. {
  131.     CopyBeforeWrite();
  132.  
  133.     if (nIndex < 0)
  134.         nIndex = 0;
  135.  
  136.     int nNewLength = GetData()->nDataLength;
  137.     if (nIndex > nNewLength)
  138.         nIndex = nNewLength;
  139.     nNewLength++;
  140.  
  141.     if (GetData()->nAllocLength < nNewLength)
  142.     {
  143.         CStringData* pOldData = GetData();
  144.         LPTSTR pstr = m_pchData;
  145.         AllocBuffer(nNewLength);
  146.         memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  147.         CString::Release(pOldData);
  148.     }
  149.  
  150.     // move existing bytes down
  151.     memcpy(m_pchData + nIndex + 1,
  152.         m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
  153.     m_pchData[nIndex] = ch;
  154.     GetData()->nDataLength = nNewLength;
  155.  
  156.     return nNewLength;
  157. }
  158.  
  159. int CString::Insert(int nIndex, LPCTSTR pstr)
  160. {
  161.     if (nIndex < 0)
  162.         nIndex = 0;
  163.  
  164.     int nInsertLength = SafeStrlen(pstr);
  165.     int nNewLength = GetData()->nDataLength;
  166.     if (nInsertLength > 0)
  167.     {
  168.         CopyBeforeWrite();
  169.         if (nIndex > nNewLength)
  170.             nIndex = nNewLength;
  171.         nNewLength += nInsertLength;
  172.  
  173.         if (GetData()->nAllocLength < nNewLength)
  174.         {
  175.             CStringData* pOldData = GetData();
  176.             LPTSTR pstr = m_pchData;
  177.             AllocBuffer(nNewLength);
  178.             memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  179.             CString::Release(pOldData);
  180.         }
  181.  
  182.         // move existing bytes down
  183.         memcpy(m_pchData + nIndex + nInsertLength,
  184.             m_pchData + nIndex, 
  185.             (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
  186.         memcpy(m_pchData + nIndex,
  187.             pstr, nInsertLength*sizeof(TCHAR));
  188.         GetData()->nDataLength = nNewLength;
  189.     }
  190.  
  191.     return nNewLength;
  192. }
  193.  
  194. int CString::Replace(TCHAR chOld, TCHAR chNew)
  195. {
  196.     int nCount = 0;
  197.  
  198.     // short-circuit the nop case
  199.     if (chOld != chNew)
  200.     {
  201.         // otherwise modify each character that matches in the string
  202.         CopyBeforeWrite();
  203.         LPTSTR psz = m_pchData;
  204.         LPTSTR pszEnd = psz + GetData()->nDataLength;
  205.         while (psz < pszEnd)
  206.         {
  207.             // replace instances of the specified character only
  208.             if (*psz == chOld)
  209.             {
  210.                 *psz = chNew;
  211.                 nCount++;
  212.             }
  213.             psz = _tcsinc(psz);
  214.         }
  215.     }
  216.     return nCount;
  217. }
  218.  
  219. int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  220. {
  221.     // can't have empty or NULL lpszOld
  222.  
  223.     int nSourceLen = SafeStrlen(lpszOld);
  224.     if (nSourceLen == 0)
  225.         return 0;
  226.     int nReplacementLen = SafeStrlen(lpszNew);
  227.  
  228.     // loop once to figure out the size of the result string
  229.     int nCount = 0;
  230.     LPTSTR lpszStart = m_pchData;
  231.     LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  232.     LPTSTR lpszTarget;
  233.     while (lpszStart < lpszEnd)
  234.     {
  235.         while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  236.         {
  237.             nCount++;
  238.             lpszStart = lpszTarget + nSourceLen;
  239.         }
  240.         lpszStart += lstrlen(lpszStart) + 1;
  241.     }
  242.  
  243.     // if any changes were made, make them
  244.     if (nCount > 0)
  245.     {
  246.         CopyBeforeWrite();
  247.  
  248.         // if the buffer is too small, just
  249.         //   allocate a new buffer (slow but sure)
  250.         int nOldLength = GetData()->nDataLength;
  251.         int nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount;
  252.         if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  253.         {
  254.             CStringData* pOldData = GetData();
  255.             LPTSTR pstr = m_pchData;
  256.             AllocBuffer(nNewLength);
  257.             memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  258.             CString::Release(pOldData);
  259.         }
  260.         // else, we just do it in-place
  261.         lpszStart = m_pchData;
  262.         lpszEnd = m_pchData + GetData()->nDataLength;
  263.  
  264.         // loop again to actually do the work
  265.         while (lpszStart < lpszEnd)
  266.         {
  267.             while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  268.             {
  269.                 int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen);
  270.                 memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen, 
  271.                     nBalance * sizeof(TCHAR));
  272.                  memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
  273.                 lpszStart = lpszTarget + nReplacementLen;
  274.                 lpszStart[nBalance] = '\0';
  275.                 nOldLength += (nReplacementLen - nSourceLen);
  276.             }
  277.             lpszStart += lstrlen(lpszStart) + 1;
  278.         }
  279.         ASSERT(m_pchData[nNewLength] == '\0');
  280.         GetData()->nDataLength = nNewLength;
  281.     }
  282.  
  283.     return nCount;
  284. }
  285.  
  286. int CString::Remove(TCHAR chRemove)
  287. {
  288.     CopyBeforeWrite();
  289.  
  290.     LPTSTR pstrSource = m_pchData;
  291.     LPTSTR pstrDest = m_pchData;
  292.     LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
  293.  
  294.     while (pstrSource < pstrEnd)
  295.     {
  296.         if (*pstrSource != chRemove)
  297.         {
  298.             *pstrDest = *pstrSource;
  299.             pstrDest = _tcsinc(pstrDest);
  300.         }
  301.         pstrSource = _tcsinc(pstrSource);
  302.     }
  303.     *pstrDest = '\0';
  304.     int nCount = pstrSource - pstrDest;
  305.     GetData()->nDataLength -= nCount;
  306.  
  307.     return nCount;
  308. }
  309.  
  310. //////////////////////////////////////////////////////////////////////////////
  311. // Very simple sub-string extraction
  312.  
  313. CString CString::Mid(int nFirst) const
  314. {
  315.     return Mid(nFirst, GetData()->nDataLength - nFirst);
  316. }
  317.  
  318. CString CString::Mid(int nFirst, int nCount) const
  319. {
  320.     // out-of-bounds requests return sensible things
  321.     if (nFirst < 0)
  322.         nFirst = 0;
  323.     if (nCount < 0)
  324.         nCount = 0;
  325.  
  326.     if (nFirst + nCount > GetData()->nDataLength)
  327.         nCount = GetData()->nDataLength - nFirst;
  328.     if (nFirst > GetData()->nDataLength)
  329.         nCount = 0;
  330.  
  331.     ASSERT(nFirst >= 0);
  332.     ASSERT(nFirst + nCount <= GetData()->nDataLength);
  333.  
  334.     // optimize case of returning entire string
  335.     if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  336.         return *this;
  337.  
  338.     CString dest;
  339.     AllocCopy(dest, nCount, nFirst, 0);
  340.     return dest;
  341. }
  342.  
  343. CString CString::Right(int nCount) const
  344. {
  345.     if (nCount < 0)
  346.         nCount = 0;
  347.     if (nCount >= GetData()->nDataLength)
  348.         return *this;
  349.  
  350.     CString dest;
  351.     AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  352.     return dest;
  353. }
  354.  
  355. CString CString::Left(int nCount) const
  356. {
  357.     if (nCount < 0)
  358.         nCount = 0;
  359.     if (nCount >= GetData()->nDataLength)
  360.         return *this;
  361.  
  362.     CString dest;
  363.     AllocCopy(dest, nCount, 0, 0);
  364.     return dest;
  365. }
  366.  
  367. // strspn equivalent
  368. CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  369. {
  370.     ASSERT(AfxIsValidString(lpszCharSet));
  371.     return Left(_tcsspn(m_pchData, lpszCharSet));
  372. }
  373.  
  374. // strcspn equivalent
  375. CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  376. {
  377.     ASSERT(AfxIsValidString(lpszCharSet));
  378.     return Left(_tcscspn(m_pchData, lpszCharSet));
  379. }
  380.  
  381. //////////////////////////////////////////////////////////////////////////////
  382. // Finding
  383.  
  384. int CString::ReverseFind(TCHAR ch) const
  385. {
  386.     // find last single character
  387.     LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
  388.  
  389.     // return -1 if not found, distance from beginning otherwise
  390.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  391. }
  392.  
  393. // find a sub-string (like strstr)
  394. int CString::Find(LPCTSTR lpszSub) const
  395. {
  396.     return Find(lpszSub, 0);
  397. }
  398.  
  399. int CString::Find(LPCTSTR lpszSub, int nStart) const
  400. {
  401.     ASSERT(AfxIsValidString(lpszSub));
  402.  
  403.     int nLength = GetData()->nDataLength;
  404.     if (nStart > nLength)
  405.         return -1;
  406.  
  407.     // find first matching substring
  408.     LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
  409.  
  410.     // return -1 for not found, distance from beginning otherwise
  411.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  412. }
  413.  
  414.  
  415. /////////////////////////////////////////////////////////////////////////////
  416. // CString formatting
  417.  
  418. #define TCHAR_ARG   TCHAR
  419. #define WCHAR_ARG   WCHAR
  420. #define CHAR_ARG    char
  421.  
  422. #ifdef _X86_
  423.     #define DOUBLE_ARG  _AFX_DOUBLE
  424. #else
  425.     #define DOUBLE_ARG  double
  426. #endif
  427.  
  428. #define FORCE_ANSI      0x10000
  429. #define FORCE_UNICODE   0x20000
  430. #define FORCE_INT64        0x40000
  431.  
  432. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  433. {
  434.     ASSERT(AfxIsValidString(lpszFormat));
  435.  
  436.     va_list argListSave = argList;
  437.  
  438.     // make a guess at the maximum length of the resulting string
  439.     int nMaxLen = 0;
  440.     for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  441.     {
  442.         // handle '%' character, but watch out for '%%'
  443.         if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  444.         {
  445.             nMaxLen += _tclen(lpsz);
  446.             continue;
  447.         }
  448.  
  449.         int nItemLen = 0;
  450.  
  451.         // handle '%' character with format
  452.         int nWidth = 0;
  453.         for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  454.         {
  455.             // check for valid flags
  456.             if (*lpsz == '#')
  457.                 nMaxLen += 2;   // for '0x'
  458.             else if (*lpsz == '*')
  459.                 nWidth = va_arg(argList, int);
  460.             else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  461.                 *lpsz == ' ')
  462.                 ;
  463.             else // hit non-flag character
  464.                 break;
  465.         }
  466.         // get width and skip it
  467.         if (nWidth == 0)
  468.         {
  469.             // width indicated by
  470.             nWidth = _ttoi(lpsz);
  471.             for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  472.                 ;
  473.         }
  474.         ASSERT(nWidth >= 0);
  475.  
  476.         int nPrecision = 0;
  477.         if (*lpsz == '.')
  478.         {
  479.             // skip past '.' separator (width.precision)
  480.             lpsz = _tcsinc(lpsz);
  481.  
  482.             // get precision and skip it
  483.             if (*lpsz == '*')
  484.             {
  485.                 nPrecision = va_arg(argList, int);
  486.                 lpsz = _tcsinc(lpsz);
  487.             }
  488.             else
  489.             {
  490.                 nPrecision = _ttoi(lpsz);
  491.                 for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  492.                     ;
  493.             }
  494.             ASSERT(nPrecision >= 0);
  495.         }
  496.  
  497.         // should be on type modifier or specifier
  498.         int nModifier = 0;
  499.         if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  500.         {
  501.             lpsz += 3;
  502.             nModifier = FORCE_INT64;
  503. #if !defined(_X86_) && !defined(_ALPHA_)
  504.             // __int64 is only available on X86 and ALPHA platforms
  505.             ASSERT(FALSE);
  506. #endif
  507.         }
  508.         else
  509.         {
  510.             switch (*lpsz)
  511.             {
  512.             // modifiers that affect size
  513.             case 'h':
  514.                 nModifier = FORCE_ANSI;
  515.                 lpsz = _tcsinc(lpsz);
  516.                 break;
  517.             case 'l':
  518.                 nModifier = FORCE_UNICODE;
  519.                 lpsz = _tcsinc(lpsz);
  520.                 break;
  521.  
  522.             // modifiers that do not affect size
  523.             case 'F':
  524.             case 'N':
  525.             case 'L':
  526.                 lpsz = _tcsinc(lpsz);
  527.                 break;
  528.             }
  529.         }
  530.  
  531.         // now should be on specifier
  532.         switch (*lpsz | nModifier)
  533.         {
  534.         // single characters
  535.         case 'c':
  536.         case 'C':
  537.             nItemLen = 2;
  538.             va_arg(argList, TCHAR_ARG);
  539.             break;
  540.         case 'c'|FORCE_ANSI:
  541.         case 'C'|FORCE_ANSI:
  542.             nItemLen = 2;
  543.             va_arg(argList, CHAR_ARG);
  544.             break;
  545.         case 'c'|FORCE_UNICODE:
  546.         case 'C'|FORCE_UNICODE:
  547.             nItemLen = 2;
  548.             va_arg(argList, WCHAR_ARG);
  549.             break;
  550.  
  551.         // strings
  552.         case 's':
  553.             {
  554.                 LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  555.                 if (pstrNextArg == NULL)
  556.                    nItemLen = 6;  // "(null)"
  557.                 else
  558.                 {
  559.                    nItemLen = lstrlen(pstrNextArg);
  560.                    nItemLen = max(1, nItemLen);
  561.                 }
  562.             }
  563.             break;
  564.  
  565.         case 'S':
  566.             {
  567. #ifndef _UNICODE
  568.                 LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  569.                 if (pstrNextArg == NULL)
  570.                    nItemLen = 6;  // "(null)"
  571.                 else
  572.                 {
  573.                    nItemLen = wcslen(pstrNextArg);
  574.                    nItemLen = max(1, nItemLen);
  575.                 }
  576. #else
  577.                 LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  578.                 if (pstrNextArg == NULL)
  579.                    nItemLen = 6; // "(null)"
  580.                 else
  581.                 {
  582.                    nItemLen = lstrlenA(pstrNextArg);
  583.                    nItemLen = max(1, nItemLen);
  584.                 }
  585. #endif
  586.             }
  587.             break;
  588.  
  589.         case 's'|FORCE_ANSI:
  590.         case 'S'|FORCE_ANSI:
  591.             {
  592.                 LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  593.                 if (pstrNextArg == NULL)
  594.                    nItemLen = 6; // "(null)"
  595.                 else
  596.                 {
  597.                    nItemLen = lstrlenA(pstrNextArg);
  598.                    nItemLen = max(1, nItemLen);
  599.                 }
  600.             }
  601.             break;
  602.  
  603.         case 's'|FORCE_UNICODE:
  604.         case 'S'|FORCE_UNICODE:
  605.             {
  606.                 LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  607.                 if (pstrNextArg == NULL)
  608.                    nItemLen = 6; // "(null)"
  609.                 else
  610.                 {
  611.                    nItemLen = wcslen(pstrNextArg);
  612.                    nItemLen = max(1, nItemLen);
  613.                 }
  614.             }
  615.             break;
  616.         }
  617.  
  618.         // adjust nItemLen for strings
  619.         if (nItemLen != 0)
  620.         {
  621.             if (nPrecision != 0)
  622.                 nItemLen = min(nItemLen, nPrecision);
  623.             nItemLen = max(nItemLen, nWidth);
  624.         }
  625.         else
  626.         {
  627.             switch (*lpsz)
  628.             {
  629.             // integers
  630.             case 'd':
  631.             case 'i':
  632.             case 'u':
  633.             case 'x':
  634.             case 'X':
  635.             case 'o':
  636.                 if (nModifier & FORCE_INT64)
  637.                     va_arg(argList, __int64);
  638.                 else
  639.                     va_arg(argList, int);
  640.                 nItemLen = 32;
  641.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  642.                 break;
  643.  
  644.             case 'e':
  645.             case 'g':
  646.             case 'G':
  647.                 va_arg(argList, DOUBLE_ARG);
  648.                 nItemLen = 128;
  649.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  650.                 break;
  651.  
  652.             case 'f':
  653.                 va_arg(argList, DOUBLE_ARG);
  654.                 nItemLen = 128;    // width isn't truncated
  655.                 // 312 == strlen("-1+(309 zeroes).")
  656.                 // 309 zeroes == max precision of a double
  657.                 nItemLen = max(nItemLen, 312+nPrecision);
  658.                 break;
  659.  
  660.             case 'p':
  661.                 va_arg(argList, void*);
  662.                 nItemLen = 32;
  663.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  664.                 break;
  665.  
  666.             // no output
  667.             case 'n':
  668.                 va_arg(argList, int*);
  669.                 break;
  670.  
  671.             default:
  672.                 ASSERT(FALSE);  // unknown formatting option
  673.             }
  674.         }
  675.  
  676.         // adjust nMaxLen for output nItemLen
  677.         nMaxLen += nItemLen;
  678.     }
  679.  
  680.     GetBuffer(nMaxLen);
  681.     VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
  682.     ReleaseBuffer();
  683.  
  684.     va_end(argListSave);
  685. }
  686.  
  687. // formatting (using wsprintf style formatting)
  688. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  689. {
  690.     ASSERT(AfxIsValidString(lpszFormat));
  691.  
  692.     va_list argList;
  693.     va_start(argList, lpszFormat);
  694.     FormatV(lpszFormat, argList);
  695.     va_end(argList);
  696. }
  697.  
  698. void AFX_CDECL CString::Format(UINT nFormatID, ...)
  699. {
  700.     CString strFormat;
  701.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  702.  
  703.     va_list argList;
  704.     va_start(argList, nFormatID);
  705.     FormatV(strFormat, argList);
  706.     va_end(argList);
  707. }
  708.  
  709. #if !defined(_WIN32_WCE)
  710. // formatting (using FormatMessage style formatting)
  711. void AFX_CDECL CString::FormatMessage(LPCTSTR lpszFormat, ...)
  712. {
  713.     // format message into temporary buffer lpszTemp
  714.     va_list argList;
  715.     va_start(argList, lpszFormat);
  716.     LPTSTR lpszTemp;
  717.  
  718.     if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  719.         lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  720.         lpszTemp == NULL)
  721.     {
  722.         AfxThrowMemoryException();
  723.     }
  724.  
  725.     // assign lpszTemp into the resulting string and free the temporary
  726.     *this = lpszTemp;
  727.     LocalFree(lpszTemp);
  728.     va_end(argList);
  729. }
  730.  
  731. void AFX_CDECL CString::FormatMessage(UINT nFormatID, ...)
  732. {
  733.     // get format string from string table
  734.     CString strFormat;
  735.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  736.  
  737.     // format message into temporary buffer lpszTemp
  738.     va_list argList;
  739.     va_start(argList, nFormatID);
  740.     LPTSTR lpszTemp;
  741.     if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  742.         strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  743.         lpszTemp == NULL)
  744.     {
  745.         AfxThrowMemoryException();
  746.     }
  747.  
  748.     // assign lpszTemp into the resulting string and free lpszTemp
  749.     *this = lpszTemp;
  750.     LocalFree(lpszTemp);
  751.     va_end(argList);
  752. }
  753. #endif // _WIN32_WCE
  754.  
  755. void CString::TrimRight(LPCTSTR lpszTargetList)
  756. {
  757.     // find beginning of trailing matches
  758.     // by starting at beginning (DBCS aware)
  759.  
  760.     CopyBeforeWrite();
  761.     LPTSTR lpsz = m_pchData;
  762.     LPTSTR lpszLast = NULL;
  763.  
  764.     while (*lpsz != '\0')
  765.     {
  766.         if (_tcschr(lpszTargetList, *lpsz) != NULL)
  767.         {
  768.             if (lpszLast == NULL)
  769.                 lpszLast = lpsz;
  770.         }
  771.         else
  772.             lpszLast = NULL;
  773.         lpsz = _tcsinc(lpsz);
  774.     }
  775.  
  776.     if (lpszLast != NULL)
  777.     {
  778.         // truncate at left-most matching character  
  779.         *lpszLast = '\0';
  780.         GetData()->nDataLength = lpszLast - m_pchData;
  781.     }
  782. }
  783.  
  784. void CString::TrimRight(TCHAR chTarget)
  785. {
  786.     // find beginning of trailing matches
  787.     // by starting at beginning (DBCS aware)
  788.  
  789.     CopyBeforeWrite();
  790.     LPTSTR lpsz = m_pchData;
  791.     LPTSTR lpszLast = NULL;
  792.  
  793.     while (*lpsz != '\0')
  794.     {
  795.         if (*lpsz == chTarget)
  796.         {
  797.             if (lpszLast == NULL)
  798.                 lpszLast = lpsz;
  799.         }
  800.         else
  801.             lpszLast = NULL;
  802.         lpsz = _tcsinc(lpsz);
  803.     }
  804.  
  805.     if (lpszLast != NULL)
  806.     {
  807.         // truncate at left-most matching character  
  808.         *lpszLast = '\0';
  809.         GetData()->nDataLength = lpszLast - m_pchData;
  810.     }
  811. }
  812.  
  813. void CString::TrimRight()
  814. {
  815.     // find beginning of trailing spaces by starting at beginning (DBCS aware)
  816.  
  817.     CopyBeforeWrite();
  818.     LPTSTR lpsz = m_pchData;
  819.     LPTSTR lpszLast = NULL;
  820.  
  821.     while (*lpsz != '\0')
  822.     {
  823.         if (_istspace(*lpsz))
  824.         {
  825.             if (lpszLast == NULL)
  826.                 lpszLast = lpsz;
  827.         }
  828.         else
  829.             lpszLast = NULL;
  830.         lpsz = _tcsinc(lpsz);
  831.     }
  832.  
  833.     if (lpszLast != NULL)
  834.     {
  835.         // truncate at trailing space start
  836.         *lpszLast = '\0';
  837.         GetData()->nDataLength = lpszLast - m_pchData;
  838.     }
  839. }
  840.  
  841. void CString::TrimLeft(LPCTSTR lpszTargets)
  842. {
  843.     // if we're not trimming anything, we're not doing any work
  844.     if (SafeStrlen(lpszTargets) == 0)
  845.         return;
  846.  
  847.     CopyBeforeWrite();
  848.     LPCTSTR lpsz = m_pchData;
  849.  
  850.     while (*lpsz != '\0')
  851.     {
  852.         if (_tcschr(lpszTargets, *lpsz) == NULL)
  853.             break;
  854.         lpsz = _tcsinc(lpsz);
  855.     }
  856.  
  857.     if (lpsz != m_pchData)
  858.     {
  859.         // fix up data and length
  860.         int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  861.         memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  862.         GetData()->nDataLength = nDataLength;
  863.     }
  864. }
  865.  
  866. void CString::TrimLeft(TCHAR chTarget)
  867. {
  868.     // find first non-matching character
  869.     
  870.     CopyBeforeWrite();
  871.     LPCTSTR lpsz = m_pchData;
  872.  
  873.     while (chTarget == *lpsz)
  874.         lpsz = _tcsinc(lpsz);
  875.  
  876.     if (lpsz != m_pchData)
  877.     {
  878.         // fix up data and length
  879.         int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  880.         memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  881.         GetData()->nDataLength = nDataLength;
  882.     }
  883. }
  884.  
  885. void CString::TrimLeft()
  886. {
  887.     // find first non-space character
  888.  
  889.     CopyBeforeWrite();
  890.     LPCTSTR lpsz = m_pchData;
  891.  
  892.     while (_istspace(*lpsz))
  893.         lpsz = _tcsinc(lpsz);
  894.  
  895.     if (lpsz != m_pchData)
  896.     {
  897.         // fix up data and length
  898.         int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  899.         memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  900.         GetData()->nDataLength = nDataLength;
  901.     }
  902. }
  903.  
  904. ///////////////////////////////////////////////////////////////////////////////
  905. // CString support for template collections
  906.  
  907. #if _MSC_VER >= 1100
  908. template<> void AFXAPI ConstructElements<CString> (CString* pElements, int nCount)
  909. #else
  910. void AFXAPI ConstructElements(CString* pElements, int nCount)
  911. #endif
  912. {
  913.     ASSERT(nCount == 0 ||
  914.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  915.  
  916.     for (; nCount--; ++pElements)
  917.         memcpy(pElements, &afxEmptyString, sizeof(*pElements));
  918. }
  919.  
  920. #if _MSC_VER >= 1100
  921. template<> void AFXAPI DestructElements<CString> (CString* pElements, int nCount)
  922. #else
  923. void AFXAPI DestructElements(CString* pElements, int nCount)
  924. #endif
  925. {
  926.     ASSERT(nCount == 0 ||
  927.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  928.  
  929.     for (; nCount--; ++pElements)
  930.         pElements->~CString();
  931. }
  932.  
  933. #if _MSC_VER >= 1100
  934. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, int nCount)
  935. #else
  936. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, int nCount)
  937. #endif
  938. {
  939.     ASSERT(nCount == 0 ||
  940.         AfxIsValidAddress(pDest, nCount * sizeof(CString)));
  941.     ASSERT(nCount == 0 ||
  942.         AfxIsValidAddress(pSrc, nCount * sizeof(CString)));
  943.  
  944.     for (; nCount--; ++pDest, ++pSrc)
  945.         *pDest = *pSrc;
  946. }
  947.  
  948. #ifndef OLE2ANSI
  949. #if _MSC_VER >= 1100
  950. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
  951. #else
  952. UINT AFXAPI HashKey(LPCWSTR key)
  953. #endif
  954. {
  955.     UINT nHash = 0;
  956.     while (*key)
  957.         nHash = (nHash<<5) + nHash + *key++;
  958.     return nHash;
  959. }
  960. #endif
  961.  
  962. #if _MSC_VER >= 1100
  963. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
  964. #else
  965. UINT AFXAPI HashKey(LPCSTR key)
  966. #endif
  967. {
  968.     UINT nHash = 0;
  969.     while (*key)
  970.         nHash = (nHash<<5) + nHash + *key++;
  971.     return nHash;
  972. }
  973.  
  974. ///////////////////////////////////////////////////////////////////////////////
  975.  
  976.