#endif
#include <ctype.h>
+
+#ifndef __WXWINCE__
+ #include <errno.h>
+#endif
+
#include <string.h>
#include <stdlib.h>
#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)
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 );
- //anchor
+ const wxChar * const other = str.c_str();
+
+ // 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
// put string back in a reasonable state after GetWriteBuf
void wxString::UngetWriteBuf()
{
- GetStringData()->nDataLength = wxStrlen(m_pchData);
- GetStringData()->Validate(true);
+ UngetWriteBuf(wxStrlen(m_pchData));
}
void wxString::UngetWriteBuf(size_t nLen)
{
- GetStringData()->nDataLength = nLen;
- GetStringData()->Validate(true);
+ 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);
}
-#endif
+#endif // !wxUSE_STL
// ---------------------------------------------------------------------------
// data access
if ( bFromRight )
{
// find last non-space character
- iterator psz = begin() + length() - 1;
- while ( wxSafeIsspace(*psz) && (psz >= begin()) )
- psz--;
+ reverse_iterator psz = rbegin();
+ while ( (psz != rend()) && wxSafeIsspace(*psz) )
+ psz++;
// truncate at trailing space start
- *++psz = wxT('\0');
- erase(psz, end());
+ erase(psz.base(), end());
}
else
{
// find first non-space character
iterator psz = begin();
- while ( wxSafeIsspace(*psz) )
+ while ( (psz != end()) && wxSafeIsspace(*psz) )
psz++;
// fix up data and length
// 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(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(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(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(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
+ ;
}
// ---------------------------------------------------------------------------
// current size of the buffer
size *= 2;
}
- else if ( len > size )
+ else if ( len >= size )
{
- size = len;
+ // 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
{
{
// only if old buffer was not big enough
if ( nSize > m_nSize ) {
- Free();
- wxDELETEA(m_pItems);
- m_pItems = new wxChar *[nSize];
+ wxChar **pNew = new wxChar *[nSize];
+ if ( !pNew )
+ return;
+
+ memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
+ delete [] m_pItems;
+
+ m_pItems = pNew;
m_nSize = nSize;
}
-
- m_nCount = 0;
}
// minimizes the memory usage by freeing unused memory