/////////////////////////////////////////////////////////////////////////////
-// 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>
#include <string.h>
#include <stdlib.h>
-#ifndef __WXMSW__
-#include <errno.h>
-#endif
-
#ifdef __SALFORDC__
- #include <clib.h>
+ #include <clib.h>
#endif
// allocating extra space for each string consumes more memory but speeds up
#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)
{
#ifdef __BORLANDC__
// 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)
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
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 ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
- 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;
+ }
- //anchor
- const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
- str.c_str()[0],
- length() - nStart);
+ wxASSERT( str.GetStringData()->IsValid() );
+ wxASSERT( nStart <= nLen );
- if(!p)
- return npos;
+ const wxChar * const other = str.c_str();
- while(p - c_str() + str.length() <= length() &&
- wxTmemcmp(p, str.c_str(), str.length()) )
- {
- //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)
- return npos;
- }
+ // anchor
+ const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
+ *other,
+ nLen - nStart);
+
+ if ( !p )
+ return npos;
+
+ while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
+ {
+ p++;
- return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
+ // anchor again
+ p = (const wxChar*)wxTmemchr(p, *other, nLen - (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
{
- wxASSERT( nStart <= length() );
+ wxASSERT( nStart <= length() );
- const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
+ 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
#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)
{
- // if nLength != npos, then we have to make a NULL-terminated copy
- // of first nLength bytes of psz first because the input buffer to MB2WC
- // must always be NULL-terminated:
- wxCharBuffer inBuf((const char *)NULL);
- if (nLength != npos)
- {
- wxASSERT( psz != NULL );
- wxCharBuffer tmp(nLength);
- memcpy(tmp.data(), psz, nLength);
- tmp.data()[nLength] = '\0';
- inBuf = tmp;
- psz = inBuf.data();
- }
-
- // first get the size of the buffer we need
- size_t nLen;
- if ( psz )
- {
- // calculate the needed size ourselves or use the provided one
- if (nLength == npos)
- nLen = strlen(psz);
- else
- nLen = nLength;
- }
- else
- {
- // nothing to convert
- nLen = 0;
- }
-
-
// anything to do?
- if ( (nLen != 0) && (nLen != (size_t)-1) )
+ if ( psz && nLength != 0 )
{
- //Convert string
- size_t nRealSize;
- wxWCharBuffer theBuffer = conv.cMB2WC(psz, nLen, &nRealSize);
+ if ( nLength == npos )
+ {
+ nLength = wxNO_LEN;
+ }
+
+ size_t nLenWide;
+ wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
- //Copy
- if (nRealSize)
- assign( theBuffer.data() , nRealSize - 1 );
+ if ( nLenWide )
+ assign(wbuf, nLenWide);
}
}
//Convert wxString in Unicode mode to a multi-byte string
-const wxCharBuffer wxString::mb_str(wxMBConv& conv) const
+const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
{
- size_t dwOutSize;
- return conv.cWC2MB(c_str(), length(), &dwOutSize);
+ 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)
{
- // if nLength != npos, then we have to make a NULL-terminated copy
- // of first nLength chars of psz first because the input buffer to WC2MB
- // must always be NULL-terminated:
- wxWCharBuffer inBuf((const wchar_t *)NULL);
- if (nLength != npos)
- {
- wxASSERT( pwz != NULL );
- wxWCharBuffer tmp(nLength);
- memcpy(tmp.data(), pwz, nLength * sizeof(wchar_t));
- tmp.data()[nLength] = '\0';
- inBuf = tmp;
- pwz = inBuf.data();
- }
-
- // first get the size of the buffer we need
- size_t nLen;
- if ( pwz )
- {
- // calculate the needed size ourselves or use the provided one
- if (nLength == npos)
- nLen = wxWcslen(pwz);
- else
- nLen = nLength;
- }
- else
- {
- // nothing to convert
- nLen = 0;
- }
-
// anything to do?
- if ( (nLen != 0) && (nLen != (size_t)-1) )
+ if ( pwz && nLength != 0 )
{
- //Convert string
- size_t nRealSize;
- wxCharBuffer theBuffer = conv.cWC2MB(pwz, nLen, &nRealSize);
+ if ( nLength == npos )
+ {
+ nLength = wxNO_LEN;
+ }
+
+ size_t nLenMB;
+ wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
- //Copy
- if (nRealSize)
- assign( theBuffer.data() , nRealSize - 1 );
+ if ( nLenMB )
+ assign(buf, nLenMB);
}
}
//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(wxMBConv& conv) const
+const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
{
- size_t dwOutSize;
- return conv.cMB2WC(c_str(), length(), &dwOutSize);
+ return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
}
#endif // wxUSE_WCHAR_T
wxString operator+(const wxString& str1, const wxString& str2)
{
#if !wxUSE_STL
- wxASSERT( str1.GetStringData()->IsValid() );
- wxASSERT( str2.GetStringData()->IsValid() );
+ 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)
{
#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+ 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)
{
#if !wxUSE_STL
- wxASSERT( str.GetStringData()->IsValid() );
+ 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() );
+ 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() );
+ 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(c_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
{
// 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--;
-
- // truncate at trailing space start
- *++psz = wxT('\0');
- erase(psz, end());
- }
- else
{
- // find first non-space character
- iterator psz = begin();
- while ( wxSafeIsspace(*psz) )
- psz++;
+ if ( bFromRight )
+ {
+ // find last non-space character
+ reverse_iterator psz = rbegin();
+ while ( (psz != rend()) && 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 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
{
- 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;
}
// ----------------------------------------------------------------------------
for ( ;; )
{
wxStringBuffer tmp(*this, size + 1);
- wxChar* buf = tmp;
+ wxChar *buf = tmp;
if ( !buf )
{
// 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 )
{
- // ok, there was enough space
- break;
+ // still not enough, as we don't know how much we need, double the
+ // current size of the buffer
+ size *= 2;
}
-
-#ifdef EOVERFLOW
- // if the error is not due to not having enough space (it could be e.g.
- // EILSEQ), break too -- we'd just eat all available memory uselessly
- if ( errno != EOVERFLOW )
+ else if ( len > size )
+ {
+ size = len;
+ }
+ else // ok, there was enough space
{
- // no sense in continuing
break;
}
-#endif // EOVERFLOW
-
- // still not enough, double it again
- size *= 2;
}
// we could have overshot
Shrink();
- return Len();
+ return length();
}
// ----------------------------------------------------------------------------
int wxString::Freq(wxChar ch) const
{
int count = 0;
- int len = Len();
+ int len = length();
for (int i = 0; i < len; i++)
{
if (GetChar(i) == ch)
#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();
}
-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)
{