X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/38caaa61b154f60871cb6ec82040362762dd2dba..da2b4b7a57f816723ed26dbbeca0549b9ce6735a:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index a53c4378f9..c7ce4c3d1c 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 - // 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?") ); + + 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; - // we rely on a reasonable realloc() implementation here - so far I haven't - // seen any which wouldn't behave like this + m_pchData = pData->data(); + } - wxASSERT( p != NULL ); // can't free memory? - wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move! + 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 @@ -1854,6 +1928,8 @@ wxArrayString& wxArrayString::operator=(const wxArrayString& src) Copy(src); + m_autoSort = src.m_autoSort; + return *this; } @@ -1870,8 +1946,14 @@ void wxArrayString::Copy(const wxArrayString& src) void wxArrayString::Grow() { // 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];