/////////////////////////////////////////////////////////////////////////////
-// 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
wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
{
- os << str.c_str();
- return os;
+#ifdef __BORLANDC__
+ os << str.mb_str();
+#else
+ os << str.c_str();
+#endif
+ return os;
}
#endif // wxUSE_STD_IOSTREAM
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() );
+ wxASSERT( str.GetStringData()->IsValid() );
+ wxASSERT( nStart <= length() );
- //anchor
- const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
- str.c_str()[0],
- length() - nStart);
+ //anchor
+ const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
+ str.c_str()[0],
+ length() - nStart);
- if(!p)
- return npos;
+ if(!p)
+ return npos;
- 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;
- }
+ 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;
- return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
+ //anchor again
+ p = (const wxChar*)wxTmemchr(p,
+ str.c_str()[0],
+ length() - (p - c_str()));
+
+ if(!p)
+ return npos;
+ }
+
+ return (p - c_str() + str.length() <= length()) ? 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
//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);
#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;
+ }
- //Copy
- if (nRealSize)
- assign( theBuffer.data() , nRealSize - 1 );
+ size_t nLenWide;
+ wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
+
+ 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;
}
// ===========================================================================
// 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
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
{
}
// replace first (or all) occurences of some substring with another one
-size_t wxString::Replace(const wxChar *szOld,
+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
size_t dwPos = 0;
- while ( this->c_str()[dwPos] != wxT('\0') )
+ 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 )
+ if ( dwPos == npos )
break; // exit the loop
- else
+ else
{
//replace this occurance of the old string with the new one
replace(dwPos, uiOldLen, szNew, uiNewLen);
//increase replace count
++uiCount;
-
+
// stop now?
- if ( !bReplaceAll )
+ if ( !bReplaceAll )
break; // exit the loop
}
}
// 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
- // also, it may return an errno may be something like EILSEQ,
- // in which case we need to break out
- if ( (len >= 0 && len <= size)
- // No EOVERFLOW on Windows nor Palm 6.0 nor OpenVMS nor MacOS (not X)
- // not OS/2 (not Innotek libc).
-#if !defined(__WXMSW__) && !defined(__WXPALMOS__) && !defined( __VMS ) && !(defined(__WXMAC__) && !defined(__WXMAC_OSX__)) && !(defined(__EMX__) && !defined(__INNOTEK_LIBC__))
- || errno != EOVERFLOW
-#endif
- )
+ // buffer were large enough (newer standards such as Unix98)
+ if ( len < 0 )
+ {
+ // still not enough, as we don't know how much we need, double the
+ // current size of the buffer
+ size *= 2;
+ }
+ else if ( len > size )
+ {
+ size = len;
+ }
+ 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();
}
// ----------------------------------------------------------------------------
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)
{