/////////////////////////////////////////////////////////////////////////////
-// 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 <errno.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)
{
- os << str.c_str();
- return os;
+#ifdef __BORLANDC__
+ os << str.mb_str();
+#else
+ os << str.c_str();
+#endif
+ return os;
}
#endif // wxUSE_STD_IOSTREAM
// 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();
- //anchor
- const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
- str.c_str()[0],
- length() - nStart);
+ if ( !nLenOther )
+ {
+ // empty string is a substring of anything
+ return 0;
+ }
- if(!p)
- return npos;
+ if ( !nLen )
+ {
+ // the other string is non empty so can't be our substring
+ 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;
- }
+ 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);
+
+ 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 - c_str() + str.length() <= length()) ? p - c_str() : npos;
+ 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
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;
#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;
+ }
- //Copy
- if (nRealSize)
- assign( theBuffer.data() , nRealSize - 1 );
+ size_t nLenMB;
+ wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
+
+ 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, 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
// 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;
}
// ----------------------------------------------------------------------------
// 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
+#ifndef __WATCOMC__
+
+template <typename T>
+bool wxStringToIntType(const wxChar *start,
+ T *val,
+ int base,
+ T (*func)(const wxChar *, wxChar **, int))
{
- 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();
+ errno = 0;
+
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) && (errno != ERANGE);
+}
+
+#define wxSTR2INT(val, b, func) return wxStringToIntType(c_str(), val, b, func)
+
+#else // __WATCOMC__
+
+// FIXME, TODO, ASAP !!! - ugly trick to make release for Open Watcom possible
+// without changing code flow for other compilers
+
+#define wxSTR2INT(val, base, func) \
+ wxCHECK_MSG( val, false, _T("NULL output pointer") ); \
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); \
+ \
+ errno = 0; \
+ \
+ wxChar *end; \
+ *val = (*func)(c_str(), &end, base); \
+ \
+ return !*end && (end != c_str()) && (errno != ERANGE)
+
+#endif // !__WATCOMC__/__WATCOMC__
+
+bool wxString::ToLong(long *val, int base) const
+{
+ wxSTR2INT(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") );
+ wxSTR2INT(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
+ wxSTR2INT(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
+ wxSTR2INT(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") );
+ errno = 0;
+
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) && (errno != ERANGE);
}
// ---------------------------------------------------------------------------
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)
-#if !defined(__WXMSW__) && !defined(__WXPALMOS__) && !defined( __VMS ) && !(defined(__WXMAC__) && !defined(__WXMAC_OSX__))
- || 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 )
+ {
+ // some vsnprintf() implementations NUL-terminate the buffer and
+ // some don't in len == size case, to be safe always add 1
+ size = len + 1;
+ }
+ 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)
{