X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/38caaa61b154f60871cb6ec82040362762dd2dba..e83ecba968c94965523be449a56fffcf4c55010b:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index a53c4378f9..e232c8a79d 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -46,17 +46,9 @@ #include #endif -#if wxUSE_WCSRTOMBS - #include // for wcsrtombs(), see comments where it's used -#endif // GNU - -#ifdef WXSTRING_IS_WXOBJECT - IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject) -#endif //WXSTRING_IS_WXOBJECT - #if wxUSE_UNICODE -#undef wxUSE_EXPERIMENTAL_PRINTF -#define wxUSE_EXPERIMENTAL_PRINTF 1 + #undef wxUSE_EXPERIMENTAL_PRINTF + #define wxUSE_EXPERIMENTAL_PRINTF 1 #endif // allocating extra space for each string consumes more memory but speeds up @@ -68,6 +60,12 @@ // static class variables definition // --------------------------------------------------------------------------- +#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 // Visual Age + #ifdef wxSTD_STRING_COMPATIBILITY const size_t wxString::npos = wxSTRING_MAXLEN; #endif // wxSTD_STRING_COMPATIBILITY @@ -85,12 +83,6 @@ 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; @@ -137,7 +129,7 @@ extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy; #endif //compiler #endif // no vsnprintf -#ifdef _AIX +#if defined(_AIX) // AIX has vsnprintf, but there's no prototype in the system headers. extern "C" int vsnprintf(char* str, size_t n, const char* format, va_list ap); #endif @@ -275,7 +267,10 @@ wxString::wxString(wxChar ch, size_t nLength) Init(); if ( nLength > 0 ) { - AllocBuffer(nLength); + if ( !AllocBuffer(nLength) ) { + wxFAIL_MSG( _T("out of memory in wxString::wxString") ); + return; + } #if wxUSE_UNICODE // memset only works on char @@ -302,7 +297,10 @@ void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength) if ( nLength > 0 ) { // trailing '\0' is written in AllocBuffer() - AllocBuffer(nLength); + if ( !AllocBuffer(nLength) ) { + wxFAIL_MSG( _T("out of memory in wxString::InitWith") ); + return; + } memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar)); } } @@ -332,7 +330,10 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength) // empty? if ( (nLen != 0) && (nLen != (size_t)-1) ) { - AllocBuffer(nLen); + if ( !AllocBuffer(nLen) ) { + wxFAIL_MSG( _T("out of memory in wxString::wxString") ); + return; + } conv.MB2WC(m_pchData, psz, nLen); } else { @@ -344,14 +345,24 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength) #if wxUSE_WCHAR_T // from wide string -wxString::wxString(const wchar_t *pwz, wxMBConv& conv) +wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength) { // first get necessary size - size_t nLen = pwz ? conv.WC2MB((char *) NULL, pwz, 0) : 0; + size_t nLen = 0; + if (pwz) + { + if (nLength == wxSTRING_MAXLEN) + nLen = conv.WC2MB((char *) NULL, pwz, 0); + else + nLen = nLength; + } // empty? if ( (nLen != 0) && (nLen != (size_t)-1) ) { - AllocBuffer(nLen); + if ( !AllocBuffer(nLen) ) { + wxFAIL_MSG( _T("out of memory in wxString::wxString") ); + return; + } conv.WC2MB(m_pchData, pwz, nLen); } else { @@ -367,7 +378,7 @@ wxString::wxString(const wchar_t *pwz, wxMBConv& conv) // --------------------------------------------------------------------------- // allocates memory needed to store a C string of length nLen -void wxString::AllocBuffer(size_t nLen) +bool wxString::AllocBuffer(size_t nLen) { // allocating 0 sized buffer doesn't make sense, all empty strings should // reuse g_strEmpty @@ -384,30 +395,42 @@ void wxString::AllocBuffer(size_t nLen) // 2) sizeof(wxStringData) for housekeeping info wxStringData* pData = (wxStringData*) malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failures are handled by the caller + return FALSE; + } + pData->nRefs = 1; pData->nDataLength = nLen; pData->nAllocLength = nLen + EXTRA_ALLOC; m_pchData = pData->data(); // data starts after wxStringData m_pchData[nLen] = wxT('\0'); + return TRUE; } // must be called before changing this string -void wxString::CopyBeforeWrite() +bool wxString::CopyBeforeWrite() { wxStringData* pData = GetStringData(); if ( pData->IsShared() ) { pData->Unlock(); // memory not freed because shared size_t nLen = pData->nDataLength; - AllocBuffer(nLen); + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return FALSE; + } memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar)); } wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + return TRUE; } // must be called before replacing contents of this string -void wxString::AllocBeforeWrite(size_t nLen) +bool wxString::AllocBeforeWrite(size_t nLen) { wxASSERT( nLen != 0 ); // doesn't make any sense @@ -416,7 +439,10 @@ void wxString::AllocBeforeWrite(size_t nLen) if ( pData->IsShared() || pData->IsEmpty() ) { // can't work with old buffer, get new one pData->Unlock(); - AllocBuffer(nLen); + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return FALSE; + } } else { if ( nLen > pData->nAllocLength ) { @@ -426,15 +452,13 @@ void wxString::AllocBeforeWrite(size_t 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; + + if ( pData == NULL ) { + // allocation failures are handled by the caller + // keep previous data since reallocation failed + return FALSE; } pData->nAllocLength = nLen; @@ -446,10 +470,12 @@ void wxString::AllocBeforeWrite(size_t nLen) } wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + return TRUE; } // allocate enough memory for nLen characters -void wxString::Alloc(size_t nLen) +bool wxString::Alloc(size_t nLen) { wxStringData *pData = GetStringData(); if ( pData->nAllocLength <= nLen ) { @@ -457,7 +483,13 @@ void wxString::Alloc(size_t nLen) nLen += EXTRA_ALLOC; wxStringData* pData = (wxStringData*) - malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failure handled by caller + return FALSE; + } + pData->nRefs = 1; pData->nDataLength = 0; pData->nAllocLength = nLen; @@ -467,56 +499,69 @@ void wxString::Alloc(size_t nLen) else if ( pData->IsShared() ) { pData->Unlock(); // memory not freed because shared size_t nOldLen = pData->nDataLength; - AllocBuffer(nLen); + if ( !AllocBuffer(nLen) ) { + // allocation failure handled by caller + return FALSE; + } memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar)); } else { nLen += EXTRA_ALLOC; - wxStringData *pDataOld = pData; - wxStringData *p = (wxStringData *) + pData = (wxStringData *) realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - if ( p == NULL ) { - // don't leak memory - free(pDataOld); - - // FIXME what to do on memory error? - return; + if ( pData == NULL ) { + // allocation failure handled by caller + // keep previous data since reallocation failed + return FALSE; } // it's not important if the pointer changed or not (the check for this // is not faster than assigning to m_pchData in all cases) - p->nAllocLength = nLen; - m_pchData = p->data(); + pData->nAllocLength = nLen; + m_pchData = pData->data(); } } //else: we've already got enough + return TRUE; } // shrink to minimal size (releasing extra memory) -void wxString::Shrink() +bool wxString::Shrink() { wxStringData *pData = GetStringData(); - // 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)); + size_t nLen = pData->nDataLength; + void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( p == NULL) { + wxFAIL_MSG( _T("out of memory reallocating wxString data") ); + // keep previous data since reallocation failed + return FALSE; + } + + if ( p != pData ) + { + // contrary to what one might believe, some realloc() implementation do + // move the memory block even when its size is reduced + pData = (wxStringData *)p; + + m_pchData = pData->data(); + } - // we rely on a reasonable realloc() implementation here - so far I haven't - // seen any which wouldn't behave like this + pData->nAllocLength = nLen; - wxASSERT( p != NULL ); // can't free memory? - wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move! + return TRUE; } // get the pointer to writable buffer of (at least) nLen bytes wxChar *wxString::GetWriteBuf(size_t nLen) { - AllocBeforeWrite(nLen); + if ( !AllocBeforeWrite(nLen) ) { + // allocation failure handled by caller + return NULL; + } wxASSERT( GetStringData()->nRefs == 1 ); GetStringData()->Validate(FALSE); @@ -548,17 +593,21 @@ void wxString::UngetWriteBuf(size_t nLen) // --------------------------------------------------------------------------- // helper function: does real copy -void wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) +bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) { if ( nSrcLen == 0 ) { Reinit(); } else { - AllocBeforeWrite(nSrcLen); + if ( !AllocBeforeWrite(nSrcLen) ) { + // allocation failure handled by caller + return FALSE; + } memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); GetStringData()->nDataLength = nSrcLen; m_pchData[nSrcLen] = wxT('\0'); } + return TRUE; } // assigns one string to another @@ -585,14 +634,19 @@ wxString& wxString::operator=(const wxString& stringSrc) // assigns a single character wxString& wxString::operator=(wxChar ch) { - AssignCopy(1, &ch); + if ( !AssignCopy(1, &ch) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") ); + } return *this; } + // assigns C string wxString& wxString::operator=(const wxChar *psz) { - AssignCopy(wxStrlen(psz), psz); + if ( !AssignCopy(wxStrlen(psz), psz) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") ); + } return *this; } @@ -621,7 +675,7 @@ wxString& wxString::operator=(const wchar_t *pwz) // --------------------------------------------------------------------------- // add something to this string -void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) +bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) { STATISTICS_ADD(SummandLength, nSrcLen); @@ -637,7 +691,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) // we have to allocate another buffer wxStringData* pOldData = GetStringData(); - AllocBuffer(nNewLen); + if ( !AllocBuffer(nNewLen) ) { + // allocation failure handled by caller + return FALSE; + } memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); pOldData->Unlock(); } @@ -645,7 +702,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) STATISTICS_ADD(ConcatHit, 0); // we have to grow the buffer - Alloc(nNewLen); + if ( !Alloc(nNewLen) ) { + // allocation failure handled by caller + return FALSE; + } } else { STATISTICS_ADD(ConcatHit, 1); @@ -663,6 +723,7 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) GetStringData()->nDataLength = nNewLen; // and fix the length } //else: the string to append was empty + return TRUE; } /* @@ -672,57 +733,61 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData) * C str + string and string + C str */ -wxString operator+(const wxString& string1, const wxString& string2) +wxString operator+(const wxString& str1, const wxString& str2) { - wxASSERT( string1.GetStringData()->IsValid() ); - wxASSERT( string2.GetStringData()->IsValid() ); + wxASSERT( str1.GetStringData()->IsValid() ); + wxASSERT( str2.GetStringData()->IsValid() ); - wxString s = string1; - s += string2; + wxString s = str1; + s += str2; return s; } -wxString operator+(const wxString& string, wxChar ch) +wxString operator+(const wxString& str, wxChar ch) { - wxASSERT( string.GetStringData()->IsValid() ); + wxASSERT( str.GetStringData()->IsValid() ); - wxString s = string; + wxString s = str; s += ch; return s; } -wxString operator+(wxChar ch, const wxString& string) +wxString operator+(wxChar ch, const wxString& str) { - wxASSERT( string.GetStringData()->IsValid() ); + wxASSERT( str.GetStringData()->IsValid() ); wxString s = ch; - s += string; + s += str; return s; } -wxString operator+(const wxString& string, const wxChar *psz) +wxString operator+(const wxString& str, const wxChar *psz) { - wxASSERT( string.GetStringData()->IsValid() ); + wxASSERT( str.GetStringData()->IsValid() ); wxString s; - s.Alloc(wxStrlen(psz) + string.Len()); - s = string; + if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s = str; s += psz; return s; } -wxString operator+(const wxChar *psz, const wxString& string) +wxString operator+(const wxChar *psz, const wxString& str) { - wxASSERT( string.GetStringData()->IsValid() ); + wxASSERT( str.GetStringData()->IsValid() ); wxString s; - s.Alloc(wxStrlen(psz) + string.Len()); + if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } s = psz; - s += string; + s += str; return s; } @@ -736,15 +801,19 @@ wxString operator+(const wxChar *psz, const wxString& string) // --------------------------------------------------------------------------- // helper function: clone the data attached to this string -void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const +bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const { if ( nCopyLen == 0 ) { dest.Init(); } else { - dest.AllocBuffer(nCopyLen); + if ( !dest.AllocBuffer(nCopyLen) ) { + // allocation failure handled by caller + return FALSE; + } memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); } + return TRUE; } // extract string of length nCount starting at nFirst @@ -772,7 +841,9 @@ wxString wxString::Mid(size_t nFirst, size_t nCount) const } wxString dest; - AllocCopy(dest, nCount, nFirst); + if ( !AllocCopy(dest, nCount, nFirst) ) { + wxFAIL_MSG( _T("out of memory in wxString::Mid") ); + } return dest; } @@ -813,7 +884,9 @@ wxString wxString::Right(size_t nCount) const nCount = GetStringData()->nDataLength; wxString dest; - AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount); + if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) { + wxFAIL_MSG( _T("out of memory in wxString::Right") ); + } return dest; } @@ -838,7 +911,9 @@ wxString wxString::Left(size_t nCount) const nCount = GetStringData()->nDataLength; wxString dest; - AllocCopy(dest, nCount, 0); + if ( !AllocCopy(dest, nCount, 0) ) { + wxFAIL_MSG( _T("out of memory in wxString::Left") ); + } return dest; } @@ -899,7 +974,10 @@ size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplace } else { // take chars before match - strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent); + if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) { + wxFAIL_MSG( _T("out of memory in wxString::Replace") ); + return 0; + } strTemp += szNew; pCurrent = pSubstr + uiOldLen; // restart after match @@ -965,8 +1043,11 @@ wxString wxString::Strip(stripType w) const wxString& wxString::MakeUpper() { - CopyBeforeWrite(); - + if ( !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") ); + return *this; + } + for ( wxChar *p = m_pchData; *p; p++ ) *p = (wxChar)wxToupper(*p); @@ -975,7 +1056,10 @@ wxString& wxString::MakeUpper() wxString& wxString::MakeLower() { - CopyBeforeWrite(); + if ( !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxString::MakeLower") ); + return *this; + } for ( wxChar *p = m_pchData; *p; p++ ) *p = (wxChar)wxTolower(*p); @@ -1007,7 +1091,10 @@ wxString& wxString::Trim(bool bFromRight) ) { // ok, there is at least one space to trim - CopyBeforeWrite(); + if ( !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxString::Trim") ); + return *this; + } if ( bFromRight ) { @@ -1057,7 +1144,10 @@ wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) wxString& wxString::Truncate(size_t uiLen) { if ( uiLen < Len() ) { - CopyBeforeWrite(); + if ( !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxString::Truncate") ); + return *this; + } *(m_pchData + uiLen) = wxT('\0'); GetStringData()->nDataLength = uiLen; @@ -1091,26 +1181,28 @@ int wxString::Find(const wxChar *pszSub) const // conversion to numbers // ---------------------------------------------------------------------------- -bool wxString::ToLong(long *val) const +bool wxString::ToLong(long *val, int base) const { wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") ); + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); const wxChar *start = c_str(); wxChar *end; - *val = wxStrtol(start, &end, 10); + *val = wxStrtol(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); } -bool wxString::ToULong(unsigned long *val) const +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") ); const wxChar *start = c_str(); wxChar *end; - *val = wxStrtoul(start, &end, 10); + *val = wxStrtoul(start, &end, base); // return TRUE only if scan was stopped by the terminating NUL and if the // string was not empty to start with @@ -1456,21 +1548,81 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) // of them) bool wxString::Matches(const wxChar *pszMask) const { - // check char by char - const wxChar *pszTxt; - for ( pszTxt = c_str(); *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { + // I disable this code as it doesn't seem to be faster (in fact, it seems + // to be much slower) than the old, hand-written code below and using it + // here requires always linking with libregex even if the user code doesn't + // use it +#if 0 // wxUSE_REGEX + // first translate the shell-like mask into a regex + wxString pattern; + pattern.reserve(wxStrlen(pszMask)); + + pattern += _T('^'); + while ( *pszMask ) + { + switch ( *pszMask ) + { + case _T('?'): + pattern += _T('.'); + break; + + case _T('*'): + pattern += _T(".*"); + break; + + case _T('^'): + case _T('.'): + case _T('$'): + case _T('('): + case _T(')'): + case _T('|'): + case _T('+'): + case _T('\\'): + // these characters are special in a RE, quote them + // (however note that we don't quote '[' and ']' to allow + // using them for Unix shell like matching) + pattern += _T('\\'); + // fall through + + default: + pattern += *pszMask; + } + + pszMask++; + } + pattern += _T('$'); + + // and now use it + return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); +#else // !wxUSE_REGEX + // TODO: this is, of course, awfully inefficient... + + // the char currently being checked + const wxChar *pszTxt = c_str(); + + // the last location where '*' matched + const wxChar *pszLastStarInText = NULL; + const wxChar *pszLastStarInMask = NULL; + +match: + for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { switch ( *pszMask ) { case wxT('?'): if ( *pszTxt == wxT('\0') ) return FALSE; - // pszText and pszMask will be incremented in the loop statement + // pszTxt and pszMask will be incremented in the loop statement break; case wxT('*'): { + // remember where we started to be able to backtrack later + pszLastStarInText = pszTxt; + pszLastStarInMask = pszMask; + // ignore special chars immediately following this one + // (should this be an error?) while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) pszMask++; @@ -1510,7 +1662,23 @@ bool wxString::Matches(const wxChar *pszMask) const } // match only if nothing left - return *pszTxt == wxT('\0'); + if ( *pszTxt == wxT('\0') ) + return TRUE; + + // if we failed to match, backtrack if we can + if ( pszLastStarInText ) { + pszTxt = pszLastStarInText + 1; + pszMask = pszLastStarInMask; + + pszLastStarInText = NULL; + + // don't bother resetting pszLastStarInMask, it's unnecessary + + goto match; + } + + return FALSE; +#endif // wxUSE_REGEX/!wxUSE_REGEX } // Count the number of chars @@ -1558,7 +1726,7 @@ void wxString::resize(size_t nSize, wxChar ch) } else if ( nSize > len ) { - *this += wxString(ch, len - nSize); + *this += wxString(ch, nSize - len); } //else: we have exactly the specified length, nothing to do } @@ -1570,7 +1738,7 @@ void wxString::swap(wxString& str) // ref count always stays positive wxString tmp = str; str = *this; - *this = str; + *this = tmp; } wxString& wxString::insert(size_t nPos, const wxString& str) @@ -1624,7 +1792,7 @@ size_t wxString::find(wxChar ch, size_t nStart) const size_t wxString::rfind(const wxString& str, size_t nStart) const { wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart <= Len() ); + wxASSERT( nStart == npos || nStart <= Len() ); // TODO could be made much quicker than that const wxChar *p = c_str() + (nStart == npos ? Len() : nStart); @@ -1641,7 +1809,7 @@ size_t wxString::rfind(const wxString& str, size_t nStart) const #if !defined(__VISUALC__) || defined(__WIN32__) size_t wxString::rfind(const wxChar* sz, size_t nStart, size_t n) const { - return rfind(wxString(sz, n == npos ? 0 : n), nStart); + return rfind(wxString(sz, n == npos ? wxSTRING_MAXLEN : n), nStart); } size_t wxString::rfind(wxChar ch, size_t nStart) const @@ -1818,16 +1986,17 @@ wxString& wxString::replace(size_t nStart, size_t nLen, // ArrayString // ============================================================================ -// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) +// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) #define ARRAY_MAXSIZE_INCREMENT 4096 + #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h - #define ARRAY_DEFAULT_INITIAL_SIZE (16) +#define ARRAY_DEFAULT_INITIAL_SIZE (16) #endif #define STRING(p) ((wxString *)(&(p))) // ctor -wxArrayString::wxArrayString(bool autoSort) +void wxArrayString::Init(bool autoSort) { m_nSize = m_nCount = 0; @@ -1838,10 +2007,7 @@ wxArrayString::wxArrayString(bool autoSort) // copy ctor wxArrayString::wxArrayString(const wxArrayString& src) { - m_nSize = - m_nCount = 0; - m_pItems = (wxChar **) NULL; - m_autoSort = src.m_autoSort; + Init(src.m_autoSort); *this = src; } @@ -1854,6 +2020,8 @@ wxArrayString& wxArrayString::operator=(const wxArrayString& src) Copy(src); + m_autoSort = src.m_autoSort; + return *this; } @@ -1867,11 +2035,17 @@ void wxArrayString::Copy(const wxArrayString& src) } // grow the array -void wxArrayString::Grow() +void wxArrayString::Grow(size_t nIncrement) { // only do it if no more place - if( m_nCount == m_nSize ) { - if( m_nSize == 0 ) { + if ( m_nCount == m_nSize ) { + // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would + // be never resized! + #if ARRAY_DEFAULT_INITIAL_SIZE == 0 + #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" + #endif + + if ( m_nSize == 0 ) { // was empty, alloc some memory m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; m_pItems = new wxChar *[m_nSize]; @@ -1880,10 +2054,12 @@ void wxArrayString::Grow() // otherwise when it's called for the first time, nIncrement would be 0 // and the array would never be expanded // add 50% but not too much - size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE + size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; - if ( nIncrement > ARRAY_MAXSIZE_INCREMENT ) - nIncrement = ARRAY_MAXSIZE_INCREMENT; + if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) + ndefIncrement = ARRAY_MAXSIZE_INCREMENT; + if ( nIncrement < ndefIncrement ) + nIncrement = ndefIncrement; m_nSize += nIncrement; wxChar **pNew = new wxChar *[m_nSize]; @@ -1935,8 +2111,6 @@ wxArrayString::~wxArrayString() // pre-allocates memory (frees the previous data!) void wxArrayString::Alloc(size_t nSize) { - wxASSERT( nSize > 0 ); - // only if old buffer was not big enough if ( nSize > m_nSize ) { Free(); @@ -1963,6 +2137,21 @@ void wxArrayString::Shrink() } } +// return a wxString[] as required for some control ctors. +wxString* wxArrayString::GetStringArray() const +{ + wxString *array = 0; + + if( m_nCount > 0 ) + { + array = new wxString[m_nCount]; + for( size_t i = 0; i < m_nCount; i++ ) + array[i] = m_pItems[i]; + } + + return array; +} + // searches the array for an item (forward or backwards) int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const { @@ -2013,7 +2202,7 @@ int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const } // add item at the end -size_t wxArrayString::Add(const wxString& str) +size_t wxArrayString::Add(const wxString& str, size_t nInsert) { if ( m_autoSort ) { // insert the string at the correct position to keep the array sorted @@ -2037,54 +2226,75 @@ size_t wxArrayString::Add(const wxString& str) wxASSERT_MSG( lo == hi, wxT("binary search broken") ); - Insert(str, lo); + Insert(str, lo, nInsert); return (size_t)lo; } else { wxASSERT( str.GetStringData()->IsValid() ); - Grow(); - - // the string data must not be deleted! - str.GetStringData()->Lock(); + Grow(nInsert); - // just append - m_pItems[m_nCount] = (wxChar *)str.c_str(); // const_cast + for (size_t i = 0; i < nInsert; i++) + { + // the string data must not be deleted! + str.GetStringData()->Lock(); - return m_nCount++; + // just append + m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast + } + size_t ret = m_nCount; + m_nCount += nInsert; + return ret; } } // add item at the given position -void wxArrayString::Insert(const wxString& str, size_t nIndex) +void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) { wxASSERT( str.GetStringData()->IsValid() ); wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); + wxCHECK_RET( m_nCount <= m_nCount + nInsert, + wxT("array size overflow in wxArrayString::Insert") ); - Grow(); + Grow(nInsert); - memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex], + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], (m_nCount - nIndex)*sizeof(wxChar *)); - str.GetStringData()->Lock(); - m_pItems[nIndex] = (wxChar *)str.c_str(); + for (size_t i = 0; i < nInsert; i++) + { + str.GetStringData()->Lock(); + m_pItems[nIndex + i] = (wxChar *)str.c_str(); + } + m_nCount += nInsert; +} - m_nCount++; +// expand the array +void wxArrayString::SetCount(size_t count) +{ + Alloc(count); + + wxString s; + while ( m_nCount < count ) + m_pItems[m_nCount++] = (wxChar *)s.c_str(); } // removes item from array (by index) -void wxArrayString::Remove(size_t nIndex) +void wxArrayString::Remove(size_t nIndex, size_t nRemove) { - wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Remove") ); + wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); + wxCHECK_RET( nIndex + nRemove <= m_nCount, + wxT("removing too many elements in wxArrayString::Remove") ); // release our lock - Item(nIndex).GetStringData()->Unlock(); + for (size_t i = 0; i < nRemove; i++) + Item(nIndex + i).GetStringData()->Unlock(); - memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1], - (m_nCount - nIndex - 1)*sizeof(wxChar *)); - m_nCount--; + memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], + (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); + m_nCount -= nRemove; } // removes item from array (by value) @@ -2130,7 +2340,8 @@ static wxArrayString::CompareFunction gs_compareFunction = NULL; static bool gs_sortAscending = TRUE; // function which is called by quick sort -static int LINKAGEMODE wxStringCompareFunction(const void *first, const void *second) +extern "C" int LINKAGEMODE +wxStringCompareFunction(const void *first, const void *second) { wxString *strFirst = (wxString *)first; wxString *strSecond = (wxString *)second;