/////////////////////////////////////////////////////////////////////////////
-// Name: string.cpp
+// Name: src/common/string.cpp
// Purpose: wxString class
// Author: Vadim Zeitlin, Ryan Norton
// Modified by:
#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 !wxUSE_STL
+#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)
{
-#ifdef __BORLANDC__
- os << str.mb_str();
+#if wxUSE_UNICODE && !defined(__BORLANDC__)
+ return os << str.AsWChar();
#else
- os << str.c_str();
+ return os << str.AsChar();
#endif
- return os;
}
#endif // wxUSE_STD_IOSTREAM
#define STATISTICS_ADD(av, val)
#endif // WXSTRING_STATISTICS
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
// ===========================================================================
// wxStringData class deallocation
// 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);
return true;
}
-wxStringBase& wxStringBase::append(size_t n, wxChar ch)
+wxStringBase& wxStringBase::append(size_t n, wxUniChar ch)
{
size_type len = length();
return *this;
}
-void wxStringBase::resize(size_t nSize, wxChar ch)
+void wxStringBase::resize(size_t nSize, wxUniChar ch)
{
size_t len = length();
size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
{
+ // 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 <= length() );
+ wxASSERT( nStart <= nLen );
+
+ const wxChar * const other = str.c_str();
- //anchor
+ // anchor
const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
- str.c_str()[0],
- length() - nStart);
+ *other,
+ nLen - nStart);
- if(!p)
+ if ( !p )
return npos;
- while(p - c_str() + str.length() <= length() &&
- wxTmemcmp(p, str.c_str(), str.length()) )
+ while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
{
- //Previosly passed as the first argument to wxTmemchr,
- //but C/C++ standard does not specify evaluation order
- //of arguments to functions -
- //http://embedded.com/showArticle.jhtml?articleID=9900607
- ++p;
-
- //anchor again
- p = (const wxChar*)wxTmemchr(p,
- str.c_str()[0],
- length() - (p - c_str()));
-
- if(!p)
+ p++;
+
+ // anchor again
+ p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str()));
+
+ if ( !p )
return npos;
}
- return (p - c_str() + str.length() <= length()) ? p - c_str() : 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);
}
-size_t wxStringBase::find(wxChar ch, size_t nStart) const
+size_t wxStringBase::find(wxUniChar ch, size_t nStart) const
{
wxASSERT( nStart <= length() );
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 )
{
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;
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& wxStringBase::replace(size_t nStart, size_t nLen,
- size_t nCount, wxChar ch)
+ size_t nCount, wxUniChar ch)
{
return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
}
}
// 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;
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
#undef STRINGCLASS
-#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+#endif // !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE)
// ===========================================================================
// wxString class core
{
if ( nLength == npos )
{
- nLength = (size_t)-1;
- }
- else if ( nLength == length() )
- {
- // this is important to avoid copying the string in cMB2WC: we're
- // already NUL-terminated so we can pass this NUL with the data
- nLength++;
+ nLength = wxNO_LEN;
}
size_t nLenWide;
{
if ( nLength == npos )
{
- nLength = (size_t)-1;
- }
- else if ( nLength == length() )
- {
- // this is important to avoid copying the string in cMB2WC: we're
- // already NUL-terminated so we can pass this NUL with the data
- nLength++;
+ nLength = wxNO_LEN;
}
size_t nLenMB;
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
}
// 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;
}
// ===========================================================================
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);
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);
/// 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;
}
// 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 ( !empty() &&
- (
- (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);
+ // 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") );
+#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);
+ // 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_start(argptr, format);
+
+#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
- int iLen = PrintfV(pszFormat, argptr);
+ int iLen = str->PrintfV(format, argptr);
va_end(argptr);
return iLen;
}
-int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
+int wxString::PrintfV(const wxString& format, va_list argptr)
{
int size = 1024;
// only a copy
va_list argptrcopy;
wxVaCopy(argptrcopy, argptr);
- int len = wxVsnprintf(buf, size, pszFormat, argptrcopy);
+ int len = wxVsnprintf(buf, size, format, argptrcopy);
va_end(argptrcopy);
// some implementations of vsnprintf() don't NUL terminate
// 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 )
+ else if ( len >= size )
{
- size = len;
+#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
{
// we could have overshot
Shrink();
- return Len();
+ return length();
}
// ----------------------------------------------------------------------------
}
// 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
// ============================================================================
#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;
-}
-
-void wxArrayString::Remove(size_t nIndex, size_t nRemove)
-{
- RemoveAt(nIndex, nRemove);
-}
-
-#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;
}
}
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;
}
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
// 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();
}
extern "C"
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
{
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;
+}