/////////////////////////////////////////////////////////////////////////////
-// Name: string.cpp
+// Name: src/common/string.cpp
// Purpose: wxString class
-// Author: Vadim Zeitlin
+// Author: Vadim Zeitlin, Ryan Norton
// Modified by:
// Created: 29/01/98
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// (c) 2004 Ryan Norton <wxprojects@comcast.net>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "string.h"
-#endif
-
/*
* About ref counting:
* 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
#include "wx/wxprec.h"
#ifdef __BORLANDC__
- #pragma hdrstop
+ #pragma hdrstop
#endif
#ifndef WX_PRECOMP
- #include "wx/defs.h"
- #include "wx/string.h"
- #include "wx/intl.h"
- #include "wx/thread.h"
+ #include "wx/string.h"
+ #include "wx/intl.h"
+ #include "wx/thread.h"
#endif
#include <ctype.h>
+
+#ifndef __WXWINCE__
+ #include <errno.h>
+#endif
+
#include <string.h>
#include <stdlib.h>
#ifdef __SALFORDC__
- #include <clib.h>
+ #include <clib.h>
#endif
// allocating extra space for each string consumes more memory but speeds up
// static class variables definition
// ---------------------------------------------------------------------------
-#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
-// must define this static for VA or else you get multiply defined symbols
-// everywhere
-const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
-#endif // Visual Age
-
-#if !wxUSE_STL
- const size_t wxStringBase::npos = wxSTRING_MAXLEN;
+#if !wxUSE_STL_BASED_WXSTRING
+ //According to STL _must_ be a -1 size_t
+ const size_t wxStringBase::npos = (size_t) -1;
#endif
// ----------------------------------------------------------------------------
// static data
// ----------------------------------------------------------------------------
-#if wxUSE_STL
+#if wxUSE_STL_BASED_WXSTRING
extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
#if wxUSE_STD_IOSTREAM
-// MS Visual C++ version 5.0 provides the new STL headers as well as the old
-// iostream ones.
-//
-// ATTN: you can _not_ use both of these in the same program!
-
#include <iostream>
-wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
-{
-#if 0
- int w = is.width(0);
- if ( is.ipfx(0) ) {
- streambuf *sb = is.rdbuf();
- str.erase();
- while ( true ) {
- int ch = sb->sbumpc ();
- if ( ch == EOF ) {
- is.setstate(ios::eofbit);
- break;
- }
- else if ( isspace(ch) ) {
- sb->sungetc();
- break;
- }
-
- str += ch;
- if ( --w == 1 )
- break;
- }
- }
-
- is.isfx();
- if ( str.length() == 0 )
- is.setstate(ios::failbit);
-#endif
- return is;
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
+{
+ return os << str.c_str();
}
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
{
- os << str.c_str();
- return os;
+#if wxUSE_UNICODE && !defined(__BORLANDC__)
+ return os << str.AsWChar();
+#else
+ return os << str.AsChar();
+#endif
}
#endif // wxUSE_STD_IOSTREAM
#define STATISTICS_ADD(av, val)
#endif // WXSTRING_STATISTICS
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
// ===========================================================================
// wxStringData class deallocation
wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
return;
}
- memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
+ wxTmemcpy(m_pchData, psz + nPos, nLength);
}
}
// poor man's iterators are "void *" pointers
wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
{
- InitWith((const wxChar *)pStart, 0,
- (const wxChar *)pEnd - (const wxChar *)pStart);
+ if ( pEnd >= pStart )
+ {
+ InitWith((const wxChar *)pStart, 0,
+ (const wxChar *)pEnd - (const wxChar *)pStart);
+ }
+ else
+ {
+ wxFAIL_MSG( _T("pStart is not before pEnd") );
+ Init();
+ }
}
-wxStringBase::wxStringBase(size_type n, wxChar ch)
+wxStringBase::wxStringBase(size_type n, wxUniChar ch)
{
Init();
append(n, ch);
if ( pData == NULL ) {
// allocation failures are handled by the caller
- return FALSE;
+ return false;
}
pData->nRefs = 1;
pData->nAllocLength = nLen + EXTRA_ALLOC;
m_pchData = pData->data(); // data starts after wxStringData
m_pchData[nLen] = wxT('\0');
- return TRUE;
+ return true;
}
// must be called before changing this string
size_t nLen = pData->nDataLength;
if ( !AllocBuffer(nLen) ) {
// allocation failures are handled by the caller
- return FALSE;
+ return false;
}
- memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
+ wxTmemcpy(m_pchData, pData->data(), nLen);
}
wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
- return TRUE;
+ return true;
}
// must be called before replacing contents of this string
pData->Unlock();
if ( !AllocBuffer(nLen) ) {
// allocation failures are handled by the caller
- return FALSE;
+ return false;
}
}
else {
if ( pData == NULL ) {
// allocation failures are handled by the caller
// keep previous data since reallocation failed
- return FALSE;
+ return false;
}
pData->nAllocLength = nLen;
m_pchData = pData->data();
}
-
- // now we have enough space, just update the string length
- pData->nDataLength = nLen;
}
wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
- return TRUE;
+ // it doesn't really matter what the string length is as it's going to be
+ // overwritten later but, for extra safety, set it to 0 for now as we may
+ // have some junk in m_pchData
+ GetStringData()->nDataLength = 0;
+
+ return true;
}
-wxStringBase& wxStringBase::append(size_t n, wxChar ch)
+wxStringBase& wxStringBase::append(size_t n, wxUniChar ch)
{
size_type len = length();
- if ( !CopyBeforeWrite() || !Alloc(len + n) ) {
+ if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
}
GetStringData()->nDataLength = len + n;
return *this;
}
-void wxStringBase::resize(size_t nSize, wxChar ch)
+void wxStringBase::resize(size_t nSize, wxUniChar ch)
{
size_t len = length();
if ( pData->IsEmpty() ) {
nLen += EXTRA_ALLOC;
- wxStringData* pData = (wxStringData*)
- malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+ pData = (wxStringData *)
+ malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
if ( pData == NULL ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
pData->nRefs = 1;
size_t nOldLen = pData->nDataLength;
if ( !AllocBuffer(nLen) ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
- memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
+ // +1 to copy the terminator, too
+ memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar));
+ GetStringData()->nDataLength = nOldLen;
}
else {
nLen += EXTRA_ALLOC;
if ( pData == NULL ) {
// allocation failure handled by caller
// keep previous data since reallocation failed
- return FALSE;
+ return false;
}
// it's not important if the pointer changed or not (the check for this
}
}
//else: we've already got enough
- return TRUE;
+ return true;
+}
+
+wxStringBase::iterator wxStringBase::begin()
+{
+ if (length() > 0)
+ CopyBeforeWrite();
+ return m_pchData;
+}
+
+wxStringBase::iterator wxStringBase::end()
+{
+ if (length() > 0)
+ CopyBeforeWrite();
+ return m_pchData + length();
}
wxStringBase::iterator wxStringBase::erase(iterator it)
wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
{
- wxASSERT(nStart <= length());
- size_t strLen = length() - nStart;
- // delete nLen or up to the end of the string characters
- nLen = strLen < nLen ? strLen : nLen;
- wxString strTmp(c_str(), nStart);
- strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
+ wxASSERT(nStart <= length());
+ size_t strLen = length() - nStart;
+ // delete nLen or up to the end of the string characters
+ nLen = strLen < nLen ? strLen : nLen;
+ wxString strTmp(c_str(), nStart);
+ strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
- swap(strTmp);
- return *this;
+ swap(strTmp);
+ return *this;
}
wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
{
- wxASSERT( nPos <= length() );
+ wxASSERT( nPos <= length() );
- if ( n == npos ) n = wxStrlen(sz);
- if ( n == 0 ) return *this;
+ if ( n == npos ) n = wxStrlen(sz);
+ if ( n == 0 ) return *this;
- if ( !CopyBeforeWrite() || !Alloc(length() + n) ) {
- wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
- }
+ if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
+ }
- memmove(m_pchData + nPos + n, m_pchData + nPos,
- (length() - nPos) * sizeof(wxChar));
- memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
- GetStringData()->nDataLength = length() + n;
- m_pchData[length()] = '\0';
+ memmove(m_pchData + nPos + n, m_pchData + nPos,
+ (length() - nPos) * sizeof(wxChar));
+ memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
+ GetStringData()->nDataLength = length() + n;
+ m_pchData[length()] = '\0';
- return *this;
+ return *this;
}
void wxStringBase::swap(wxStringBase& str)
size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
{
- wxASSERT( str.GetStringData()->IsValid() );
- wxASSERT( nStart <= length() );
+ // deal with the special case of empty string first
+ const size_t nLen = length();
+ const size_t nLenOther = str.length();
+
+ if ( !nLenOther )
+ {
+ // empty string is a substring of anything
+ return 0;
+ }
+
+ if ( !nLen )
+ {
+ // the other string is non empty so can't be our substring
+ return npos;
+ }
+
+ wxASSERT( str.GetStringData()->IsValid() );
+ wxASSERT( nStart <= nLen );
+
+ const wxChar * const other = str.c_str();
+
+ // anchor
+ const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
+ *other,
+ nLen - nStart);
- const wxChar *p = wxStrstr(c_str() + nStart, str.c_str());
+ if ( !p )
+ return npos;
+
+ while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
+ {
+ p++;
+
+ // anchor again
+ p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str()));
- return p == NULL ? npos : p - c_str();
+ if ( !p )
+ return npos;
+ }
+
+ return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
}
size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
{
- return find(wxStringBase(sz, n), nStart);
+ return find(wxStringBase(sz, n), nStart);
}
-size_t wxStringBase::find(wxChar ch, size_t nStart) const
+size_t wxStringBase::find(wxUniChar ch, size_t nStart) const
{
- wxASSERT( nStart <= length() );
+ wxASSERT( nStart <= length() );
- const wxChar *p = wxStrchr(c_str() + nStart, ch);
+ const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
- return p == NULL ? npos : p - c_str();
+ return p == NULL ? npos : p - c_str();
}
size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
const wxChar *cursor = c_str() + top;
do
{
- if ( memcmp(cursor, str.c_str(),
- str.length() * sizeof(wxChar)) == 0 )
+ if ( wxTmemcmp(cursor, str.c_str(),
+ str.length()) == 0 )
{
return cursor - c_str();
}
} while ( cursor-- > c_str() );
}
-
+
return npos;
}
return rfind(wxStringBase(sz, n), nStart);
}
-size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
+size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const
{
if ( nStart == npos )
{
size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
{
- const wxChar *start = c_str() + nStart;
- const wxChar *firstOf = wxStrpbrk(start, sz);
- if ( firstOf )
- return firstOf - c_str();
- else
+ wxASSERT(nStart <= length());
+
+ size_t len = wxStrlen(sz);
+
+ size_t i;
+ for(i = nStart; i < this->length(); ++i)
+ {
+ if (wxTmemchr(sz, *(c_str() + i), len))
+ break;
+ }
+
+ if(i == this->length())
return npos;
+ else
+ return i;
}
size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart,
_T("invalid index in find_last_of()") );
}
+ size_t len = wxStrlen(sz);
+
for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
{
- if ( wxStrchr(sz, *p) )
+ if ( wxTmemchr(sz, *p, len) )
return p - c_str();
}
wxASSERT( nStart <= length() );
}
- size_t nAccept = wxStrspn(c_str() + nStart, sz);
- if ( nAccept >= length() - nStart )
- return npos;
- else
- return nStart + nAccept;
+ size_t len = wxStrlen(sz);
+
+ size_t i;
+ for(i = nStart; i < this->length(); ++i)
+ {
+ if (!wxTmemchr(sz, *(c_str() + i), len))
+ break;
+ }
+
+ if(i == this->length())
+ return npos;
+ else
+ return i;
}
size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
return find_first_not_of(wxStringBase(sz, n), nStart);
}
-size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
+size_t wxStringBase::find_first_not_of(wxUniChar ch, size_t nStart) const
{
wxASSERT( nStart <= length() );
- for ( const wxChar *p = c_str() + nStart; *p; p++ )
+ for ( const_iterator p = begin() + nStart; (bool)*p; ++p ) // FIXME-DMARS
{
if ( *p != ch )
- return p - c_str();
+ return p - begin();
}
return npos;
wxASSERT( nStart <= length() );
}
+ size_t len = wxStrlen(sz);
+
for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
{
- if ( !wxStrchr(sz, *p) )
- return p - c_str();
+ if ( !wxTmemchr(sz, *p,len) )
+ return p - c_str();
}
return npos;
return find_last_not_of(wxStringBase(sz, n), nStart);
}
-size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
+size_t wxStringBase::find_last_not_of(wxUniChar ch, size_t nStart) const
{
if ( nStart == npos )
{
wxASSERT( nStart <= length() );
}
- for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
+ for ( const_iterator p = begin() + nStart; p != begin(); --p )
{
if ( *p != ch )
- return p - c_str();
+ return p - begin();
}
return npos;
wxStringBase strTmp;
strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
- if ( nStart != 0 )
- strTmp.append(c_str(), nStart);
+ //This is kind of inefficient, but its pretty good considering...
+ //we don't want to use character access operators here because on STL
+ //it will freeze the reference count of strTmp, which means a deep copy
+ //at the end when swap is called
+ //
+ //Also, we can't use append with the full character pointer and must
+ //do it manually because this string can contain null characters
+ for(size_t i1 = 0; i1 < nStart; ++i1)
+ strTmp.append(1, this->c_str()[i1]);
+
+ //its safe to do the full version here because
+ //sz must be a normal c string
strTmp.append(sz);
- strTmp.append(c_str() + nStart + nLen);
+
+ for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
+ strTmp.append(1, this->c_str()[i2]);
swap(strTmp);
return *this;
}
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
- size_t nCount, wxChar ch)
+ size_t nCount, wxUniChar ch)
{
- return replace(nStart, nLen, wxStringBase(ch, nCount).c_str());
+ return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
}
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
}
// assigns a single character
-wxStringBase& wxStringBase::operator=(wxChar ch)
+wxStringBase& wxStringBase::operator=(wxUniChar ch)
{
- if ( !AssignCopy(1, &ch) ) {
+ wxChar c(ch);
+ if ( !AssignCopy(1, &c) ) {
wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
}
return *this;
else {
if ( !AllocBeforeWrite(nSrcLen) ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
GetStringData()->nDataLength = nSrcLen;
m_pchData[nSrcLen] = wxT('\0');
}
- return TRUE;
+ return true;
}
// ---------------------------------------------------------------------------
wxStringData* pOldData = GetStringData();
if ( !AllocBuffer(nNewLen) ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
pOldData->Unlock();
// we have to grow the buffer
if ( capacity() < nNewLen ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
}
else {
GetStringData()->nDataLength = nNewLen; // and fix the length
}
//else: the string to append was empty
- return TRUE;
+ return true;
}
// ---------------------------------------------------------------------------
else {
if ( !dest.AllocBuffer(nCopyLen) ) {
// allocation failure handled by caller
- return FALSE;
+ return false;
}
memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
}
- return TRUE;
+ return true;
}
-#endif // !wxUSE_STL
+#endif // !wxUSE_STL_BASED_WXSTRING
-#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+#if !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE)
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
#define STRINGCLASS wxStringBase
#else
#define STRINGCLASS wxString
const wxChar* s2, size_t l2)
{
if( l1 == l2 )
- return wxStrncmp(s1, s2, l1);
+ return wxTmemcmp(s1, s2, l1);
else if( l1 < l2 )
{
- int ret = wxStrncmp(s1, s2, l1);
+ int ret = wxTmemcmp(s1, s2, l1);
return ret == 0 ? -1 : ret;
}
- else if( l1 > l2 )
+ else
{
- int ret = wxStrncmp(s1, s2, l2);
+ int ret = wxTmemcmp(s1, s2, l2);
return ret == 0 ? +1 : ret;
}
-
- wxFAIL; // must never get there
- return 0; // quiet compilers
}
-#if wxUSE_STL
-
int STRINGCLASS::compare(const wxStringBase& str) const
{
return ::wxDoCmp(data(), length(), str.data(), str.length());
}
-#endif
-
int STRINGCLASS::compare(size_t nStart, size_t nLen,
const wxStringBase& str) const
{
return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
}
-#if wxUSE_STL
-
int STRINGCLASS::compare(const wxChar* sz) const
{
size_t nLen = wxStrlen(sz);
return ::wxDoCmp(data(), length(), sz, nLen);
}
-#endif
-
int STRINGCLASS::compare(size_t nStart, size_t nLen,
const wxChar* sz, size_t nCount) const
{
#undef STRINGCLASS
-#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+#endif // !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE)
// ===========================================================================
// wxString class core
// ===========================================================================
// ---------------------------------------------------------------------------
-// construction
+// construction and conversion
// ---------------------------------------------------------------------------
#if wxUSE_UNICODE
// from multibyte string
-wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
+wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength)
{
- // first get the size of the buffer we need
- size_t nLen;
- if ( psz )
- {
- // calculate the needed size ourselves or use the provided one
- nLen = nLength == npos ? conv.MB2WC(NULL, psz, 0) : nLength;
- }
- else
- {
- // nothing to convert
- nLen = 0;
- }
-
// anything to do?
- if ( (nLen != 0) && (nLen != (size_t)-1) )
+ if ( psz && nLength != 0 )
{
- if ( !Alloc(nLen) )
+ if ( nLength == npos )
{
- wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+ nLength = wxNO_LEN;
}
- else
- {
- // the input buffer to MB2WC must always be NUL-terminated
- wxCharBuffer inBuf(nLen);
- memcpy(inBuf.data(), psz, nLen);
- inBuf.data()[nLen] = '\0';
- wxWCharBuffer buf(nLen);
- // MB2WC wants the buffer size, not the string length hence +1
- nLen = conv.MB2WC(buf.data(), inBuf.data(), nLen + 1);
+ size_t nLenWide;
+ wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
- if ( nLen != (size_t)-1 )
- {
- // initialized ok, set the real length as nLength specified by
- // the caller could be greater than the real string length
- assign(buf.data(), nLen);
- return;
- }
- //else: the conversion failed -- leave the string empty (what else?)
- }
+ if ( nLenWide )
+ assign(wbuf, nLenWide);
}
}
+//Convert wxString in Unicode mode to a multi-byte string
+const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
+{
+ return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
+}
+
#else // ANSI
#if wxUSE_WCHAR_T
+
// from wide string
-wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
+wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength)
{
- // first get the size of the buffer we need
- size_t nLen;
- if ( pwz )
- {
- // calculate the needed size ourselves or use the provided one
- nLen = nLength == npos ? conv.WC2MB(NULL, pwz, 0) : nLength;
- }
- else
- {
- // nothing to convert
- nLen = 0;
- }
-
// anything to do?
- if ( (nLen != 0) && (nLen != (size_t)-1) )
+ if ( pwz && nLength != 0 )
{
- if ( !Alloc(nLen) )
+ if ( nLength == npos )
{
- wxFAIL_MSG( _T("out of memory in wxString::wxString") );
- }
- else
- {
- wxCharBuffer buf(nLen);
- // WC2MB wants the buffer size, not the string length
- if ( conv.WC2MB(buf.data(), pwz, nLen + 1) != (size_t)-1 )
- {
- // initialized ok
- assign(buf.data(), nLen);
- return;
- }
- //else: the conversion failed -- leave the string empty (what else?)
+ nLength = wxNO_LEN;
}
+
+ size_t nLenMB;
+ wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
+
+ if ( nLenMB )
+ assign(buf, nLenMB);
}
+}
- // leave empty
+//Converts this string to a wide character string if unicode
+//mode is not enabled and wxUSE_WCHAR_T is enabled
+const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
+{
+ return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
}
+
#endif // wxUSE_WCHAR_T
#endif // Unicode/ANSI
return tmp.length() == length();
}
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
// get the pointer to writable buffer of (at least) nLen bytes
-wxChar *wxString::GetWriteBuf(size_t nLen)
+wxChar *wxString::DoGetWriteBuf(size_t nLen)
{
if ( !AllocBeforeWrite(nLen) ) {
// allocation failure handled by caller
}
wxASSERT( GetStringData()->nRefs == 1 );
- GetStringData()->Validate(FALSE);
+ GetStringData()->Validate(false);
return m_pchData;
}
// put string back in a reasonable state after GetWriteBuf
+void wxString::DoUngetWriteBuf()
+{
+ DoUngetWriteBuf(wxStrlen(m_pchData));
+}
+
+void wxString::DoUngetWriteBuf(size_t nLen)
+{
+ wxStringData * const pData = GetStringData();
+
+ wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
+
+ // the strings we store are always NUL-terminated
+ pData->data()[nLen] = _T('\0');
+ pData->nDataLength = nLen;
+ pData->Validate(true);
+}
+
+// deprecated compatibility code:
+#if WXWIN_COMPATIBILITY_2_8
+wxChar *wxString::GetWriteBuf(size_t nLen)
+{
+ return DoGetWriteBuf(nLen);
+}
+
void wxString::UngetWriteBuf()
{
- GetStringData()->nDataLength = wxStrlen(m_pchData);
- GetStringData()->Validate(TRUE);
+ DoUngetWriteBuf();
}
void wxString::UngetWriteBuf(size_t nLen)
{
- GetStringData()->nDataLength = nLen;
- GetStringData()->Validate(TRUE);
+ DoUngetWriteBuf(nLen);
}
-#endif
+#endif // WXWIN_COMPATIBILITY_2_8
+
+#endif // !wxUSE_STL_BASED_WXSTRING
+
// ---------------------------------------------------------------------------
// data access
wxString operator+(const wxString& str1, const wxString& str2)
{
-#if !wxUSE_STL
- wxASSERT( str1.GetStringData()->IsValid() );
- wxASSERT( str2.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+ wxASSERT( str1.GetStringData()->IsValid() );
+ wxASSERT( str2.GetStringData()->IsValid() );
#endif
- wxString s = str1;
- s += str2;
+ wxString s = str1;
+ s += str2;
- return s;
+ return s;
}
-wxString operator+(const wxString& str, wxChar ch)
+wxString operator+(const wxString& str, wxUniChar ch)
{
-#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+ wxASSERT( str.GetStringData()->IsValid() );
#endif
- wxString s = str;
- s += ch;
+ wxString s = str;
+ s += ch;
- return s;
+ return s;
}
-wxString operator+(wxChar ch, const wxString& str)
+wxString operator+(wxUniChar ch, const wxString& str)
{
-#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+ wxASSERT( str.GetStringData()->IsValid() );
#endif
- wxString s = ch;
- s += str;
+ wxString s = ch;
+ s += str;
- return s;
+ return s;
}
wxString operator+(const wxString& str, const wxChar *psz)
{
-#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+ wxASSERT( str.GetStringData()->IsValid() );
#endif
- wxString s;
- if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
- wxFAIL_MSG( _T("out of memory in wxString::operator+") );
- }
- s = str;
- s += psz;
+ wxString s;
+ if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+ wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+ }
+ s += str;
+ s += psz;
- return s;
+ return s;
}
wxString operator+(const wxChar *psz, const wxString& str)
{
-#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+ wxASSERT( str.GetStringData()->IsValid() );
#endif
- wxString s;
- if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
- wxFAIL_MSG( _T("out of memory in wxString::operator+") );
- }
- s = psz;
- s += str;
+ wxString s;
+ if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+ wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+ }
+ s = psz;
+ s += str;
- return s;
+ return s;
}
// ===========================================================================
// other common string functions
// ===========================================================================
+int wxString::Cmp(const wxString& s) const
+{
+ return compare(s);
+}
+
+int wxString::Cmp(const wxChar* psz) const
+{
+ return compare(psz);
+}
+
+static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
+ const wxChar* s2, size_t l2)
+{
+ size_t i;
+
+ if( l1 == l2 )
+ {
+ for(i = 0; i < l1; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+ else if( l1 < l2 )
+ {
+ for(i = 0; i < l1; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+ else
+ {
+ for(i = 0; i < l2; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+}
+
+int wxString::CmpNoCase(const wxString& s) const
+{
+ return wxDoCmpNoCase(data(), length(), s.data(), s.length());
+}
+
+int wxString::CmpNoCase(const wxChar* psz) const
+{
+ int nLen = wxStrlen(psz);
+
+ return wxDoCmpNoCase(data(), length(), psz, nLen);
+}
+
+
#if wxUSE_UNICODE
+#ifdef __MWERKS__
+#ifndef __SCHAR_MAX__
+#define __SCHAR_MAX__ 127
+#endif
+#endif
+
wxString wxString::FromAscii(const char *ascii)
{
if (!ascii)
// this will allocate enough space for the terminating NUL too
wxCharBuffer buffer(length());
- signed char *dest = (signed char *)buffer.data();
+
+ char *dest = buffer.data();
const wchar_t *pwc = c_str();
for ( ;; )
{
- *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
+ *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
// the output string can't have embedded NULs anyhow, so we can safely
// stop at first of them even if we do have any
// extract string of length nCount starting at nFirst
wxString wxString::Mid(size_t nFirst, size_t nCount) const
{
- size_t nLen = length();
+ size_t nLen = length();
- // default value of nCount is npos and means "till the end"
- if ( nCount == npos )
- {
- nCount = nLen - nFirst;
- }
+ // default value of nCount is npos and means "till the end"
+ if ( nCount == npos )
+ {
+ nCount = nLen - nFirst;
+ }
- // out-of-bounds requests return sensible things
- if ( nFirst + nCount > nLen )
- {
- nCount = nLen - nFirst;
- }
+ // out-of-bounds requests return sensible things
+ if ( nFirst + nCount > nLen )
+ {
+ nCount = nLen - nFirst;
+ }
- if ( nFirst > nLen )
- {
- // AllocCopy() will return empty string
- nCount = 0;
- }
+ if ( nFirst > nLen )
+ {
+ // AllocCopy() will return empty string
+ return wxEmptyString;
+ }
- wxString dest(*this, nFirst, nCount);
- if ( dest.length() != nCount ) {
- wxFAIL_MSG( _T("out of memory in wxString::Mid") );
- }
+ wxString dest(*this, nFirst, nCount);
+ if ( dest.length() != nCount )
+ {
+ wxFAIL_MSG( _T("out of memory in wxString::Mid") );
+ }
- return dest;
+ return dest;
}
// check that the string starts with prefix and return the rest of the string
-// in the provided pointer if it is not NULL, otherwise return FALSE
+// in the provided pointer if it is not NULL, otherwise return false
bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
{
wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
if ( *prefix++ != *p++ )
{
// no match
- return FALSE;
+ return false;
}
}
*rest = p;
}
- return TRUE;
+ return true;
}
+
+// check that the string ends with suffix and return the rest of it in the
+// provided pointer if it is not NULL, otherwise return false
+bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
+{
+ wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
+
+ int start = length() - wxStrlen(suffix);
+ if ( start < 0 || wxStrcmp(wx_str() + start, suffix) != 0 )
+ return false;
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ rest->assign(*this, 0, start);
+ }
+
+ return true;
+}
+
+
// extract nCount last (rightmost) characters
wxString wxString::Right(size_t nCount) const
{
// get all characters after the last occurence of ch
// (returns the whole string if ch not found)
-wxString wxString::AfterLast(wxChar ch) const
+wxString wxString::AfterLast(wxUniChar ch) const
{
wxString str;
- int iPos = Find(ch, TRUE);
+ int iPos = Find(ch, true);
if ( iPos == wxNOT_FOUND )
str = *this;
else
- str = c_str() + iPos + 1;
+ str = wx_str() + iPos + 1;
return str;
}
// get all characters before the first occurence of ch
// (returns the whole string if ch not found)
-wxString wxString::BeforeFirst(wxChar ch) const
+wxString wxString::BeforeFirst(wxUniChar ch) const
{
int iPos = Find(ch);
if ( iPos == wxNOT_FOUND ) iPos = length();
/// get all characters before the last occurence of ch
/// (returns empty string if ch not found)
-wxString wxString::BeforeLast(wxChar ch) const
+wxString wxString::BeforeLast(wxUniChar ch) const
{
wxString str;
- int iPos = Find(ch, TRUE);
+ int iPos = Find(ch, true);
if ( iPos != wxNOT_FOUND && iPos != 0 )
str = wxString(c_str(), iPos);
/// get all characters after the first occurence of ch
/// (returns empty string if ch not found)
-wxString wxString::AfterFirst(wxChar ch) const
+wxString wxString::AfterFirst(wxUniChar ch) const
{
wxString str;
int iPos = Find(ch);
if ( iPos != wxNOT_FOUND )
- str = c_str() + iPos + 1;
+ str = wx_str() + iPos + 1;
return str;
}
// replace first (or all) occurences of some substring with another one
-size_t
-wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
+size_t wxString::Replace(const wxChar *szOld,
+ const wxChar *szNew, bool bReplaceAll)
{
// if we tried to replace an empty string we'd enter an infinite loop below
wxCHECK_MSG( szOld && *szOld && szNew, 0,
_T("wxString::Replace(): invalid parameter") );
- size_t uiCount = 0; // count of replacements made
+ size_t uiCount = 0; // count of replacements made
- size_t uiOldLen = wxStrlen(szOld);
+ size_t uiOldLen = wxStrlen(szOld);
+ size_t uiNewLen = wxStrlen(szNew);
- wxString strTemp;
- const wxChar *pCurrent = c_str();
- const wxChar *pSubstr;
- while ( *pCurrent != wxT('\0') ) {
- pSubstr = wxStrstr(pCurrent, szOld);
- if ( pSubstr == NULL ) {
- // strTemp is unused if no replacements were made, so avoid the copy
- if ( uiCount == 0 )
- return 0;
+ size_t dwPos = 0;
- strTemp += pCurrent; // copy the rest
- break; // exit the loop
- }
- else {
- // take chars before match
- size_type len = strTemp.length();
- strTemp.append(pCurrent, pSubstr - pCurrent);
- if ( strTemp.length() != (size_t)(len + pSubstr - pCurrent) ) {
- wxFAIL_MSG( _T("out of memory in wxString::Replace") );
- return 0;
- }
- strTemp += szNew;
- pCurrent = pSubstr + uiOldLen; // restart after match
+ while ( this->c_str()[dwPos] != wxT('\0') )
+ {
+ //DO NOT USE STRSTR HERE
+ //this string can contain embedded null characters,
+ //so strstr will function incorrectly
+ dwPos = find(szOld, dwPos);
+ if ( dwPos == npos )
+ break; // exit the loop
+ else
+ {
+ //replace this occurance of the old string with the new one
+ replace(dwPos, uiOldLen, szNew, uiNewLen);
- uiCount++;
+ //move up pos past the string that was replaced
+ dwPos += uiNewLen;
- // stop now?
- if ( !bReplaceAll ) {
- strTemp += pCurrent; // copy the rest
- break; // exit the loop
- }
- }
- }
+ //increase replace count
+ ++uiCount;
- // only done if there were replacements, otherwise would have returned above
- swap(strTemp);
+ // stop now?
+ if ( !bReplaceAll )
+ break; // exit the loop
+ }
+ }
- return uiCount;
+ return uiCount;
}
bool wxString::IsAscii() const
{
const wxChar *s = (const wxChar*) *this;
while(*s){
- if(!isascii(*s)) return(FALSE);
+ if(!isascii(*s)) return(false);
s++;
}
- return(TRUE);
+ return(true);
}
bool wxString::IsWord() const
{
const wxChar *s = (const wxChar*) *this;
while(*s){
- if(!wxIsalpha(*s)) return(FALSE);
+ if(!wxIsalpha(*s)) return(false);
s++;
}
- return(TRUE);
+ return(true);
}
bool wxString::IsNumber() const
{
const wxChar *s = (const wxChar*) *this;
if (wxStrlen(s))
- if ((s[0] == '-') || (s[0] == '+')) s++;
+ if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
while(*s){
- if(!wxIsdigit(*s)) return(FALSE);
+ if(!wxIsdigit(*s)) return(false);
s++;
}
- return(TRUE);
+ return(true);
}
wxString wxString::Strip(stripType w) const
{
wxString s = *this;
- if ( w & leading ) s.Trim(FALSE);
- if ( w & trailing ) s.Trim(TRUE);
+ if ( w & leading ) s.Trim(false);
+ if ( w & trailing ) s.Trim(true);
return s;
}
// trimming and padding
// ---------------------------------------------------------------------------
-// some compilers (VC++ 6.0 not to name them) return TRUE for a call to
+// some compilers (VC++ 6.0 not to name them) return true for a call to
// isspace('ê') in the C locale which seems to be broken to me, but we have to
// live with this by checking that the character is a 7 bit one - even if this
// may fail to detect some spaces (I don't know if Unicode doesn't have
// trims spaces (in the sense of isspace) from left or right side
wxString& wxString::Trim(bool bFromRight)
{
- // first check if we're going to modify the string at all
- if ( !IsEmpty() &&
- (
- (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) ||
- (!bFromRight && wxSafeIsspace(GetChar(0u)))
+ // first check if we're going to modify the string at all
+ if ( !empty() &&
+ (
+ (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
+ (!bFromRight && wxSafeIsspace(GetChar(0u)))
+ )
)
- )
- {
- if ( bFromRight )
{
- // find last non-space character
- iterator psz = begin() + length() - 1;
- while ( wxSafeIsspace(*psz) && (psz >= begin()) )
- psz--;
+ if ( bFromRight )
+ {
+ // find last non-space character
+ reverse_iterator psz = rbegin();
+ while ( (psz != rend()) && wxSafeIsspace(*psz) )
+ psz++;
- // truncate at trailing space start
- *++psz = wxT('\0');
- erase(psz, end());
- }
- else
- {
- // find first non-space character
- iterator psz = begin();
- while ( wxSafeIsspace(*psz) )
- psz++;
+ // truncate at trailing space start
+ erase(psz.base(), end());
+ }
+ else
+ {
+ // find first non-space character
+ iterator psz = begin();
+ while ( (psz != end()) && wxSafeIsspace(*psz) )
+ psz++;
- // fix up data and length
- erase(begin(), psz);
+ // fix up data and length
+ erase(begin(), psz);
+ }
}
- }
- return *this;
+ return *this;
}
// adds nCount characters chPad to the string from either side
-wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
+wxString& wxString::Pad(size_t nCount, wxUniChar chPad, bool bFromRight)
{
- wxString s(chPad, nCount);
+ wxString s(chPad, nCount);
- if ( bFromRight )
- *this += s;
- else
- {
- s += *this;
- swap(s);
- }
+ if ( bFromRight )
+ *this += s;
+ else
+ {
+ s += *this;
+ swap(s);
+ }
- return *this;
+ return *this;
}
// truncate the string
wxString& wxString::Truncate(size_t uiLen)
{
- if ( uiLen < Len() ) {
- erase(begin() + uiLen, end());
- }
- //else: nothing to do, string is already short enough
+ if ( uiLen < length() )
+ {
+ erase(begin() + uiLen, end());
+ }
+ //else: nothing to do, string is already short enough
- return *this;
+ return *this;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// find a character
-int wxString::Find(wxChar ch, bool bFromEnd) const
+int wxString::Find(wxUniChar ch, bool bFromEnd) const
{
- size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
+ size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
- return (idx == npos) ? wxNOT_FOUND : (int)idx;
+ return (idx == npos) ? wxNOT_FOUND : (int)idx;
}
// find a sub-string (like strstr)
int wxString::Find(const wxChar *pszSub) const
{
- size_type idx = find(pszSub);
+ size_type idx = find(pszSub);
- return (idx == npos) ? wxNOT_FOUND : (int)idx;
+ return (idx == npos) ? wxNOT_FOUND : (int)idx;
}
// ----------------------------------------------------------------------------
// conversion to numbers
// ----------------------------------------------------------------------------
-bool wxString::ToLong(long *val, int base) const
+// the implementation of all the functions below is exactly the same so factor
+// it out
+
+template <typename T, typename F>
+bool wxStringToIntType(const wxChar *start,
+ T *val,
+ int base,
+ F func)
{
- wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
+ wxCHECK_MSG( val, false, _T("NULL output pointer") );
wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
- const wxChar *start = c_str();
+#ifndef __WXWINCE__
+ errno = 0;
+#endif
+
wxChar *end;
- *val = wxStrtol(start, &end, base);
+ *val = (*func)(start, &end, base);
- // return TRUE only if scan was stopped by the terminating NUL and if the
- // string was not empty to start with
- return !*end && (end != start);
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with and no under/overflow occurred
+ return !*end && (end != start)
+#ifndef __WXWINCE__
+ && (errno != ERANGE)
+#endif
+ ;
+}
+
+bool wxString::ToLong(long *val, int base) const
+{
+ return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtol);
}
bool wxString::ToULong(unsigned long *val, int base) const
{
- wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
- wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+ return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoul);
+}
- const wxChar *start = c_str();
- wxChar *end;
- *val = wxStrtoul(start, &end, base);
+bool wxString::ToLongLong(wxLongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+ return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoll);
+#else
+ // TODO: implement this ourselves
+ wxUnusedVar(val);
+ wxUnusedVar(base);
+ return false;
+#endif // wxHAS_STRTOLL
+}
- // return TRUE only if scan was stopped by the terminating NUL and if the
- // string was not empty to start with
- return !*end && (end != start);
+bool wxString::ToULongLong(wxULongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+ return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoull);
+#else
+ // TODO: implement this ourselves
+ wxUnusedVar(val);
+ wxUnusedVar(base);
+ return false;
+#endif
}
bool wxString::ToDouble(double *val) const
{
- wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToDouble") );
+ wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
+
+#ifndef __WXWINCE__
+ errno = 0;
+#endif
const wxChar *start = c_str();
wxChar *end;
*val = wxStrtod(start, &end);
- // return TRUE only if scan was stopped by the terminating NUL and if the
- // string was not empty to start with
- return !*end && (end != start);
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with and no under/overflow occurred
+ return !*end && (end != start)
+#ifndef __WXWINCE__
+ && (errno != ERANGE)
+#endif
+ ;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/* static */
-wxString wxString::Format(const wxChar *pszFormat, ...)
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+wxString wxStringPrintfMixinBase::DoFormat(const wxChar *format, ...)
+#else
+wxString wxString::DoFormat(const wxChar *format, ...)
+#endif
{
va_list argptr;
- va_start(argptr, pszFormat);
+ va_start(argptr, format);
wxString s;
- s.PrintfV(pszFormat, argptr);
+ s.PrintfV(format, argptr);
va_end(argptr);
}
/* static */
-wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
+wxString wxString::FormatV(const wxString& format, va_list argptr)
{
wxString s;
- s.PrintfV(pszFormat, argptr);
+ s.PrintfV(format, argptr);
return s;
}
-int wxString::Printf(const wxChar *pszFormat, ...)
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+int wxStringPrintfMixinBase::DoPrintf(const wxChar *format, ...)
+#else
+int wxString::DoPrintf(const wxChar *format, ...)
+#endif
{
- va_list argptr;
- va_start(argptr, pszFormat);
+ va_list argptr;
+ va_start(argptr, format);
- int iLen = PrintfV(pszFormat, argptr);
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+ // get a pointer to the wxString instance; we have to use dynamic_cast<>
+ // because it's the only cast that works safely for downcasting when
+ // multiple inheritance is used:
+ wxString *str = static_cast<wxString*>(this);
+#else
+ wxString *str = this;
+#endif
- va_end(argptr);
+ int iLen = str->PrintfV(format, argptr);
+
+ va_end(argptr);
- return iLen;
+ return iLen;
}
-int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
+int wxString::PrintfV(const wxString& format, va_list argptr)
{
int size = 1024;
- int len;
for ( ;; )
{
- {
- wxStringBuffer tmp(*this, size + 1);
- wxChar* buf = tmp;
+ wxStringBuffer tmp(*this, size + 1);
+ wxChar *buf = tmp;
- if ( !buf )
- {
- // out of memory
- return -1;
- }
+ if ( !buf )
+ {
+ // out of memory
+ return -1;
+ }
- len = wxVsnprintf(buf, size, pszFormat, argptr);
+ // wxVsnprintf() may modify the original arg pointer, so pass it
+ // only a copy
+ va_list argptrcopy;
+ wxVaCopy(argptrcopy, argptr);
+ int len = wxVsnprintf(buf, size, format, argptrcopy);
+ va_end(argptrcopy);
- // some implementations of vsnprintf() don't NUL terminate
- // the string if there is not enough space for it so
- // always do it manually
- buf[size] = _T('\0');
- }
+ // some implementations of vsnprintf() don't NUL terminate
+ // the string if there is not enough space for it so
+ // always do it manually
+ buf[size] = _T('\0');
// vsnprintf() may return either -1 (traditional Unix behaviour) or the
// total number of characters which would have been written if the
- // buffer were large enough
- if ( len >= 0 && len <= size )
+ // buffer were large enough (newer standards such as Unix98)
+ if ( len < 0 )
+ {
+#if wxUSE_WXVSNPRINTF
+ // we know that our own implementation of wxVsnprintf() returns -1
+ // only for a format error - thus there's something wrong with
+ // the user's format string
+ return -1;
+#else // assume that system version only returns error if not enough space
+ // still not enough, as we don't know how much we need, double the
+ // current size of the buffer
+ size *= 2;
+#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
+ }
+ else if ( len >= size )
+ {
+#if wxUSE_WXVSNPRINTF
+ // we know that our own implementation of wxVsnprintf() returns
+ // size+1 when there's not enough space but that's not the size
+ // of the required buffer!
+ size *= 2; // so we just double the current size of the buffer
+#else
+ // some vsnprintf() implementations NUL-terminate the buffer and
+ // some don't in len == size case, to be safe always add 1
+ size = len + 1;
+#endif
+ }
+ else // ok, there was enough space
{
- // ok, there was enough space
break;
}
-
- // still not enough, double it again
- size *= 2;
}
// we could have overshot
Shrink();
- return Len();
+ return length();
}
// ----------------------------------------------------------------------------
// misc other operations
// ----------------------------------------------------------------------------
-// returns TRUE if the string matches the pattern which may contain '*' and
+// returns true if the string matches the pattern which may contain '*' and
// '?' metacharacters (as usual, '?' matches any character and '*' any number
// of them)
bool wxString::Matches(const wxChar *pszMask) const
switch ( *pszMask ) {
case wxT('?'):
if ( *pszTxt == wxT('\0') )
- return FALSE;
+ return false;
// pszTxt and pszMask will be incremented in the loop statement
// if there is nothing more, match
if ( *pszMask == wxT('\0') )
- return TRUE;
+ return true;
// are there any other metacharacters in the mask?
size_t uiLenMask;
wxString strToMatch(pszMask, uiLenMask);
const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
if ( pMatch == NULL )
- return FALSE;
+ return false;
// -1 to compensate "++" in the loop
pszTxt = pMatch + uiLenMask - 1;
default:
if ( *pszMask != *pszTxt )
- return FALSE;
+ return false;
break;
}
}
// match only if nothing left
if ( *pszTxt == wxT('\0') )
- return TRUE;
+ return true;
// if we failed to match, backtrack if we can
if ( pszLastStarInText ) {
goto match;
}
- return FALSE;
+ return false;
#endif // wxUSE_REGEX/!wxUSE_REGEX
}
// Count the number of chars
-int wxString::Freq(wxChar ch) const
+int wxString::Freq(wxUniChar ch) const
{
int count = 0;
- int len = Len();
+ int len = length();
for (int i = 0; i < len; i++)
{
if (GetChar(i) == ch)
// convert to lower case, return the copy of the string
wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
-int wxString::sprintf(const wxChar *pszFormat, ...)
- {
- va_list argptr;
- va_start(argptr, pszFormat);
- int iLen = PrintfV(pszFormat, argptr);
- va_end(argptr);
- return iLen;
- }
-
// ============================================================================
// ArrayString
// ============================================================================
#include "wx/arrstr.h"
+wxArrayString::wxArrayString(size_t sz, const wxChar** a)
+{
+#if !wxUSE_STL
+ Init(false);
+#endif
+ for (size_t i=0; i < sz; i++)
+ Add(a[i]);
+}
+
+wxArrayString::wxArrayString(size_t sz, const wxString* a)
+{
+#if !wxUSE_STL
+ Init(false);
+#endif
+ for (size_t i=0; i < sz; i++)
+ Add(a[i]);
+}
+
#if !wxUSE_STL
// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
#define ARRAY_DEFAULT_INITIAL_SIZE (16)
#endif
-#define STRING(p) ((wxString *)(&(p)))
-
// ctor
void wxArrayString::Init(bool autoSort)
{
m_nSize =
m_nCount = 0;
- m_pItems = (wxChar **) NULL;
+ m_pItems = NULL;
m_autoSort = autoSort;
}
m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
if (m_nSize < nIncrement)
m_nSize = nIncrement;
- m_pItems = new wxChar *[m_nSize];
+ m_pItems = new wxString[m_nSize];
}
else {
// otherwise when it's called for the first time, nIncrement would be 0
if ( nIncrement < ndefIncrement )
nIncrement = ndefIncrement;
m_nSize += nIncrement;
- wxChar **pNew = new wxChar *[m_nSize];
+ wxString *pNew = new wxString[m_nSize];
// copy data to new location
- memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
+ for ( size_t j = 0; j < m_nCount; j++ )
+ pNew[j] = m_pItems[j];
// delete old memory (but do not release the strings!)
wxDELETEA(m_pItems);
}
}
-void wxArrayString::Free()
-{
- for ( size_t n = 0; n < m_nCount; n++ ) {
- STRING(m_pItems[n])->GetStringData()->Unlock();
- }
-}
-
// deletes all the strings from the list
void wxArrayString::Empty()
{
- Free();
-
m_nCount = 0;
}
// as Empty, but also frees memory
void wxArrayString::Clear()
{
- Free();
-
m_nSize =
m_nCount = 0;
// dtor
wxArrayString::~wxArrayString()
{
- Free();
-
wxDELETEA(m_pItems);
}
{
// only if old buffer was not big enough
if ( nSize > m_nSize ) {
- Free();
- wxDELETEA(m_pItems);
- m_pItems = new wxChar *[nSize];
+ wxString *pNew = new wxString[nSize];
+ if ( !pNew )
+ return;
+
+ for ( size_t j = 0; j < m_nCount; j++ )
+ pNew[j] = m_pItems[j];
+ delete [] m_pItems;
+
+ m_pItems = pNew;
m_nSize = nSize;
}
-
- m_nCount = 0;
}
// minimizes the memory usage by freeing unused memory
// only do it if we have some memory to free
if( m_nCount < m_nSize ) {
// allocates exactly as much memory as we need
- wxChar **pNew = new wxChar *[m_nCount];
+ wxString *pNew = new wxString[m_nCount];
// copy data to new location
- memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
+ for ( size_t j = 0; j < m_nCount; j++ )
+ pNew[j] = m_pItems[j];
delete [] m_pItems;
m_pItems = pNew;
}
}
-#if WXWIN_COMPATIBILITY_2_4
-
-// return a wxString[] as required for some control ctors.
-wxString* wxArrayString::GetStringArray() const
-{
- wxString *array = 0;
-
- if( m_nCount > 0 )
- {
- array = new wxString[m_nCount];
- for( size_t i = 0; i < m_nCount; i++ )
- array[i] = m_pItems[i];
- }
-
- return array;
-}
-
-#endif // WXWIN_COMPATIBILITY_2_4
-
// searches the array for an item (forward or backwards)
int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
{
if ( m_nCount > 0 ) {
size_t ui = m_nCount;
do {
- if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
+ if ( m_pItems[--ui].IsSameAs(sz, bCase) )
return ui;
}
while ( ui != 0 );
}
else {
for( size_t ui = 0; ui < m_nCount; ui++ ) {
- if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
+ if( m_pItems[ui].IsSameAs(sz, bCase) )
return ui;
}
}
while ( lo < hi ) {
i = (lo + hi)/2;
- res = wxStrcmp(str, m_pItems[i]);
+ res = str.Cmp(m_pItems[i]);
if ( res < 0 )
hi = i;
else if ( res > 0 )
return (size_t)lo;
}
else {
- wxASSERT( str.GetStringData()->IsValid() );
-
Grow(nInsert);
for (size_t i = 0; i < nInsert; i++)
{
- // the string data must not be deleted!
- str.GetStringData()->Lock();
-
// just append
- m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
+ m_pItems[m_nCount + i] = str;
}
size_t ret = m_nCount;
m_nCount += nInsert;
// add item at the given position
void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
{
- wxASSERT( str.GetStringData()->IsValid() );
-
wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
wxCHECK_RET( m_nCount <= m_nCount + nInsert,
wxT("array size overflow in wxArrayString::Insert") );
Grow(nInsert);
- memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
- (m_nCount - nIndex)*sizeof(wxChar *));
+ for (int j = m_nCount - nIndex - 1; j >= 0; j--)
+ m_pItems[nIndex + nInsert + j] = m_pItems[nIndex + j];
for (size_t i = 0; i < nInsert; i++)
{
- str.GetStringData()->Lock();
- m_pItems[nIndex + i] = (wxChar *)str.c_str();
+ m_pItems[nIndex + i] = str;
}
m_nCount += nInsert;
}
+// range insert (STL 23.2.4.3)
+void
+wxArrayString::insert(iterator it, const_iterator first, const_iterator last)
+{
+ const int idx = it - begin();
+
+ // grow it once
+ Grow(last - first);
+
+ // reset "it" since it can change inside Grow()
+ it = begin() + idx;
+
+ while ( first != last )
+ {
+ it = insert(it, *first);
+
+ // insert returns an iterator to the last element inserted but we need
+ // insert the next after this one, that is before the next one
+ ++it;
+
+ ++first;
+ }
+}
+
// expand the array
void wxArrayString::SetCount(size_t count)
{
wxString s;
while ( m_nCount < count )
- m_pItems[m_nCount++] = (wxChar *)s.c_str();
+ m_pItems[m_nCount++] = s;
}
// removes item from array (by index)
wxCHECK_RET( nIndex + nRemove <= m_nCount,
wxT("removing too many elements in wxArrayString::Remove") );
- // release our lock
- for (size_t i = 0; i < nRemove; i++)
- Item(nIndex + i).GetStringData()->Unlock();
+ for ( size_t j = 0; j < m_nCount - nIndex -nRemove; j++)
+ m_pItems[nIndex + j] = m_pItems[nIndex + nRemove + j];
- memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
- (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
m_nCount -= nRemove;
}
#if wxUSE_THREADS
// need a critical section to protect access to gs_compareFunction and
// gs_sortAscending variables
- static wxCriticalSection *gs_critsectStringSort = NULL;
-
- // call this before the value of the global sort vars is changed/after
- // you're finished with them
- #define START_SORT() wxASSERT( !gs_critsectStringSort ); \
- gs_critsectStringSort = new wxCriticalSection; \
- gs_critsectStringSort->Enter()
- #define END_SORT() gs_critsectStringSort->Leave(); \
- delete gs_critsectStringSort; \
- gs_critsectStringSort = NULL
-#else // !threads
- #define START_SORT()
- #define END_SORT()
+ static wxCriticalSection gs_critsectStringSort;
#endif // wxUSE_THREADS
// function to use for string comparaison
// if we don't use the compare function, this flag tells us if we sort the
// array in ascending or descending order
-static bool gs_sortAscending = TRUE;
+static bool gs_sortAscending = true;
// function which is called by quick sort
extern "C" int wxC_CALLING_CONV // LINKAGEMODE
}
else {
// maybe we should use wxStrcoll
- int result = wxStrcmp(strFirst->c_str(), strSecond->c_str());
+ int result = strFirst->Cmp(*strSecond);
return gs_sortAscending ? result : -result;
}
// sort array elements using passed comparaison function
void wxArrayString::Sort(CompareFunction compareFunction)
{
- START_SORT();
+ wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort);
wxASSERT( !gs_compareFunction ); // must have been reset to NULL
gs_compareFunction = compareFunction;
// reset it to NULL so that Sort(bool) will work the next time
gs_compareFunction = NULL;
-
- END_SORT();
}
-typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, const void *second);
+extern "C"
+{
+ typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first,
+ const void *second);
+}
void wxArrayString::Sort(CompareFunction2 compareFunction)
{
- qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction);
+ qsort(m_pItems, m_nCount, sizeof(wxString), (wxStringCompareFn)compareFunction);
}
void wxArrayString::Sort(bool reverseOrder)
{
wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
- // just sort the pointers using qsort() - of course it only works because
- // wxString() *is* a pointer to its data
- qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
+ qsort(m_pItems, m_nCount, sizeof(wxString), wxStringCompareFunction);
}
bool wxArrayString::operator==(const wxArrayString& a) const
{
if ( m_nCount != a.m_nCount )
- return FALSE;
+ return false;
for ( size_t n = 0; n < m_nCount; n++ )
{
if ( Item(n) != a[n] )
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
#endif // !wxUSE_STL
int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2)
{
- return wxStrcmp(s1->c_str(), s2->c_str());
+ return s1->Cmp(*s2);
}
int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2)
{
- return -wxStrcmp(s1->c_str(), s2->c_str());
+ return -s1->Cmp(*s2);
+}
+
+
+
+// ===========================================================================
+// wxJoin and wxSplit
+// ===========================================================================
+
+#include "wx/tokenzr.h"
+
+wxString wxJoin(const wxArrayString& arr, const wxChar sep, const wxChar escape)
+{
+ size_t count = arr.size();
+ if ( count == 0 )
+ return wxEmptyString;
+
+ wxString str;
+
+ // pre-allocate memory using the estimation of the average length of the
+ // strings in the given array: this is very imprecise, of course, but
+ // better than nothing
+ str.reserve(count*(arr[0].length() + arr[count-1].length()) / 2);
+
+ if ( escape == wxT('\0') )
+ {
+ // escaping is disabled:
+ for ( size_t i = 0; i < count; i++ )
+ {
+ if ( i )
+ str += sep;
+ str += arr[i];
+ }
+ }
+ else // use escape character
+ {
+ for ( size_t n = 0; n < count; n++ )
+ {
+ if ( n )
+ str += sep;
+
+ for ( wxString::const_iterator i = arr[n].begin(),
+ end = arr[n].end();
+ i != end;
+ ++i )
+ {
+ const wxChar ch = *i;
+ if ( ch == sep )
+ str += escape; // escape this separator
+ str += ch;
+ }
+ }
+ }
+
+ str.Shrink(); // release extra memory if we allocated too much
+ return str;
+}
+
+wxArrayString wxSplit(const wxString& str, const wxChar sep, const wxChar escape)
+{
+ if ( escape == wxT('\0') )
+ {
+ // simple case: we don't need to honour the escape character
+ return wxStringTokenize(str, sep, wxTOKEN_RET_EMPTY_ALL);
+ }
+
+ wxArrayString ret;
+ wxString curr;
+ wxChar prev = wxT('\0');
+
+ for ( wxString::const_iterator i = str.begin(),
+ end = str.end();
+ i != end;
+ ++i )
+ {
+ const wxChar ch = *i;
+
+ if ( ch == sep )
+ {
+ if ( prev == escape )
+ {
+ // remove the escape character and don't consider this
+ // occurrence of 'sep' as a real separator
+ *curr.rbegin() = sep;
+ }
+ else // real separator
+ {
+ ret.push_back(curr);
+ curr.clear();
+ }
+ }
+ else // normal character
+ {
+ curr += ch;
+ }
+
+ prev = ch;
+ }
+
+ // add the last token
+ if ( !curr.empty() || prev == sep )
+ ret.Add(curr);
+
+ return ret;
}