home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / prefs / nsdlg / src / cstring.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.4 KB  |  467 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "pch.h"
  20. #ifdef _WIN32
  21. #include <tchar.h>
  22. #endif
  23. #include <assert.h>
  24. #include "cstring.h"
  25.  
  26. #ifndef _WIN32
  27. // CoTaskMemAlloc uses the default OLE allocator to allocate a memory
  28. // block in the same way that IMalloc::Alloc does
  29. LPVOID NEAR
  30. CoTaskMemAlloc(ULONG cb)
  31. {
  32.     LPMALLOC pMalloc;
  33.      
  34.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
  35.         LPVOID    lpv = pMalloc->Alloc(cb);
  36.  
  37.         pMalloc->Release();
  38.         return lpv;
  39.     }
  40.  
  41.     return NULL;
  42. }
  43.  
  44. // CoTaskMemRealloc changes the size of a previously allocated memory
  45. // block in the same way that IMalloc::Realloc does
  46. LPVOID NEAR
  47. CoTaskMemRealloc(LPVOID lpv, ULONG cb)
  48. {
  49.     LPMALLOC    pMalloc;
  50.     
  51.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
  52.         lpv = pMalloc->Realloc(lpv, cb);
  53.         pMalloc->Release();
  54.         return lpv;
  55.     }
  56.  
  57.     return NULL;
  58. }
  59.  
  60. // CoTaskMemFree uses the default OLE allocator to free a block of
  61. // memory previously allocated through a call to CoTaskMemAlloc
  62. void NEAR
  63. CoTaskMemFree(LPVOID lpv)
  64. {
  65.     if (lpv) {
  66.         LPMALLOC    pMalloc;
  67.     
  68.         if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
  69.             pMalloc->Free(lpv);
  70.             pMalloc->Release();
  71.         }
  72.     }
  73. }
  74. #endif
  75.  
  76. // Used as m_pchData for all empty strings
  77. static char g_chNil = '\0';
  78.  
  79. #ifndef _WIN32
  80. #if defined(DEBUG_blythe)
  81. //  Watch DBCS code from now on.
  82. static BOOL    g_bDBCS = TRUE;
  83. #else
  84. static BOOL    g_bDBCS = GetSystemMetrics(SM_DBCSENABLED);
  85. #endif
  86. #endif
  87.  
  88. void
  89. CString::Init()
  90. {
  91.     m_nDataLength = m_nAllocLength = 0;
  92.     m_pchData = &g_chNil;
  93. }
  94.  
  95. CString::CString(const CString& str)
  96. {
  97.     Init();
  98.     AssignCopy(str.m_pchData, str.m_nDataLength);
  99. }
  100.  
  101. CString::CString(LPCSTR lpsz)
  102. {
  103.     Init();
  104.     AssignCopy(lpsz, -1);
  105. }
  106.  
  107. #ifdef _WIN32
  108. CString::CString(LPOLESTR lpsz)
  109. {
  110.     Init();
  111.     AssignCopy(lpsz);
  112. }
  113. #endif
  114.  
  115. CString::CString(LPCSTR lpsz, int nLen)
  116. {
  117.     Init();
  118.     AssignCopy(lpsz, nLen);
  119. }
  120.  
  121. CString::CString(LPCSTR lpszSrc1, int nSrc1Len, LPCSTR lpszSrc2, int nSrc2Len)
  122. {
  123.     Init();
  124.     AllocBuffer(nSrc1Len + nSrc2Len);
  125.     memcpy(m_pchData, lpszSrc1, nSrc1Len);
  126.     memcpy(&m_pchData[nSrc1Len], lpszSrc2, nSrc2Len);
  127. }
  128.  
  129. void
  130. CString::AllocBuffer(int nLen)
  131. {
  132.     if (nLen == 0) {
  133.         Init();
  134.  
  135.     } else {
  136.         // allocate one extra character for '\0' terminator
  137.         m_pchData = (LPSTR)CoTaskMemAlloc(nLen + 1);
  138.         m_pchData[nLen] = '\0';
  139.         m_nDataLength = m_nAllocLength = nLen;
  140.     }
  141. }
  142.  
  143. void
  144. CString::Empty()
  145. {
  146.     if (m_nAllocLength > 0)
  147.         CoTaskMemFree(m_pchData);
  148.     Init();
  149. }
  150.  
  151. CString::~CString()
  152. {
  153.     if (m_nAllocLength > 0)
  154.         CoTaskMemFree(m_pchData);
  155. }
  156.  
  157. void
  158. CString::AssignCopy(LPCSTR lpszSrcData, int nSrcLen)
  159. {
  160.     // nSrcLen of -1 means we should measure
  161.     if (nSrcLen < 0)
  162.         nSrcLen = lpszSrcData ? lstrlen(lpszSrcData) : 0;
  163.  
  164.     // check if it will fit in the existing buffer
  165.     if (nSrcLen > m_nAllocLength) {
  166.         // won't fit so allocate another buffer
  167.         Empty();
  168.         AllocBuffer(nSrcLen);
  169.     }
  170.  
  171.     if (nSrcLen != 0)
  172.         memcpy(m_pchData, lpszSrcData, nSrcLen);
  173.     m_nDataLength = nSrcLen;
  174.     m_pchData[m_nDataLength] = '\0';
  175. }
  176.  
  177. #ifdef _WIN32
  178. void
  179. CString::AssignCopy(LPOLESTR lpsz)
  180. {
  181.     int    nBytes;
  182.  
  183.     // see how many bytes we need for the buffer
  184.     nBytes = lpsz ? WideCharToMultiByte(CP_ACP, 0, lpsz, -1, NULL, 0, NULL, NULL) : 0;
  185.  
  186.     // don't include the null terminator in the number of bytes
  187.     if (nBytes > 0)
  188.         nBytes--;
  189.  
  190.     // check if it will fit in the existing buffer
  191.     if (nBytes > m_nAllocLength) {
  192.         // won't fit so allocate another buffer
  193.         Empty();
  194.         AllocBuffer(nBytes);
  195.     }
  196.  
  197.     if (nBytes > 0)
  198.         WideCharToMultiByte(CP_ACP, 0, lpsz, -1, m_pchData, nBytes, NULL, NULL);
  199.     m_nDataLength = nBytes;
  200.     m_pchData[m_nDataLength] = '\0';
  201. }
  202. #endif
  203.         
  204. // Overloaded assignment
  205. const CString&
  206. CString::operator =(const CString& str)
  207. {
  208.     AssignCopy(str.m_pchData, str.m_nDataLength);
  209.     return *this;
  210. }
  211.  
  212. const CString&
  213. CString::operator =(LPCSTR lpsz)
  214. {
  215.     AssignCopy(lpsz, -1);
  216.     return *this;
  217. }
  218.  
  219. const CString&
  220. CString::operator =(char ch)
  221. {
  222.     AssignCopy(&ch, 1);
  223.     return *this;
  224. }
  225.  
  226. #ifdef _WIN32
  227. const CString &
  228. CString::operator =(LPOLESTR lpsz)
  229. {
  230.     AssignCopy(lpsz);
  231.     return *this;
  232. }
  233. #endif
  234.  
  235. // String concatenation
  236. CString
  237. operator +(const CString& str1, const CString& str2)
  238. {
  239.     return CString(str1.m_pchData, str1.m_nDataLength, str2.m_pchData, str2.m_nDataLength);
  240. }
  241.  
  242. CString
  243. operator +(const CString& str, LPCSTR lpsz)
  244. {
  245.     return CString(str.m_pchData, str.m_nDataLength, lpsz, lpsz ? lstrlen(lpsz) : 0);
  246. }
  247.  
  248. CString
  249. operator +(LPCSTR lpsz, const CString& str)
  250. {
  251.     return CString(lpsz, lpsz ? lstrlen(lpsz) : 0, str.m_pchData, str.m_nDataLength);
  252. }
  253.  
  254. CString
  255. operator +(const CString& str, char ch)
  256. {
  257.     return CString(str.m_pchData, str.m_nDataLength, &ch, 1);
  258. }
  259.  
  260. CString
  261. operator +(char ch, const CString& str)
  262. {
  263.     return CString(&ch, 1, str.m_pchData, str.m_nDataLength);
  264. }
  265.  
  266. void
  267. CString::ConcatInPlace(LPCSTR lpszSrc, int nSrcLen)
  268. {
  269.     if (nSrcLen > 0) {
  270.         int    nNewAllocLength = m_nDataLength + nSrcLen;
  271.  
  272.         if (nNewAllocLength > m_nAllocLength) {
  273.             if (m_nAllocLength == 0) {
  274.                 m_pchData = (LPSTR)CoTaskMemAlloc(nNewAllocLength + 1);
  275.             
  276.             } else {
  277.                 // realloc the existing memory
  278.                 m_pchData = (LPSTR)CoTaskMemRealloc(m_pchData, nNewAllocLength + 1);
  279.             }
  280.  
  281.             m_nAllocLength = nNewAllocLength;
  282.         }
  283.     
  284.         memcpy(&m_pchData[m_nDataLength], lpszSrc, nSrcLen);
  285.         m_nDataLength += nSrcLen;
  286.         m_pchData[m_nDataLength] = '\0';
  287.     }
  288. }
  289.  
  290. const CString&
  291. CString::operator +=(LPCSTR lpsz)
  292. {
  293.     ConcatInPlace(lpsz, lpsz ? lstrlen(lpsz) : 0);
  294.     return *this;
  295. }
  296.  
  297. const CString&
  298. CString::operator +=(char ch)
  299. {
  300.     ConcatInPlace(&ch, 1);
  301.     return *this;
  302. }
  303.  
  304. const CString&
  305. CString::operator +=(const CString& str)
  306. {
  307.     ConcatInPlace(str.m_pchData, str.m_nDataLength);
  308.     return *this;
  309. }
  310.  
  311. // Searching (return starting index, or -1 if not found)
  312. // look for a single character match
  313. int
  314. CString::Find(char ch) const
  315. {
  316.     LPSTR    lpsz;
  317.  
  318. #ifdef _WIN32
  319.     lpsz = _tcschr(m_pchData, ch);
  320. #else
  321.     assert(!IsDBCSLeadByte(ch));
  322.     
  323.     // Visual C++ 1.52 runtime has no multi-byte aware version
  324.     // of strchr
  325.     if (g_bDBCS) {
  326.         if (ch == '\0')
  327.             lpsz = m_pchData + m_nDataLength;
  328.  
  329.         else {
  330.             // Use the MBCS routine to step through the characters
  331.             for (lpsz = m_pchData; *lpsz; lpsz = AnsiNext(lpsz)) {
  332.                 if (*lpsz == ch)
  333.                     break;
  334.             }
  335.             if (*lpsz == '\0') {
  336.                 lpsz = NULL; // No match.
  337.             }
  338.         }
  339.  
  340.     } else {
  341.         lpsz = strchr(m_pchData, ch);
  342.     }
  343. #endif
  344.     
  345.     return lpsz == NULL ? -1 : (int)(lpsz - m_pchData);
  346. }
  347.  
  348. int
  349. CString::ReverseFind(char ch) const
  350. {
  351.     LPSTR    lpsz;
  352.  
  353. #ifdef _WIN32
  354.     // This routine is multi-byte aware
  355.     lpsz = _tcsrchr(m_pchData, (_TUCHAR)ch);
  356. #else
  357.     assert(!IsDBCSLeadByte(ch));
  358.  
  359.     // Visual C++ 1.52 runtime has no multi-byte aware version
  360.     // of strrchr
  361.     if (g_bDBCS) {
  362.         LPSTR    lpszLast = NULL;
  363.  
  364.         // Walk forward through the string remembering the last
  365.         // match
  366.         for (lpsz = m_pchData; *lpsz; lpsz = AnsiNext(lpsz)) {
  367.             if (*lpsz == ch)
  368.                 lpszLast = lpsz;
  369.         }
  370.  
  371.         lpsz = lpszLast;
  372.  
  373.     } else {
  374.         lpsz = strrchr(m_pchData, ch);
  375.     }
  376. #endif
  377.     
  378.     return lpsz == NULL ? -1 : (int)(lpsz - m_pchData);
  379. }
  380.  
  381. // Simple sub-string extraction
  382. CString
  383. CString::Mid(int nFirst) const
  384. {
  385.     return Mid(nFirst, m_nDataLength - nFirst);
  386. }
  387.  
  388. CString
  389. CString::Mid(int nFirst, int nCount) const
  390. {
  391.     assert(nFirst >= 0);
  392.     assert(nCount >= 0);
  393.  
  394.     // out-of-bounds requests return sensible things
  395.     if (nFirst > m_nDataLength)
  396.         nFirst = m_nDataLength;
  397.     if (nFirst + nCount > m_nDataLength)
  398.         nCount = m_nDataLength - nFirst;
  399.  
  400.     return CString(m_pchData + nFirst, nCount);
  401. }
  402.  
  403. CString CString::Right(int nCount) const
  404. {
  405.     assert(nCount >= 0);
  406.  
  407.     if (nCount > m_nDataLength)
  408.         nCount = m_nDataLength;
  409.  
  410.     return CString(m_pchData + m_nDataLength - nCount, nCount);
  411. }
  412.  
  413. CString CString::Left(int nCount) const
  414. {
  415.     assert(nCount >= 0);
  416.  
  417.     if (nCount > m_nDataLength)
  418.         nCount = m_nDataLength;
  419.  
  420.     return CString(m_pchData, nCount);
  421. }
  422.  
  423. // Load from string resource
  424. BOOL
  425. CString::LoadString(HINSTANCE hInstance, UINT nID)
  426. {
  427.     char    buf[256];
  428.     int        nLen;
  429.  
  430.     nLen = ::LoadString(hInstance, nID, buf, sizeof(buf));
  431.     if (nLen == 0)
  432.         return FALSE;  // resource does not exist
  433.  
  434.     AssignCopy(buf, nLen);
  435.     return TRUE;
  436. }
  437.  
  438. // Set string from window text
  439. BOOL
  440. CString::GetWindowText(HWND hwnd)
  441. {
  442.     int    nLen = GetWindowTextLength(hwnd);
  443.  
  444.     if (nLen > m_nAllocLength) {
  445.         Empty();
  446.         AllocBuffer(nLen);
  447.     }
  448.  
  449.     m_nDataLength = ::GetWindowText(hwnd, m_pchData, m_nAllocLength + 1);
  450.     return TRUE;
  451. }
  452.  
  453. LPSTR
  454. CString::BufferSetLength(int nNewLength)
  455. {
  456.     assert(nNewLength >= 0);
  457.  
  458.     if (nNewLength > m_nAllocLength) {
  459.         Empty();
  460.         AllocBuffer(nNewLength);
  461.     }
  462.     
  463.     m_nDataLength = nNewLength;
  464.     m_pchData[nNewLength] = '\0';
  465.     return m_pchData;
  466. }
  467.