X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b568d04ffa191f9e3b643ca33526094eca0ba304..f0ce3409421a7c5c800a2255295274187220e8de:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index 280e105f25..4fd4c02a14 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -85,6 +85,12 @@ static const struct 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; @@ -107,9 +113,11 @@ 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__ - #if defined(__VISUALC__) || defined(wxUSE_NORLANDER_HEADERS) + #if defined(__VISUALC__) || (defined(__MINGW32__) && wxUSE_NORLANDER_HEADERS) #define wxVsnprintfA _vsnprintf #endif +#elif defined(__WXMAC__) + #define wxVsnprintfA vsnprintf #else // !Windows #ifdef HAVE_VSNPRINTF #define wxVsnprintfA vsnprintf @@ -124,9 +132,7 @@ extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy; #if defined(__VISUALC__) #pragma message("Using sprintf() because no snprintf()-like function defined") - #elif defined(__GNUG__) && !defined(__UNIX__) - #warning "Using sprintf() because no snprintf()-like function defined" - #elif defined(__MWERKS__) + #elif defined(__GNUG__) #warning "Using sprintf() because no snprintf()-like function defined" #endif //compiler #endif // no vsnprintf @@ -203,7 +209,10 @@ extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len, // 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); - buf[len] = 0; + if ( rc == -1 ) + { + buf[len] = 0; + } return rc; #endif // Unicode/ANSI @@ -281,10 +290,12 @@ void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength) { 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); @@ -332,15 +343,15 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t 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(); @@ -357,8 +368,13 @@ wxString::wxString(const wchar_t *pwz) // 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); @@ -514,6 +530,12 @@ void wxString::UngetWriteBuf() GetStringData()->Validate(TRUE); } +void wxString::UngetWriteBuf(size_t nLen) +{ + GetStringData()->nDataLength = nLen; + GetStringData()->Validate(TRUE); +} + // --------------------------------------------------------------------------- // data access // --------------------------------------------------------------------------- @@ -754,6 +776,35 @@ wxString wxString::Mid(size_t nFirst, size_t nCount) const 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 { @@ -890,6 +941,8 @@ bool wxString::IsWord() 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++; @@ -933,14 +986,22 @@ wxString& wxString::MakeLower() // trimming and padding // --------------------------------------------------------------------------- +// some compilers (VC++ 6.0 not to name them) return TRUE for a call to +// isspace('ê') in the C locale which seems to be broken to me, but we have to +// live with this by checking that the character is a 7 bit one - even if this +// may fail to detect some spaces (I don't know if Unicode doesn't have +// space-like symbols somewhere except in the first 128 chars), it is arguably +// still better than trimming away accented letters +inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } + // 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 ( !IsEmpty() && ( - (bFromRight && wxIsspace(GetChar(Len() - 1))) || - (!bFromRight && wxIsspace(GetChar(0u))) + (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) || + (!bFromRight && wxSafeIsspace(GetChar(0u))) ) ) { @@ -951,7 +1012,7 @@ wxString& wxString::Trim(bool bFromRight) { // find last non-space character wxChar *psz = m_pchData + GetStringData()->nDataLength - 1; - while ( wxIsspace(*psz) && (psz >= m_pchData) ) + while ( wxSafeIsspace(*psz) && (psz >= m_pchData) ) psz--; // truncate at trailing space start @@ -962,7 +1023,7 @@ wxString& wxString::Trim(bool bFromRight) { // find first non-space character const wxChar *psz = m_pchData; - while ( wxIsspace(*psz) ) + while ( wxSafeIsspace(*psz) ) psz++; // fix up data and length @@ -1025,37 +1086,75 @@ int wxString::Find(const wxChar *pszSub) const 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") ); - return (*this) << res; + const wxChar *start = c_str(); + wxChar *end; + *val = wxStrtol(start, &end, 10); + + // 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") ); + + const wxChar *start = c_str(); + wxChar *end; + *val = wxStrtod(start, &end); - 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); } // --------------------------------------------------------------------------- // 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; @@ -1311,7 +1410,7 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) // NB: wxVsnprintf() may return either less than the buffer size or -1 if // there is not enough place depending on implementation - int iLen = wxVsnprintfA(szScratch, WXSIZEOF(szScratch), pszFormat, argptr); + int iLen = wxVsnprintfA(szScratch, WXSIZEOF(szScratch), (char *)pszFormat, argptr); if ( iLen != -1 ) { // the whole string is in szScratch *this = szScratch; @@ -1445,8 +1544,34 @@ int wxString::sprintf(const wxChar *pszFormat, ...) // --------------------------------------------------------------------------- // 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() ); @@ -1479,7 +1604,7 @@ size_t wxString::find(const wxString& str, size_t nStart) const #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 @@ -1544,7 +1669,7 @@ size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const const wxChar *start = c_str() + nStart; const wxChar *firstOf = wxStrpbrk(start, sz); if ( firstOf ) - return firstOf - start; + return firstOf - c_str(); else return npos; } @@ -1640,17 +1765,6 @@ size_t wxString::find_last_not_of(wxChar ch, size_t nStart) const 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); @@ -1666,13 +1780,15 @@ wxString& wxString::erase(size_t nStart, size_t nLen) 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; @@ -1745,20 +1861,8 @@ void wxArrayString::Copy(const wxArrayString& src) 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 @@ -2058,6 +2162,9 @@ void wxArrayString::Sort(CompareFunction compareFunction) DoSort(); + // reset it to NULL so that Sort(bool) will work the next time + gs_compareFunction = NULL; + END_SORT(); } @@ -2082,3 +2189,17 @@ void wxArrayString::DoSort() 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; +} +