]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
no message
[wxWidgets.git] / src / common / string.cpp
index bb02779aee932d74d9adbe243a52801147348506..70fdb635e1785ea8a705afe5808b679c184983af 100644 (file)
 #endif
 
 #ifndef WX_PRECOMP
-#include "wx/defs.h"
-#include "wx/string.h"
+  #include "wx/defs.h"
+  #include "wx/string.h"
+  #include "wx/intl.h"
 #endif
 
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
 
+#ifdef wxUSE_WCSRTOMBS
+  #include <wchar.h>    // for wcsrtombs(), see comments where it's used
+#endif // GNU
+
 #ifdef  WXSTRING_IS_WXOBJECT
   IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
 #endif  //WXSTRING_IS_WXOBJECT
 
+// allocating extra space for each string consumes more memory but speeds up
+// the concatenation operations (nLen is the current string's length)
+// NB: EXTRA_ALLOC must be >= 0!
+#define EXTRA_ALLOC       (19 - nLen % 16)
+
 // ---------------------------------------------------------------------------
 // static class variables definition
 // ---------------------------------------------------------------------------
   const size_t wxString::npos = STRING_MAXLEN;
 #endif
 
-// ===========================================================================
-// static class data, special inlines
-// ===========================================================================
+// ----------------------------------------------------------------------------
+// static data
+// ----------------------------------------------------------------------------
+
+// for an empty string, GetStringData() will return this address: this
+// structure has the same layout as wxStringData and it's data() method will
+// return the empty string (dummy pointer)
+static const struct
+{
+  wxStringData data;
+  char dummy;
+} g_strEmpty = { {-1, 0, 0}, '\0' };
 
-// for an empty string, GetStringData() will return this address
-static int g_strEmpty[] = { -1,     // ref count (locked)
-                             0,     // current length
-                             0,     // allocated memory
-                             0 };   // string data
 // empty C style string: points to 'string data' byte of g_strEmpty
-extern const char *g_szNul = (const char *)(&g_strEmpty[3]);
+extern const char *g_szNul = &g_strEmpty.dummy;
 
-// ===========================================================================
+// ----------------------------------------------------------------------------
 // global functions
-// ===========================================================================
+// ----------------------------------------------------------------------------
 
 #ifdef  STD_STRING_COMPATIBILITY
 
@@ -74,13 +88,19 @@ extern const char *g_szNul = (const char *)(&g_strEmpty[3]);
 // iostream ones.
 //
 // ATTN: you can _not_ use both of these in the same program!
-#if 0 // def  _MSC_VER
-  #include  <iostream>
-  #define   NAMESPACE   std::
+#if wxUSE_IOSTREAMH
+#include <iostream.h>
+#define   NAMESPACE
 #else
