#endif
#include <ctype.h>
+#include <errno.h>
#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 );
+
+ 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
// 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);
}
// ---------------------------------------------------------------------------
// 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
{