wxChar dummy;
} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
+#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
+// must define this static for VA or else you get multiply defined symbols everywhere
+const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
+
+#endif
+
// empty C style string: points to 'string data' byte of g_strEmpty
extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy;
// function wxVsnprintfA (A for ANSI), should also find one for Unicode
// strings in Unicode build
#ifdef __WXMSW__
- #ifdef __VISUALC__
+ #if defined(__VISUALC__) || (defined(__MINGW32__) && wxUSE_NORLANDER_HEADERS)
#define wxVsnprintfA _vsnprintf
#endif
#else // !Windows
return iLen;
#else // ANSI
- return wxVsnprintfA(buf, len, format, argptr);
+ // vsnprintf() will not terminate the string with '\0' if there is not
+ // enough place, but we want the string to always be NUL terminated
+ int rc = wxVsnprintfA(buf, len - 1, format, argptr);
+ if ( rc == -1 )
+ {
+ buf[len] = 0;
+ }
+
+ return rc;
#endif // Unicode/ANSI
}
{
Init();
- wxASSERT( nPos <= wxStrlen(psz) );
+ // if the length is not given, assume the string to be NUL terminated
+ if ( nLength == wxSTRING_MAXLEN ) {
+ wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
- if ( nLength == wxSTRING_MAXLEN )
nLength = wxStrlen(psz + nPos);
+ }
STATISTICS_ADD(InitialLength, nLength);
#if wxUSE_WCHAR_T
// from wide string
-wxString::wxString(const wchar_t *pwz)
+wxString::wxString(const wchar_t *pwz, wxMBConv& conv)
{
// first get necessary size
- size_t nLen = pwz ? wxWC2MB((char *) NULL, pwz, 0) : 0;
+ size_t nLen = pwz ? conv.WC2MB((char *) NULL, pwz, 0) : 0;
// empty?
if ( (nLen != 0) && (nLen != (size_t)-1) ) {
AllocBuffer(nLen);
- wxWC2MB(m_pchData, pwz, nLen);
+ conv.WC2MB(m_pchData, pwz, nLen);
}
else {
Init();
// allocates memory needed to store a C string of length nLen
void wxString::AllocBuffer(size_t nLen)
{
- wxASSERT( nLen > 0 ); //
- wxASSERT( nLen <= INT_MAX-1 ); // max size (enough room for 1 extra)
+ // allocating 0 sized buffer doesn't make sense, all empty strings should
+ // reuse g_strEmpty
+ wxASSERT( nLen > 0 );
+
+ // make sure that we don't overflow
+ wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
+ (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
STATISTICS_ADD(Length, nLen);
// must not share string and must have enough space
wxStringData* pData = GetStringData();
- if ( pData->IsShared() || (nLen > pData->nAllocLength) ) {
+ if ( pData->IsShared() || pData->IsEmpty() ) {
// can't work with old buffer, get new one
pData->Unlock();
AllocBuffer(nLen);
}
else {
- // update the string length
+ if ( nLen > pData->nAllocLength ) {
+ // realloc the buffer instead of calling malloc() again, this is more
+ // efficient
+ STATISTICS_ADD(Length, nLen);
+
+ nLen += EXTRA_ALLOC;
+
+ wxStringData *pDataOld = pData;
+ pData = (wxStringData*)
+ realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+ if ( !pData ) {
+ // out of memory
+ free(pDataOld);
+
+ // FIXME we're going to crash...
+ return;
+ }
+
+ pData->nAllocLength = nLen;
+ m_pchData = pData->data();
+ }
+
+ // now we have enough space, just update the string length
pData->nDataLength = nLen;
}
else {
nLen += EXTRA_ALLOC;
+ wxStringData *pDataOld = pData;
wxStringData *p = (wxStringData *)
realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
if ( p == NULL ) {
- // @@@ what to do on memory error?
+ // don't leak memory
+ free(pDataOld);
+
+ // FIXME what to do on memory error?
return;
}
{
wxStringData *pData = GetStringData();
- // this variable is unused in release build, so avoid the compiler warning by
- // just not declaring it
+ // this variable is unused in release build, so avoid the compiler warning
+ // by just not declaring it
#ifdef __WXDEBUG__
void *p =
#endif
realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(wxChar));
+ // we rely on a reasonable realloc() implementation here - so far I haven't
+ // seen any which wouldn't behave like this
+
wxASSERT( p != NULL ); // can't free memory?
wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
}
GetStringData()->Validate(TRUE);
}
+void wxString::UngetWriteBuf(size_t nLen)
+{
+ GetStringData()->nDataLength = nLen;
+ GetStringData()->Validate(TRUE);
+}
+
// ---------------------------------------------------------------------------
// data access
// ---------------------------------------------------------------------------
return dest;
}
+// check that the tring starts with prefix and return the rest of the string
+// in the provided pointer if it is not NULL, otherwise return FALSE
+bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
+{
+ wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
+
+ // first check if the beginning of the string matches the prefix: note
+ // that we don't have to check that we don't run out of this string as
+ // when we reach the terminating NUL, either prefix string ends too (and
+ // then it's ok) or we break out of the loop because there is no match
+ const wxChar *p = c_str();
+ while ( *prefix )
+ {
+ if ( *prefix++ != *p++ )
+ {
+ // no match
+ return FALSE;
+ }
+ }
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ *rest = p;
+ }
+
+ return TRUE;
+}
+
// extract nCount last (rightmost) characters
wxString wxString::Right(size_t nCount) const
{
bool wxString::IsNumber() const
{
const wxChar *s = (const wxChar*) *this;
+ if (wxStrlen(s))
+ if ((s[0] == '-') || (s[0] == '+')) s++;
while(*s){
if(!wxIsdigit(*s)) return(FALSE);
s++;
return (psz == NULL) ? wxNOT_FOUND : psz - (const wxChar*) m_pchData;
}
-// ---------------------------------------------------------------------------
-// stream-like operators
-// ---------------------------------------------------------------------------
-wxString& wxString::operator<<(int i)
+// ----------------------------------------------------------------------------
+// conversion to numbers
+// ----------------------------------------------------------------------------
+
+bool wxString::ToLong(long *val) const
{
- wxString res;
- res.Printf(wxT("%d"), i);
+ wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
+
+ const wxChar *start = c_str();
+ wxChar *end;
+ *val = wxStrtol(start, &end, 10);
- return (*this) << res;
+ // 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);
}
-wxString& wxString::operator<<(float f)
+bool wxString::ToULong(unsigned long *val) const
{
- wxString res;
- res.Printf(wxT("%f"), f);
+ wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
+
+ const wxChar *start = c_str();
+ wxChar *end;
+ *val = wxStrtoul(start, &end, 10);
- return (*this) << res;
+ // 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);
}
-wxString& wxString::operator<<(double d)
+bool wxString::ToDouble(double *val) const
{
- wxString res;
- res.Printf(wxT("%g"), d);
+ wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToDouble") );
- return (*this) << res;
+ 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);
}
// ---------------------------------------------------------------------------
// formatted output
// ---------------------------------------------------------------------------
+/* static */
+wxString wxString::Format(const wxChar *pszFormat, ...)
+{
+ va_list argptr;
+ va_start(argptr, pszFormat);
+
+ wxString s;
+ s.PrintfV(pszFormat, argptr);
+
+ va_end(argptr);
+
+ return s;
+}
+
+/* static */
+wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
+{
+ wxString s;
+ s.Printf(pszFormat, argptr);
+ return s;
+}
+
int wxString::Printf(const wxChar *pszFormat, ...)
{
va_list argptr;
// ---------------------------------------------------------------------------
// standard C++ library string functions
// ---------------------------------------------------------------------------
+
#ifdef wxSTD_STRING_COMPATIBILITY
+void wxString::resize(size_t nSize, wxChar ch)
+{
+ size_t len = length();
+
+ if ( nSize < len )
+ {
+ Truncate(nSize);
+ }
+ else if ( nSize > len )
+ {
+ *this += wxString(ch, len - nSize);
+ }
+ //else: we have exactly the specified length, nothing to do
+}
+
+void wxString::swap(wxString& str)
+{
+ // this is slightly less efficient than fiddling with m_pchData directly,
+ // but it is still quite efficient as we don't copy the string here because
+ // ref count always stays positive
+ wxString tmp = str;
+ str = *this;
+ *this = str;
+}
+
wxString& wxString::insert(size_t nPos, const wxString& str)
{
wxASSERT( str.GetStringData()->IsValid() );
#if !defined(__VISUALC__) || defined(__WIN32__)
size_t wxString::find(const wxChar* sz, size_t nStart, size_t n) const
{
- return find(wxString(sz, n == npos ? 0 : n), nStart);
+ return find(wxString(sz, n), nStart);
}
#endif // VC++ 1.5
const wxChar *start = c_str() + nStart;
const wxChar *firstOf = wxStrpbrk(start, sz);
if ( firstOf )
- return firstOf - start;
+ return firstOf - c_str();
else
return npos;
}
return npos;
}
-wxString wxString::substr(size_t nStart, size_t nLen) const
-{
- // npos means 'take all'
- if ( nLen == npos )
- nLen = 0;
-
- wxASSERT( nStart + nLen <= Len() );
-
- return wxString(c_str() + nStart, nLen == npos ? 0 : nLen);
-}
-
wxString& wxString::erase(size_t nStart, size_t nLen)
{
wxString strTmp(c_str(), nStart);
wxString& wxString::replace(size_t nStart, size_t nLen, const wxChar *sz)
{
- wxASSERT( nStart + nLen <= wxStrlen(sz) );
+ wxASSERT_MSG( nStart + nLen <= Len(),
+ _T("index out of bounds in wxString::replace") );
wxString strTmp;
+ strTmp.Alloc(Len()); // micro optimisation to avoid multiple mem allocs
+
if ( nStart != 0 )
strTmp.append(c_str(), nStart);
- strTmp += sz;
- strTmp.append(c_str() + nStart + nLen);
+ strTmp << sz << c_str() + nStart + nLen;
*this = strTmp;
return *this;
if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
Alloc(src.m_nCount);
- // we can't just copy the pointers here because otherwise we would share
- // the strings with another array because strings are ref counted
-#if 0
- if ( m_nCount != 0 )
- memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(wxChar *));
-#endif // 0
-
for ( size_t n = 0; n < src.m_nCount; n++ )
Add(src[n]);
-
- // if the other array is auto sorted too, we're already sorted, but
- // otherwise we should rearrange the items
- if ( m_autoSort && !src.m_autoSort )
- Sort();
}
// grow the array
DoSort();
+ // reset it to NULL so that Sort(bool) will work the next time
+ gs_compareFunction = NULL;
+
END_SORT();
}
qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
}
+bool wxArrayString::operator==(const wxArrayString& a) const
+{
+ if ( m_nCount != a.m_nCount )
+ return FALSE;
+
+ for ( size_t n = 0; n < m_nCount; n++ )
+ {
+ if ( Item(n) != a[n] )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+