X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e6feb95a79834836e88143b15d9f424ebe79621..fa1c12bdd76acc21ddb45b90bb53b2f58aed946d:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index 38d6d28300..7a30eb68ce 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -38,6 +38,8 @@ #include "wx/thread.h" #endif +#include "wx/regex.h" // for wxString::Matches() + #include #include #include @@ -46,10 +48,6 @@ #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 @@ -68,6 +66,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 +89,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 // Visual Age - // empty C style string: points to 'string data' byte of g_strEmpty extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy; @@ -499,18 +497,21 @@ void 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)); + + wxASSERT_MSG( p != NULL, _T("can't free memory?") ); - // we rely on a reasonable realloc() implementation here - so far I haven't - // seen any which wouldn't behave like this + 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; - wxASSERT( p != NULL ); // can't free memory? - wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move! + m_pchData = pData->data(); + } + + pData->nAllocLength = nLen; } // get the pointer to writable buffer of (at least) nLen bytes @@ -589,6 +590,7 @@ wxString& wxString::operator=(wxChar ch) return *this; } + // assigns C string wxString& wxString::operator=(const wxChar *psz) { @@ -1091,26 +1093,26 @@ 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") ); 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") ); 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 +1458,77 @@ 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++ ) { +#if 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 +1568,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 +1632,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 } @@ -1624,7 +1698,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 +1715,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 @@ -2082,6 +2156,16 @@ void wxArrayString::Insert(const wxString& str, size_t nIndex) 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) {