#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>
+// This probably isn't right, what should it be Vadim?
+// Otherwise we end up with no wxVsprintf defined.
+#ifdef __WXMOTIF__
+#define HAVE_VPRINTF
+#endif
+
+#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)
-#define EXTRA_ALLOC 16
+// NB: EXTRA_ALLOC must be >= 0!
+#define EXTRA_ALLOC (19 - nLen % 16)
// ---------------------------------------------------------------------------
// static class variables definition
// static data
// ----------------------------------------------------------------------------
-// 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
+// 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' };
+
// 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;
+
+// ----------------------------------------------------------------------------
+// conditional compilation
+// ----------------------------------------------------------------------------
+
+// we want to find out if the current platform supports vsnprintf()-like
+// function: for Unix this is done with configure, for Windows we test the
+// compiler explicitly.
+#ifdef __WXMSW__
+ #ifdef _MSC_VER
+ #define wxVsprintf _vsnprintf
+ #endif
+#else // !Windows
+ #ifdef HAVE_VSNPRINTF
+ #define wxVsprintf vsnprintf
+ #endif
+#endif // Windows/!Windows
+
+#ifndef wxVsprintf
+ // in this case we'll use vsprintf() (which is ANSI and thus should be
+ // always available), but it's unsafe because it doesn't check for buffer
+ // size - so give a warning
+ #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr)
+ #pragma message("Using sprintf() because no snprintf()-like function defined")
+#endif
// ----------------------------------------------------------------------------
// global functions
// 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
+
+#ifdef __WXMSW__
+ #ifdef _MSC_VER
+ #define wxVsprintf _vsnprintf
+ #endif
+#else
+ #if defined ( HAVE_VSNPRINTF )
+ #define wxVsprintf vsnprintf
+ #endif
+#endif
+
+#ifndef wxVsprintf
+ // vsprintf() is ANSI so we can always use it, but it's unsafe!
+ #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr)
+ #pragma message("Using sprintf() because no snprintf()-like function defined")
+#endif
NAMESPACE istream& operator>>(NAMESPACE istream& is, wxString& WXUNUSED(str))
{
{
public:
Averager(const char *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
- ~Averager()
+ ~Averager()
{ printf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
- void Add(uint n) { m_nTotal += n; m_nCount++; }
+ void Add(size_t n) { m_nTotal += n; m_nCount++; }
private:
- uint m_nCount, m_nTotal;
+ size_t m_nCount, m_nTotal;
const char *m_sz;
} g_averageLength("allocation size"),
g_averageSummandLength("summand length"),
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 ) {
if ( pData->IsShared() ) {
pData->Unlock(); // memory not freed because shared
- uint nLen = pData->nDataLength;
+ size_t nLen = pData->nDataLength;
AllocBuffer(nLen);
memcpy(m_pchData, pData->data(), nLen*sizeof(char));
}
}
// allocate enough memory for nLen characters
-void wxString::Alloc(uint nLen)
+void wxString::Alloc(size_t nLen)
{
wxStringData *pData = GetStringData();
if ( pData->nAllocLength <= nLen ) {
}
else if ( pData->IsShared() ) {
pData->Unlock(); // memory not freed because shared
- uint nOldLen = pData->nDataLength;
+ size_t nOldLen = pData->nDataLength;
AllocBuffer(nLen);
memcpy(m_pchData, pData->data(), nOldLen*sizeof(char));
}
}
// get the pointer to writable buffer of (at least) nLen bytes
-char *wxString::GetWriteBuf(uint nLen)
+char *wxString::GetWriteBuf(size_t nLen)
{
AllocBeforeWrite(nLen);
{
STATISTICS_ADD(SummandLength, nSrcLen);
- // concatenating an empty string is a NOP, but it happens quite rarely,
- // so we don't waste our time checking for it
- // if ( nSrcLen > 0 )
- wxStringData *pData = GetStringData();
- uint nLen = pData->nDataLength;
- uint nNewLen = nLen + nSrcLen;
-
- // alloc new buffer if current is too small
- if ( pData->IsShared() ) {
- STATISTICS_ADD(ConcatHit, 0);
-
- // we have to allocate another buffer
- wxStringData* pOldData = GetStringData();
- AllocBuffer(nNewLen);
- memcpy(m_pchData, pOldData->data(), nLen*sizeof(char));
- pOldData->Unlock();
- }
- else if ( nNewLen > pData->nAllocLength ) {
- STATISTICS_ADD(ConcatHit, 0);
+ // concatenating an empty string is a NOP
+ 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() ) {
+ STATISTICS_ADD(ConcatHit, 0);
+
+ // we have to allocate another buffer
+ wxStringData* pOldData = GetStringData();
+ AllocBuffer(nNewLen);
+ memcpy(m_pchData, pOldData->data(), nLen*sizeof(char));
+ pOldData->Unlock();
+ }
+ else if ( nNewLen > pData->nAllocLength ) {
+ STATISTICS_ADD(ConcatHit, 0);
- // we have to grow the buffer
- Alloc(nNewLen);
- }
- else {
- STATISTICS_ADD(ConcatHit, 1);
+ // we have to grow the buffer
+ Alloc(nNewLen);
+ }
+ else {
+ STATISTICS_ADD(ConcatHit, 1);
- // the buffer is already big enough
- }
+ // the buffer is already big enough
+ }
- // should be enough space
- wxASSERT( nNewLen <= GetStringData()->nAllocLength );
+ // should be enough space
+ wxASSERT( nNewLen <= GetStringData()->nAllocLength );
- // fast concatenation - all is done in our buffer
- memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(char));
+ // 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
+ m_pchData[nNewLen] = '\0'; // put terminating '\0'
+ GetStringData()->nDataLength = nNewLen; // and fix the length
+ }
+ //else: the string to append was empty
}
/*
}
// 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;
}
}
// 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;
// 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;
// truncate the string
wxString& wxString::Truncate(size_t uiLen)
{
- *(m_pchData + uiLen) = '\0';
- GetStringData()->nDataLength = uiLen;
+ if ( uiLen < Len() ) {
+ CopyBeforeWrite();
+
+ *(m_pchData + uiLen) = '\0';
+ GetStringData()->nDataLength = uiLen;
+ }
+ //else: nothing to do, string is already short enough
return *this;
}
return (psz == NULL) ? NOT_FOUND : psz - m_pchData;
}
+// ---------------------------------------------------------------------------
+// stream-like operators
+// ---------------------------------------------------------------------------
+wxString& wxString::operator<<(int i)
+{
+ wxString res;
+ res.Printf("%d", i);
+
+ return (*this) << res;
+}
+
+wxString& wxString::operator<<(float f)
+{
+ wxString res;
+ res.Printf("%f", f);
+
+ return (*this) << res;
+}
+
+wxString& wxString::operator<<(double d)
+{
+ wxString res;
+ res.Printf("%g", d);
+
+ return (*this) << res;
+}
+
// ---------------------------------------------------------------------------
// formatted output
// ---------------------------------------------------------------------------
int wxString::PrintfV(const char* pszFormat, va_list argptr)
{
+ // static buffer to avoid dynamic memory allocation each time
static char s_szScratch[1024];
- int iLen = vsprintf(s_szScratch, pszFormat, argptr);
+ // NB: wxVsprintf() may return either less than the buffer size or -1 if there
+ // is not enough place depending on implementation
+ int iLen = wxVsprintf(s_szScratch, WXSIZEOF(s_szScratch), pszFormat, argptr);
+ char *buffer;
+ if ( iLen < (int)WXSIZEOF(s_szScratch) ) {
+ buffer = s_szScratch;
+ }
+ else {
+ int size = WXSIZEOF(s_szScratch) * 2;
+ buffer = (char *)malloc(size);
+ while ( buffer != NULL ) {
+ iLen = wxVsprintf(buffer, WXSIZEOF(s_szScratch), pszFormat, argptr);
+ if ( iLen < size ) {
+ // ok, there was enough space
+ break;
+ }
+
+ // still not enough, double it again
+ buffer = (char *)realloc(buffer, size *= 2);
+ }
+
+ if ( !buffer ) {
+ // out of memory
+ return -1;
+ }
+ }
+
AllocBeforeWrite(iLen);
- strcpy(m_pchData, s_szScratch);
+ strcpy(m_pchData, buffer);
+
+ if ( buffer != s_szScratch )
+ free(buffer);
return iLen;
}
return TRUE;
// are there any other metacharacters in the mask?
- uint uiLenMask;
+ size_t uiLenMask;
const char *pEndMask = strpbrk(pszMask, "*?");
if ( pEndMask != NULL ) {
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;
}
{
m_nSize =
m_nCount = 0;
- m_pItems = NULL;
+ m_pItems = (char **) NULL;
}
// copy ctor
{
m_nSize =
m_nCount = 0;
- m_pItems = NULL;
+ m_pItems = (char **) NULL;
*this = src;
}
// we can't just copy the pointers here because otherwise we would share
// the strings with another array
- for ( uint n = 0; n < src.m_nCount; n++ )
+ for ( size_t n = 0; n < src.m_nCount; n++ )
Add(src[n]);
if ( m_nCount != 0 )
{
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;
}
}
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;
}
{
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();
// 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();
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