-  #include  <iostream.h>
-  #define   NAMESPACE
-#endif  //Visual C++
+#include <iostream>
+#  ifdef _MSC_VER
+      using namespace std;
+#  endif
+// for msvc (bcc50+ also) you don't need these NAMESPACE defines,
+// using namespace std; takes care of that.
+#define   NAMESPACE   std::
+#endif
+
 
 NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
 {
@@ -115,6 +135,35 @@ NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
 
 #endif  //std::string compatibility
 
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+// this small class is used to gather statistics for performance tuning
+//#define WXSTRING_STATISTICS
+#ifdef  WXSTRING_STATISTICS
+  class Averager
+  {
+  public:
+    Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
+   ~Averager()
+   { printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
+
+    void Add(size_t n) { m_nTotal += n; m_nCount++; }
+
+  private:
+    size_t m_nCount, m_nTotal;
+    const char *m_sz;
+  } g_averageLength("allocation size"),
+    g_averageSummandLength("summand length"),
+    g_averageConcatHit("hit probability in concat"),
+    g_averageInitialLength("initial string length");
+
+  #define STATISTICS_ADD(av, val) g_average##av.Add(val)
+#else
+  #define STATISTICS_ADD(av, val)
+#endif // WXSTRING_STATISTICS
+
 // ===========================================================================
 // wxString class core
 // ===========================================================================
@@ -123,27 +172,6 @@ NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
 // construction
 // ---------------------------------------------------------------------------
 
-// construct an empty string
-wxString::wxString()
-{
-  Init();
-}
-
-// copy constructor
-wxString::wxString(const wxString& stringSrc)
-{
-  wxASSERT( stringSrc.GetStringData()->IsValid() );
-
-  if ( stringSrc.IsEmpty() ) {
-    // nothing to do for an empty string
-    Init();
-  }
-  else {
-    m_pchData = stringSrc.m_pchData;            // share same data
-    GetStringData()->Lock();                    // => one more copy
-  }
-}
-
 // constructs string of <nLength> copies of character <ch>
 wxString::wxString(char ch, size_t nLength)
 {
@@ -168,6 +196,8 @@ void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
   if ( nLength == STRING_MAXLEN )
     nLength = Strlen(psz + nPos);
 
+  STATISTICS_ADD(InitialLength, nLength);
+
   if ( nLength > 0 ) {
     // trailing '\0' is written in AllocBuffer()
     AllocBuffer(nLength);
@@ -175,13 +205,6 @@ void wxString::InitWith(const char *psz, size_t nPos, size_t nLength)
   }
 }
 
-// take first nLength characters of C string psz
-// (default value of STRING_MAXLEN means take all the string)
-wxString::wxString(const char *psz, size_t nLength)
-{
-  InitWith(psz, 0, nLength);
-}
-
 // the same as previous constructor, but for compilers using unsigned char
 wxString::wxString(const unsigned char* psz, size_t nLength)
 {
@@ -190,14 +213,6 @@ wxString::wxString(const unsigned char* psz, size_t nLength)
 
 #ifdef  STD_STRING_COMPATIBILITY
 
-// ctor from a substring
-wxString::wxString(const wxString& str, size_t nPos, size_t nLen)
-{
-  wxASSERT( str.GetStringData()->IsValid() );
-
-  InitWith(str.c_str(), nPos, nLen == npos ? 0 : nLen);
-}
-
 // poor man's iterators are "void *" pointers
 wxString::wxString(const void *pStart, const void *pEnd)
 {
@@ -211,7 +226,17 @@ wxString::wxString(const void *pStart, const void *pEnd)
 wxString::wxString(const wchar_t *pwz)
 {
   // first get necessary size
-  size_t nLen = wcstombs(NULL, pwz, 0);
+
+  // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't
+  //     honor the 3rd parameter, thus it will happily crash here).
+#ifdef wxUSE_WCSRTOMBS
+  // don't know if it's really needed (or if we can pass NULL), but better safe
+  // than quick
+  mbstate_t mbstate;  
+  size_t nLen = wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
+#else  // !GNU libc
+  size_t nLen = wcstombs((char *) NULL, pwz, 0);
+#endif // GNU
 
   // empty?
   if ( nLen != 0 ) {
@@ -233,16 +258,18 @@ void wxString::AllocBuffer(size_t nLen)
   wxASSERT( nLen >  0         );    //
   wxASSERT( nLen <= INT_MAX-1 );    // max size (enough room for 1 extra)
 
+  STATISTICS_ADD(Length, nLen);
+
   // allocate memory:
   // 1) one extra character for '\0' termination
   // 2) sizeof(wxStringData) for housekeeping info
-  wxStringData* pData = (wxStringData*)malloc(sizeof(wxStringData) +
-                                              (nLen + 1)*sizeof(char));
+  wxStringData* pData = (wxStringData*)
+    malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(char));
   pData->nRefs        = 1;
-  pData->data()[nLen] = '\0';
   pData->nDataLength  = nLen;
-  pData->nAllocLength = nLen;
+  pData->nAllocLength = nLen + EXTRA_ALLOC;
   m_pchData           = pData->data();  // data starts after wxStringData
+  m_pchData[nLen]     = '\0';
 }
 
 // must be called before changing this string
@@ -252,11 +279,12 @@ void wxString::CopyBeforeWrite()
 
   if ( pData->IsShared() ) {
     pData->Unlock();                // memory not freed because shared
-    AllocBuffer(pData->nDataLength);
-    memcpy(m_pchData, pData->data(), (pData->nDataLength + 1)*sizeof(char));
+    size_t nLen = pData->nDataLength;
+    AllocBuffer(nLen);
+    memcpy(m_pchData, pData->data(), nLen*sizeof(char));
   }
 
-  wxASSERT( !pData->IsShared() );  // we must be the only owner
+  wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
 }
 
 // must be called before replacing contents of this string
@@ -265,7 +293,7 @@ void wxString::AllocBeforeWrite(size_t nLen)
   wxASSERT( nLen != 0 );  // doesn't make any sense
 
   // must not share string and must have enough space
-  register wxStringData* pData = GetStringData();
+  wxStringData* pData = GetStringData();
   if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
     // can't work with old buffer, get new one
     pData->Unlock();
@@ -276,25 +304,42 @@ void wxString::AllocBeforeWrite(size_t nLen)
 }
 
 // allocate enough memory for nLen characters
-void wxString::Alloc(uint nLen)
+void wxString::Alloc(size_t nLen)
 {
   wxStringData *pData = GetStringData();
   if ( pData->nAllocLength <= nLen ) {
-    if ( pData->IsEmpty() )
+    if ( pData->IsEmpty() ) {
+      nLen += EXTRA_ALLOC;
+
+      wxStringData* pData = (wxStringData*)
+        malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(char));
+      pData->nRefs = 1;
+      pData->nDataLength = 0;
+      pData->nAllocLength = nLen;
+      m_pchData = pData->data();  // data starts after wxStringData
+      m_pchData[0u] = '\0';
+    }
+    else if ( pData->IsShared() ) {
+      pData->Unlock();                // memory not freed because shared
+      size_t nOldLen = pData->nDataLength;
       AllocBuffer(nLen);
+      memcpy(m_pchData, pData->data(), nOldLen*sizeof(char));
+    }
     else {
+      nLen += EXTRA_ALLOC;
+
       wxStringData *p = (wxStringData *)
         realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(char));
-      if ( p != NULL && p != pData ) {
-        // the call succeeded but the pointer changed
-        pData->Unlock();
-        free(pData);
-
-        p->nRefs = 1;
-        p->nAllocLength = nLen;
-        m_pchData = p->data();
+
+      if ( p == NULL ) {
+        // @@@ what to do on memory error?
+        return;
       }
-      //else: do nothing: either the call failed or the pointer is unchanged
+
+      // it's not important if the pointer changed or not (the check for this
+      // is not faster than assigning to m_pchData in all cases)
+      p->nAllocLength = nLen;
+      m_pchData = p->data();
     }
   }
   //else: we've already got enough
@@ -304,15 +349,20 @@ void wxString::Alloc(uint nLen)
 void wxString::Shrink()
 {
   wxStringData *pData = GetStringData();
-  void *p = realloc(pData, sizeof(wxStringData) +
-                    (pData->nDataLength + 1)*sizeof(char));
-  if ( p == NULL )  // huh? can't unallocate memory? unlikely but possible.
-    return;
+
+  // this variable is unused in release build, so avoid the compiler warning by
+  // just not declaring it
+#ifdef __WXDEBUG__
+  void *p =
+#endif
+  realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(char));
+
+  wxASSERT( p != NULL );  // can't free memory?
   wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
 }
 
 // get the pointer to writable buffer of (at least) nLen bytes
-char *wxString::GetWriteBuf(uint nLen)
+char *wxString::GetWriteBuf(size_t nLen)
 {
   AllocBeforeWrite(nLen);
 
@@ -329,12 +379,6 @@ void wxString::UngetWriteBuf()
   GetStringData()->Validate(TRUE);
 }
 
-// dtor frees memory if no other strings use it
-wxString::~wxString()
-{
-  GetStringData()->Unlock();
-}
-
 // ---------------------------------------------------------------------------
 // data access
 // ---------------------------------------------------------------------------
@@ -412,47 +456,49 @@ wxString& wxString::operator=(const wchar_t *pwz)
 // string concatenation
 // ---------------------------------------------------------------------------
 
-// concatenate two sources
-// NB: assume that 'this' is a new wxString object
-void wxString::ConcatCopy(int nSrc1Len, const char *pszSrc1Data,
-                          int nSrc2Len, const char *pszSrc2Data)
-{
-  int nNewLen = nSrc1Len + nSrc2Len;
-  if ( nNewLen != 0 )
-  {
-    AllocBuffer(nNewLen);
-    memcpy(m_pchData, pszSrc1Data, nSrc1Len*sizeof(char));
-    memcpy(m_pchData + nSrc1Len, pszSrc2Data, nSrc2Len*sizeof(char));
-  }
-}
-
 // add something to this string
 void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
 {
+  STATISTICS_ADD(SummandLength, nSrcLen);
+
   // concatenating an empty string is a NOP
-  if ( nSrcLen != 0 ) {
-    register wxStringData *pData = GetStringData();
+  if ( nSrcLen > 0 ) {
+    wxStringData *pData = GetStringData();
+    size_t nLen = pData->nDataLength;
+    size_t nNewLen = nLen + nSrcLen;
 
     // alloc new buffer if current is too small
-    if ( pData->IsShared() ||
-         pData->nDataLength + nSrcLen > pData->nAllocLength ) {
-      // we have to grow the buffer, use the ConcatCopy routine
-      // (which will allocate memory)
+    if ( pData->IsShared() ) {
+      STATISTICS_ADD(ConcatHit, 0);
+
+      // we have to allocate another buffer
       wxStringData* pOldData = GetStringData();
-      ConcatCopy(pOldData->nDataLength, m_pchData, nSrcLen, pszSrcData);
+      AllocBuffer(nNewLen);
+      memcpy(m_pchData, pOldData->data(), nLen*sizeof(char));
       pOldData->Unlock();
     }
-    else {
-      // fast concatenation when buffer big enough
-      memcpy(m_pchData + pData->nDataLength, pszSrcData, nSrcLen*sizeof(char));
-      pData->nDataLength += nSrcLen;
+    else if ( nNewLen > pData->nAllocLength ) {
+      STATISTICS_ADD(ConcatHit, 0);
 
-      // should be enough space
-      wxASSERT( pData->nDataLength <= pData->nAllocLength );
+      // we have to grow the buffer
+      Alloc(nNewLen);
+    }
+    else {
+      STATISTICS_ADD(ConcatHit, 1);
 
-      m_pchData[pData->nDataLength] = '\0';   // put terminating '\0'
+      // the buffer is already big enough
     }
+
+    // should be enough space
+    wxASSERT( nNewLen <= GetStringData()->nAllocLength );
+
+    // fast concatenation - all is done in our buffer
+    memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char));
+
+    m_pchData[nNewLen] = '\0';              // put terminating '\0'
+    GetStringData()->nDataLength = nNewLen; // and fix the length
   }
+  //else: the string to append was empty
 }
 
 /*
@@ -467,18 +513,19 @@ wxString operator+(const wxString& string1, const wxString& string2)
   wxASSERT( string1.GetStringData()->IsValid() );
   wxASSERT( string2.GetStringData()->IsValid() );
 
-  wxString s;
-  s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData,
-               string2.GetStringData()->nDataLength, string2.m_pchData);
+  wxString s = string1;
+  s += string2;
+
   return s;
 }
 
-wxString operator+(const wxString& string1, char ch)
+wxString operator+(const wxString& string, char ch)
 {
-  wxASSERT( string1.GetStringData()->IsValid() );
+  wxASSERT( string.GetStringData()->IsValid() );
+
+  wxString s = string;
+  s += ch;
 
-  wxString s;
-  s.ConcatCopy(string1.GetStringData()->nDataLength, string1.m_pchData, 1, &ch);
   return s;
 }
 
@@ -486,8 +533,9 @@ wxString operator+(char ch, const wxString& string)
 {
   wxASSERT( string.GetStringData()->IsValid() );
 
-  wxString s;
-  s.ConcatCopy(1, &ch, string.GetStringData()->nDataLength, string.m_pchData);
+  wxString s = ch;
+  s += string;
+
   return s;
 }
 
@@ -496,8 +544,10 @@ wxString operator+(const wxString& string, const char *psz)
   wxASSERT( string.GetStringData()->IsValid() );
 
   wxString s;
-  s.ConcatCopy(string.GetStringData()->nDataLength, string.m_pchData,
-               Strlen(psz), psz);
+  s.Alloc(Strlen(psz) + string.Len());
+  s = string;
+  s += psz;
+
   return s;
 }
 
@@ -506,8 +556,10 @@ wxString operator+(const char *psz, const wxString& string)
   wxASSERT( string.GetStringData()->IsValid() );
 
   wxString s;
-  s.ConcatCopy(Strlen(psz), psz,
-               string.GetStringData()->nDataLength, string.m_pchData);
+  s.Alloc(Strlen(psz) + string.Len());
+  s = psz;
+  s += string;
+
   return s;
 }
 
@@ -522,32 +574,42 @@ wxString operator+(const char *psz, const wxString& string)
 // helper function: clone the data attached to this string
 void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
 {
-  if ( nCopyLen == 0 )
-  {
+  if ( nCopyLen == 0 ) {
     dest.Init();
   }
-  else
-  {
+  else {
     dest.AllocBuffer(nCopyLen);
     memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(char));
   }
 }
 
 // extract string of length nCount starting at nFirst
-// default value of nCount is 0 and means "till the end"
 wxString wxString::Mid(size_t nFirst, size_t nCount) const
 {
+  wxStringData *pData = GetStringData();
+  size_t nLen = pData->nDataLength;
+
+  // default value of nCount is STRING_MAXLEN and means "till the end"
+  if ( nCount == STRING_MAXLEN )
+  {
+    nCount = nLen - nFirst;
+  }
+
   // out-of-bounds requests return sensible things
-  if ( nCount == 0 )
-    nCount = GetStringData()->nDataLength - nFirst;
+  if ( nFirst + nCount > nLen )
+  {
+    nCount = nLen - nFirst;
+  }
 
-  if ( nFirst + nCount > (size_t)GetStringData()->nDataLength )
-    nCount = GetStringData()->nDataLength - nFirst;
-  if ( nFirst > (size_t)GetStringData()->nDataLength )
+  if ( nFirst > nLen )
+  {
+    // AllocCopy() will return empty string
     nCount = 0;
+  }
 
   wxString dest;
   AllocCopy(dest, nCount, nFirst);
+
   return dest;
 }
 
@@ -623,11 +685,11 @@ wxString wxString::After(char ch) const
 }
 
 // replace first (or all) occurences of some substring with another one
-uint wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
+size_t wxString::Replace(const char *szOld, const char *szNew, bool bReplaceAll)
 {
-  uint uiCount = 0;   // count of replacements made
+  size_t uiCount = 0;   // count of replacements made
 
-  uint uiOldLen = Strlen(szOld);
+  size_t uiOldLen = Strlen(szOld);
 
   wxString strTemp;
   const char *pCurrent = m_pchData;
@@ -733,30 +795,40 @@ wxString& wxString::MakeLower()
 // trims spaces (in the sense of isspace) from left or right side
 wxString& wxString::Trim(bool bFromRight)
 {
-  CopyBeforeWrite();
-
-  if ( bFromRight )
-  {
-    // find last non-space character
-    char *psz = m_pchData + GetStringData()->nDataLength - 1;
-    while ( isspace(*psz) && (psz >= m_pchData) )
-      psz--;
-
-    // truncate at trailing space start
-    *++psz = '\0';
-    GetStringData()->nDataLength = psz - m_pchData;
-  }
-  else
+  // first check if we're going to modify the string at all
+  if ( !IsEmpty() && 
+       ( 
+        (bFromRight && isspace(GetChar(Len() - 1))) ||
+        (!bFromRight && isspace(GetChar(0u)))
+       )
+     )
   {
-    // find first non-space character
-    const char *psz = m_pchData;
-    while ( isspace(*psz) )
-      psz++;
-
-    // fix up data and length
-    int nDataLength = GetStringData()->nDataLength - (psz - m_pchData);
-    memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char));
-    GetStringData()->nDataLength = nDataLength;
+    // ok, there is at least one space to trim
+    CopyBeforeWrite();
+
+    if ( bFromRight )
+    {
+      // find last non-space character
+      char *psz = m_pchData + GetStringData()->nDataLength - 1;
+      while ( isspace(*psz) && (psz >= m_pchData) )
+        psz--;
+
+      // truncate at trailing space start
+      *++psz = '\0';
+      GetStringData()->nDataLength = psz - m_pchData;
+    }
+    else
+    {
+      // find first non-space character
+      const char *psz = m_pchData;
+      while ( isspace(*psz) )
+        psz++;
+
+      // fix up data and length
+      int nDataLength = GetStringData()->nDataLength - (psz - m_pchData);
+      memmove(m_pchData, psz, (nDataLength + 1)*sizeof(char));
+      GetStringData()->nDataLength = nDataLength;
+    }
   }
 
   return *this;
@@ -833,30 +905,6 @@ int wxString::PrintfV(const char* pszFormat, va_list argptr)
   return iLen;
 }
 
-#if 0
-int wxString::Scanf(const char *pszFormat, ...) const
-{
-  va_list argptr;
-  va_start(argptr, pszFormat);
-
-  int iLen = ScanfV(pszFormat, argptr);
-
-  va_end(argptr);
-
-  return iLen;
-}
-
-int wxString::ScanfV(const char *pszFormat, va_list argptr) const
-{
-#ifdef __WXMSW__
-  wxMessageBox("ScanfV not implemented");
-  return 0;
-#else
-  return vsscanf(c_str(), pszFormat, argptr);
-#endif
-}
-#endif
-
 // ----------------------------------------------------------------------------
 // misc other operations
 // ----------------------------------------------------------------------------
@@ -885,7 +933,7 @@ bool wxString::Matches(const char *pszMask) const
             return TRUE;
 
           // are there any other metacharacters in the mask?
-          uint uiLenMask;
+          size_t uiLenMask;
           const char *pEndMask = strpbrk(pszMask, "*?");
 
           if ( pEndMask != NULL ) {
@@ -929,13 +977,15 @@ wxString& wxString::insert(size_t nPos, const wxString& str)
   wxASSERT( str.GetStringData()->IsValid() );
   wxASSERT( nPos <= Len() );
 
-  wxString strTmp;
-  char *pc = strTmp.GetWriteBuf(Len() + str.Len());
-  strncpy(pc, c_str(), nPos);
-  strcpy(pc + nPos, str);
-  strcpy(pc + nPos + str.Len(), c_str() + nPos);
-  strTmp.UngetWriteBuf();
-  *this = strTmp;
+  if ( !str.IsEmpty() ) {
+    wxString strTmp;
+    char *pc = strTmp.GetWriteBuf(Len() + str.Len());
+    strncpy(pc, c_str(), nPos);
+    strcpy(pc + nPos, str);
+    strcpy(pc + nPos + str.Len(), c_str() + nPos);
+    strTmp.UngetWriteBuf();
+    *this = strTmp;
+  }
 
   return *this;
 }
@@ -1074,36 +1124,32 @@ wxArrayString::wxArrayString()
 {
   m_nSize  =
   m_nCount = 0;
-  m_pItems = NULL;
+  m_pItems = (char **) NULL;
 }
 
 // copy ctor
 wxArrayString::wxArrayString(const wxArrayString& src)
 {
-  m_nSize  = src.m_nSize;
-  m_nCount = src.m_nCount;
-
-  if ( m_nSize != 0 )
-    m_pItems = new char *[m_nSize];
-  else
-    m_pItems = NULL;
+  m_nSize  =
+  m_nCount = 0;
+  m_pItems = (char **) NULL;
 
-  if ( m_nCount != 0 )
-    memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
+  *this = src;
 }
 
-// copy operator
+// assignment operator
 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
 {
-  DELETEA(m_pItems);
+  if ( m_nSize > 0 )
+    Clear();
 
-  m_nSize  = src.m_nSize;
-  m_nCount = src.m_nCount;
+  if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
+    Alloc(src.m_nCount);
 
-  if ( m_nSize != 0 )
-    m_pItems = new char *[m_nCount];
-  else
-    m_pItems = NULL;
+  // we can't just copy the pointers here because otherwise we would share
+  // the strings with another array
+  for ( size_t n = 0; n < src.m_nCount; n++ )
+    Add(src[n]);
 
   if ( m_nCount != 0 )
     memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(char *));
@@ -1122,8 +1168,13 @@ void wxArrayString::Grow()
       m_pItems = new char *[m_nSize];
     }
     else {
+      // otherwise when it's called for the first time, nIncrement would be 0
+      // and the array would never be expanded
+      wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE != 0 );
+
       // add 50% but not too much
-      size_t nIncrement = m_nSize >> 1;
+      size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
+                          ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
       if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
         nIncrement = ARRAY_MAXSIZE_INCREMENT;
       m_nSize += nIncrement;
@@ -1133,7 +1184,7 @@ void wxArrayString::Grow()
       memcpy(pNew, m_pItems, m_nCount*sizeof(char *));
 
       // delete old memory (but do not release the strings!)
-      DELETEA(m_pItems);
+      wxDELETEA(m_pItems);
 
       m_pItems = pNew;
     }
@@ -1163,8 +1214,7 @@ void wxArrayString::Clear()
   m_nSize  =
   m_nCount = 0;
 
-  DELETEA(m_pItems);
-  m_pItems = NULL;
+  wxDELETEA(m_pItems);
 }
 
 // dtor
@@ -1172,7 +1222,7 @@ wxArrayString::~wxArrayString()
 {
   Free();
 
-  DELETEA(m_pItems);
+  wxDELETEA(m_pItems);
 }
 
 // pre-allocates memory (frees the previous data!)
@@ -1183,7 +1233,7 @@ void wxArrayString::Alloc(size_t nSize)
   // only if old buffer was not big enough
   if ( nSize > m_nSize ) {
     Free();
-    DELETEA(m_pItems);
+    wxDELETEA(m_pItems);
     m_pItems = new char *[nSize];
     m_nSize  = nSize;
   }
@@ -1192,14 +1242,11 @@ void wxArrayString::Alloc(size_t nSize)
 }
 
 // searches the array for an item (forward or backwards)
-
-// Robert Roebling (changed to bool from bool)
-
 int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
 {
   if ( bFromEnd ) {
     if ( m_nCount > 0 ) {
-      uint ui = m_nCount;
+      size_t ui = m_nCount;
       do {
         if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
           return ui;
@@ -1208,7 +1255,7 @@ int wxArrayString::Index(const char *sz, bool bCase, bool bFromEnd) const
     }
   }
   else {
-    for( uint ui = 0; ui < m_nCount; ui++ ) {
+    for( size_t ui = 0; ui < m_nCount; ui++ ) {
       if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
         return ui;
     }
@@ -1234,7 +1281,7 @@ void wxArrayString::Insert(const wxString& str, size_t nIndex)
 {
   wxASSERT( str.GetStringData()->IsValid() );
 
-  wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Insert" );
+  wxCHECK_RET( nIndex <= m_nCount, ("bad index in wxArrayString::Insert") );
 
   Grow();
 
@@ -1250,7 +1297,7 @@ void wxArrayString::Insert(const wxString& str, size_t nIndex)
 // removes item from array (by index)
 void wxArrayString::Remove(size_t nIndex)
 {
-  wxCHECK_RET( nIndex <= m_nCount, "bad index in wxArrayString::Remove" );
+  wxCHECK_RET( nIndex <= m_nCount, _("bad index in wxArrayString::Remove") );
 
   // release our lock
   Item(nIndex).GetStringData()->Unlock();
@@ -1266,14 +1313,14 @@ void wxArrayString::Remove(const char *sz)
   int iIndex = Index(sz);
 
   wxCHECK_RET( iIndex != NOT_FOUND,
-               "removing inexistent element in wxArrayString::Remove" );
+               _("removing inexistent element in wxArrayString::Remove") );
 
-  Remove((size_t)iIndex);
+  Remove(iIndex);
 }
 
 // sort array elements using passed comparaison function
 
-void wxArrayString::Sort(bool bCase, bool bReverse)
+void wxArrayString::Sort(bool WXUNUSED(bCase), bool WXUNUSED(bReverse) )
 {
   //@@@@ TO DO
   //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);