home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / STREX.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  13.5 KB  |  608 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. #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.     ASSERT(!_istlead(ch));    // can't create a lead byte string
  31.     Init();
  32.     if (nLength >= 1)
  33.     {
  34.         AllocBuffer(nLength);
  35. #ifdef _UNICODE
  36.         for (int i = 0; i < nLength; i++)
  37.             m_pchData[i] = ch;
  38. #else
  39.         memset(m_pchData, ch, nLength);
  40. #endif
  41.     }
  42. }
  43.  
  44. CString::CString(LPCTSTR lpch, int nLength)
  45. {
  46.     Init();
  47.     if (nLength != 0)
  48.     {
  49.         ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  50.         AllocBuffer(nLength);
  51.         memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  52.     }
  53. }
  54.  
  55. //////////////////////////////////////////////////////////////////////////////
  56. // Assignment operators
  57.  
  58. const CString& CString::operator=(TCHAR ch)
  59. {
  60.     ASSERT(!_istlead(ch));    // can't set single lead byte
  61.     AssignCopy(1, &ch);
  62.     return *this;
  63. }
  64.  
  65. //////////////////////////////////////////////////////////////////////////////
  66. // less common string expressions
  67.  
  68. CString AFXAPI operator+(const CString& string1, TCHAR ch)
  69. {
  70.     CString s;
  71.     s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  72.     return s;
  73. }
  74.  
  75. CString AFXAPI operator+(TCHAR ch, const CString& string)
  76. {
  77.     CString s;
  78.     s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  79.     return s;
  80. }
  81.  
  82. //////////////////////////////////////////////////////////////////////////////
  83. // Very simple sub-string extraction
  84.  
  85. CString CString::Mid(int nFirst) const
  86. {
  87.     return Mid(nFirst, GetData()->nDataLength - nFirst);
  88. }
  89.  
  90. CString CString::Mid(int nFirst, int nCount) const
  91. {
  92.     // out-of-bounds requests return sensible things
  93.     if (nFirst < 0)
  94.         nFirst = 0;
  95.     if (nCount < 0)
  96.         nCount = 0;
  97.  
  98.     if (nFirst + nCount > GetData()->nDataLength)
  99.         nCount = GetData()->nDataLength - nFirst;
  100.     if (nFirst > GetData()->nDataLength)
  101.         nCount = 0;
  102.  
  103.     CString dest;
  104.     AllocCopy(dest, nCount, nFirst, 0);
  105.     return dest;
  106. }
  107.  
  108. CString CString::Right(int nCount) const
  109. {
  110.     if (nCount < 0)
  111.         nCount = 0;
  112.     else if (nCount > GetData()->nDataLength)
  113.         nCount = GetData()->nDataLength;
  114.  
  115.     CString dest;
  116.     AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  117.     return dest;
  118. }
  119.  
  120. CString CString::Left(int nCount) const
  121. {
  122.     if (nCount < 0)
  123.         nCount = 0;
  124.     else if (nCount > GetData()->nDataLength)
  125.         nCount = GetData()->nDataLength;
  126.  
  127.     CString dest;
  128.     AllocCopy(dest, nCount, 0, 0);
  129.     return dest;
  130. }
  131.  
  132. // strspn equivalent
  133. CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  134. {
  135.     ASSERT(AfxIsValidString(lpszCharSet, FALSE));
  136.     return Left(_tcsspn(m_pchData, lpszCharSet));
  137. }
  138.  
  139. // strcspn equivalent
  140. CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  141. {
  142.     ASSERT(AfxIsValidString(lpszCharSet, FALSE));
  143.     return Left(_tcscspn(m_pchData, lpszCharSet));
  144. }
  145.  
  146. //////////////////////////////////////////////////////////////////////////////
  147. // Finding
  148.  
  149. int CString::ReverseFind(TCHAR ch) const
  150. {
  151.     // find last single character
  152.     LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR)ch);
  153.  
  154.     // return -1 if not found, distance from beginning otherwise
  155.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  156. }
  157.  
  158. // find a sub-string (like strstr)
  159. int CString::Find(LPCTSTR lpszSub) const
  160. {
  161.     ASSERT(AfxIsValidString(lpszSub, FALSE));
  162.  
  163.     // find first matching substring
  164.     LPTSTR lpsz = _tcsstr(m_pchData, lpszSub);
  165.  
  166.     // return -1 for not found, distance from beginning otherwise
  167.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  168. }
  169.  
  170. /////////////////////////////////////////////////////////////////////////////
  171. // CString formatting
  172.  
  173. #ifdef _MAC
  174.     #define TCHAR_ARG   int
  175.     #define WCHAR_ARG   unsigned
  176.     #define CHAR_ARG    int
  177. #else
  178.     #define TCHAR_ARG   TCHAR
  179.     #define WCHAR_ARG   WCHAR
  180.     #define CHAR_ARG    char
  181. #endif
  182.  
  183. #if defined(_68K_) || defined(_X86_)
  184.     #define DOUBLE_ARG  _AFX_DOUBLE
  185. #else
  186.     #define DOUBLE_ARG  double
  187. #endif
  188.  
  189. #define FORCE_ANSI      0x10000
  190. #define FORCE_UNICODE   0x20000
  191.  
  192. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  193. {
  194.     ASSERT(AfxIsValidString(lpszFormat, FALSE));
  195.  
  196.     va_list argListSave = argList;
  197.  
  198.     // make a guess at the maximum length of the resulting string
  199.     int nMaxLen = 0;
  200.     for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  201.     {
  202.         // handle '%' character, but watch out for '%%'
  203.         if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  204.         {
  205.             nMaxLen += _tclen(lpsz);
  206.             continue;
  207.         }
  208.  
  209.         int nItemLen = 0;
  210.  
  211.         // handle '%' character with format
  212.         int nWidth = 0;
  213.         for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  214.         {
  215.             // check for valid flags
  216.             if (*lpsz == '#')
  217.                 nMaxLen += 2;   // for '0x'
  218.             else if (*lpsz == '*')
  219.                 nWidth = va_arg(argList, int);
  220.             else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  221.                 *lpsz == ' ')
  222.                 ;
  223.             else // hit non-flag character
  224.                 break;
  225.         }
  226.         // get width and skip it
  227.         if (nWidth == 0)
  228.         {
  229.             // width indicated by
  230.             nWidth = _ttoi(lpsz);
  231.             for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  232.                 ;
  233.         }
  234.         ASSERT(nWidth >= 0);
  235.  
  236.         int nPrecision = 0;
  237.         if (*lpsz == '.')
  238.         {
  239.             // skip past '.' separator (width.precision)
  240.             lpsz = _tcsinc(lpsz);
  241.  
  242.             // get precision and skip it
  243.             if (*lpsz == '*')
  244.             {
  245.                 nPrecision = va_arg(argList, int);
  246.                 lpsz = _tcsinc(lpsz);
  247.             }
  248.             else
  249.             {
  250.                 nPrecision = _ttoi(lpsz);
  251.                 for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  252.                     ;
  253.             }
  254.             ASSERT(nPrecision >= 0);
  255.         }
  256.  
  257.         // should be on type modifier or specifier
  258.         int nModifier = 0;
  259.         switch (*lpsz)
  260.         {
  261.         // modifiers that affect size
  262.         case 'h':
  263.             nModifier = FORCE_ANSI;
  264.             lpsz = _tcsinc(lpsz);
  265.             break;
  266.         case 'l':
  267.             nModifier = FORCE_UNICODE;
  268.             lpsz = _tcsinc(lpsz);
  269.             break;
  270.  
  271.         // modifiers that do not affect size
  272.         case 'F':
  273.         case 'N':
  274.         case 'L':
  275.             lpsz = _tcsinc(lpsz);
  276.             break;
  277.         }
  278.  
  279.         // now should be on specifier
  280.         switch (*lpsz | nModifier)
  281.         {
  282.         // single characters
  283.         case 'c':
  284.         case 'C':
  285.             nItemLen = 2;
  286.             va_arg(argList, TCHAR_ARG);
  287.             break;
  288.         case 'c'|FORCE_ANSI:
  289.         case 'C'|FORCE_ANSI:
  290.             nItemLen = 2;
  291.             va_arg(argList, CHAR_ARG);
  292.             break;
  293.         case 'c'|FORCE_UNICODE:
  294.         case 'C'|FORCE_UNICODE:
  295.             nItemLen = 2;
  296.             va_arg(argList, WCHAR_ARG);
  297.             break;
  298.  
  299.         // strings
  300.         case 's':
  301.         {
  302.             LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  303.             if (pstrNextArg == NULL)
  304.                nItemLen = 6;  // "(null)"
  305.             else
  306.             {
  307.                nItemLen = lstrlen(pstrNextArg);
  308.                nItemLen = max(1, nItemLen);
  309.             }
  310.             break;
  311.         }
  312.  
  313.         case 'S':
  314.         {
  315. #ifndef _UNICODE
  316.             LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  317.             if (pstrNextArg == NULL)
  318.                nItemLen = 6;  // "(null)"
  319.             else
  320.             {
  321.                nItemLen = wcslen(pstrNextArg);
  322.                nItemLen = max(1, nItemLen);
  323.             }
  324. #else
  325.             LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  326.             if (pstrNextArg == NULL)
  327.                nItemLen = 6; // "(null)"
  328.             else
  329.             {
  330.                nItemLen = lstrlenA(pstrNextArg);
  331.                nItemLen = max(1, nItemLen);
  332.             }
  333. #endif
  334.             break;
  335.         }
  336.  
  337.         case 's'|FORCE_ANSI:
  338.         case 'S'|FORCE_ANSI:
  339.         {
  340.             LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  341.             if (pstrNextArg == NULL)
  342.                nItemLen = 6; // "(null)"
  343.             else
  344.             {
  345.                nItemLen = lstrlenA(pstrNextArg);
  346.                nItemLen = max(1, nItemLen);
  347.             }
  348.             break;
  349.         }
  350.  
  351. #ifndef _MAC
  352.         case 's'|FORCE_UNICODE:
  353.         case 'S'|FORCE_UNICODE:
  354.         {
  355.             LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  356.             if (pstrNextArg == NULL)
  357.                nItemLen = 6; // "(null)"
  358.             else
  359.             {
  360.                nItemLen = wcslen(pstrNextArg);
  361.                nItemLen = max(1, nItemLen);
  362.             }
  363.             break;
  364.         }
  365. #endif
  366.         }
  367.  
  368.         // adjust nItemLen for strings
  369.         if (nItemLen != 0)
  370.         {
  371.             nItemLen = max(nItemLen, nWidth);
  372.             if (nPrecision != 0)
  373.                 nItemLen = min(nItemLen, nPrecision);
  374.         }
  375.         else
  376.         {
  377.             switch (*lpsz)
  378.             {
  379.             // integers
  380.             case 'd':
  381.             case 'i':
  382.             case 'u':
  383.             case 'x':
  384.             case 'X':
  385.             case 'o':
  386.                 va_arg(argList, int);
  387.                 nItemLen = 32;
  388.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  389.                 break;
  390.  
  391.             case 'e':
  392.             case 'f':
  393.             case 'g':
  394.             case 'G':
  395.                 va_arg(argList, DOUBLE_ARG);
  396.                 nItemLen = 128;
  397.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  398.                 break;
  399.  
  400.             case 'p':
  401.                 va_arg(argList, void*);
  402.                 nItemLen = 32;
  403.                 nItemLen = max(nItemLen, nWidth+nPrecision);
  404.                 break;
  405.  
  406.             // no output
  407.             case 'n':
  408.                 va_arg(argList, int*);
  409.                 break;
  410.  
  411.             default:
  412.                 ASSERT(FALSE);  // unknown formatting option
  413.             }
  414.         }
  415.  
  416.         // adjust nMaxLen for output nItemLen
  417.         nMaxLen += nItemLen;
  418.     }
  419.  
  420.     GetBuffer(nMaxLen);
  421.     VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
  422.     ReleaseBuffer();
  423.  
  424.     va_end(argListSave);
  425. }
  426.  
  427. // formatting (using wsprintf style formatting)
  428. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  429. {
  430.     ASSERT(AfxIsValidString(lpszFormat, FALSE));
  431.  
  432.     va_list argList;
  433.     va_start(argList, lpszFormat);
  434.     FormatV(lpszFormat, argList);
  435.     va_end(argList);
  436. }
  437.  
  438. void AFX_CDECL CString::Format(UINT nFormatID, ...)
  439. {
  440.     CString strFormat;
  441.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  442.  
  443.     va_list argList;
  444.     va_start(argList, nFormatID);
  445.     FormatV(strFormat, argList);
  446.     va_end(argList);
  447. }
  448.  
  449. #ifndef _MAC
  450. // formatting (using FormatMessage style formatting)
  451. void AFX_CDECL CString::FormatMessage(LPCTSTR lpszFormat, ...)
  452. {
  453.     // format message into temporary buffer lpszTemp
  454.     va_list argList;
  455.     va_start(argList, lpszFormat);
  456.     LPTSTR lpszTemp;
  457.  
  458.     if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  459.         lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  460.         lpszTemp == NULL)
  461.     {
  462.         AfxThrowMemoryException();
  463.     }
  464.  
  465.     // assign lpszTemp into the resulting string and free the temporary
  466.     *this = lpszTemp;
  467.     LocalFree(lpszTemp);
  468.     va_end(argList);
  469. }
  470.  
  471. void AFX_CDECL CString::FormatMessage(UINT nFormatID, ...)
  472. {
  473.     // get format string from string table
  474.     CString strFormat;
  475.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  476.  
  477.     // format message into temporary buffer lpszTemp
  478.     va_list argList;
  479.     va_start(argList, nFormatID);
  480.     LPTSTR lpszTemp;
  481.     if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  482.         strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  483.         lpszTemp == NULL)
  484.     {
  485.         AfxThrowMemoryException();
  486.     }
  487.  
  488.     // assign lpszTemp into the resulting string and free lpszTemp
  489.     *this = lpszTemp;
  490.     LocalFree(lpszTemp);
  491.     va_end(argList);
  492. }
  493. #endif //!_MAC
  494.  
  495. void CString::TrimRight()
  496. {
  497.     CopyBeforeWrite();
  498.  
  499.     // find beginning of trailing spaces by starting at beginning (DBCS aware)
  500.     LPTSTR lpsz = m_pchData;
  501.     LPTSTR lpszLast = NULL;
  502.     while (*lpsz != '\0')
  503.     {
  504.         if (_istspace(*lpsz))
  505.         {
  506.             if (lpszLast == NULL)
  507.                 lpszLast = lpsz;
  508.         }
  509.         else
  510.             lpszLast = NULL;
  511.         lpsz = _tcsinc(lpsz);
  512.     }
  513.  
  514.     if (lpszLast != NULL)
  515.     {
  516.         // truncate at trailing space start
  517.         *lpszLast = '\0';
  518.         GetData()->nDataLength = lpszLast - m_pchData;
  519.     }
  520. }
  521.  
  522. void CString::TrimLeft()
  523. {
  524.     CopyBeforeWrite();
  525.  
  526.     // find first non-space character
  527.     LPCTSTR lpsz = m_pchData;
  528.     while (_istspace(*lpsz))
  529.         lpsz = _tcsinc(lpsz);
  530.  
  531.     // fix up data and length
  532.     int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  533.     memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  534.     GetData()->nDataLength = nDataLength;
  535. }
  536.  
  537. ///////////////////////////////////////////////////////////////////////////////
  538. // CString support for template collections
  539.  
  540. #if _MSC_VER >= 1100
  541. template<> void AFXAPI ConstructElements<CString> (CString* pElements, int nCount)
  542. #else
  543. void AFXAPI ConstructElements(CString* pElements, int nCount)
  544. #endif
  545. {
  546.     ASSERT(nCount == 0 ||
  547.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  548.  
  549.     for (; nCount--; ++pElements)
  550.         memcpy(pElements, &afxEmptyString, sizeof(*pElements));
  551. }
  552.  
  553. #if _MSC_VER >= 1100
  554. template<> void AFXAPI DestructElements<CString> (CString* pElements, int nCount)
  555. #else
  556. void AFXAPI DestructElements(CString* pElements, int nCount)
  557. #endif
  558. {
  559.     ASSERT(nCount == 0 ||
  560.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  561.  
  562.     for (; nCount--; ++pElements)
  563.         pElements->~CString();
  564. }
  565.  
  566. #if _MSC_VER >= 1100
  567. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, int nCount)
  568. #else
  569. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, int nCount)
  570. #endif
  571. {
  572.     ASSERT(nCount == 0 ||
  573.         AfxIsValidAddress(pDest, nCount * sizeof(CString)));
  574.     ASSERT(nCount == 0 ||
  575.         AfxIsValidAddress(pSrc, nCount * sizeof(CString)));
  576.  
  577.     for (; nCount--; ++pDest, ++pSrc)
  578.         *pDest = *pSrc;
  579. }
  580.  
  581. #ifndef OLE2ANSI
  582. #if _MSC_VER >= 1100
  583. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
  584. #else
  585. UINT AFXAPI HashKey(LPCWSTR key)
  586. #endif
  587. {
  588.     UINT nHash = 0;
  589.     while (*key)
  590.         nHash = (nHash<<5) + nHash + *key++;
  591.     return nHash;
  592. }
  593. #endif
  594.  
  595. #if _MSC_VER >= 1100
  596. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
  597. #else
  598. UINT AFXAPI HashKey(LPCSTR key)
  599. #endif
  600. {
  601.     UINT nHash = 0;
  602.     while (*key)
  603.         nHash = (nHash<<5) + nHash + *key++;
  604.     return nHash;
  605. }
  606.  
  607. ///////////////////////////////////////////////////////////////////////////////
  608.