X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c781c31638cc5ae06eb325567323f131e8183a75..94e8d77cbb22041c133edaa00720dff0de45a68a:/src/common/regex.cpp?ds=sidebyside diff --git a/src/common/regex.cpp b/src/common/regex.cpp index ac85aac972..b5b1fb49d4 100644 --- a/src/common/regex.cpp +++ b/src/common/regex.cpp @@ -18,10 +18,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "regex.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -49,10 +45,22 @@ #include #include "wx/regex.h" +// defined when the regex lib uses 'char' but 'wxChar' is wide +#if wxUSE_UNICODE && !defined(__REG_NOFRONT) +# define WXREGEX_CONVERT_TO_MB +#endif + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- +// the character type used by the regular expression engine +#ifndef WXREGEX_CONVERT_TO_MB +typedef wxChar wxRegChar; +#else +typedef char wxRegChar; +#endif + // the real implementation of wxRegEx class wxRegExImpl { @@ -66,7 +74,7 @@ public: // RE operations bool Compile(const wxString& expr, int flags = 0); - bool Matches(const wxChar *str, int flags = 0) const; + bool Matches(const wxRegChar *str, int flags, size_t len) const; bool GetMatch(size_t *start, size_t *len, size_t index = 0) const; size_t GetMatchCount() const; int Replace(wxString *pattern, const wxString& replacement, @@ -134,7 +142,7 @@ wxRegExImpl::~wxRegExImpl() wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const { -#if wxUSE_UNICODE && !defined(__REG_NOFRONT) +#ifdef WXREGEX_CONVERT_TO_MB // currently only needed when using system library in Unicode mode if ( badconv ) { @@ -259,7 +267,7 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) return IsValid(); } -bool wxRegExImpl::Matches(const wxChar *str, int flags) const +bool wxRegExImpl::Matches(const wxRegChar *str, int flags, size_t len) const { wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); @@ -282,11 +290,9 @@ bool wxRegExImpl::Matches(const wxChar *str, int flags) const // do match it #ifdef __REG_NOFRONT - bool conv = true; - int rc = wx_re_exec(&self->m_RegEx, str, wxStrlen(str), NULL, m_nMatches, m_Matches, flagsRE); + int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, m_Matches, flagsRE); #else - const wxWX2MBbuf conv = wxConvertWX2MB(str); - int rc = conv ? regexec(&self->m_RegEx, conv, m_nMatches, m_Matches, flagsRE) : REG_BADPAT; + int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, m_Matches, flagsRE) : REG_BADPAT; #endif switch ( rc ) @@ -297,8 +303,8 @@ bool wxRegExImpl::Matches(const wxChar *str, int flags) const default: // an error occurred - wxLogError(_("Failed to match '%s' in regular expression: %s"), - str, GetErrorMsg(rc, !conv).c_str()); + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(rc, !str).c_str()); // fall through case REG_NOMATCH: @@ -340,9 +346,29 @@ int wxRegExImpl::Replace(wxString *text, wxCHECK_MSG( text, wxNOT_FOUND, _T("NULL text in wxRegEx::Replace") ); wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); + // the input string +#ifndef WXREGEX_CONVERT_TO_MB + const wxChar *textstr = text->c_str(); + size_t textlen = text->length(); +#else + const wxWX2MBbuf textstr = wxConvertWX2MB(*text); + if (!textstr) + { + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(0, true).c_str()); + return 0; + } + size_t textlen = strlen(textstr); + text->clear(); +#endif + // the replacement text wxString textNew; + // the result, allow 25% extra + wxString result; + result.reserve(5 * textlen / 4); + // attempt at optimization: don't iterate over the string if it doesn't // contain back references at all bool mayHaveBackrefs = @@ -354,10 +380,6 @@ int wxRegExImpl::Replace(wxString *text, } // the position where we start looking for the match - // - // NB: initial version had a nasty bug because it used a wxChar* instead of - // an index but the problem is that replace() in the loop invalidates - // all pointers into the string so we have to use indices instead size_t matchStart = 0; // number of replacement made: we won't make more than maxMatches of them @@ -367,7 +389,9 @@ int wxRegExImpl::Replace(wxString *text, // note that "^" shouldn't match after the first call to Matches() so we // use wxRE_NOTBOL to prevent it from happening while ( (!maxMatches || countRepl < maxMatches) && - Matches(text->c_str() + matchStart, countRepl ? wxRE_NOTBOL : 0) ) + Matches(textstr + matchStart, + countRepl ? wxRE_NOTBOL : 0, + textlen - matchStart) ) { // the string possibly contains back references: we need to calculate // the replacement text anew after each match @@ -411,8 +435,8 @@ int wxRegExImpl::Replace(wxString *text, } else { - textNew += wxString(text->c_str() + matchStart + start, - len); + textNew += wxString(textstr + matchStart + start, + *wxConvCurrent, len); mayHaveBackrefs = true; } @@ -433,14 +457,31 @@ int wxRegExImpl::Replace(wxString *text, return wxNOT_FOUND; } + // an insurance against implementations that don't grow exponentially + // to ensure building the result takes linear time + if (result.capacity() < result.length() + start + textNew.length()) + result.reserve(2 * result.length()); + +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, start); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent, start)); +#endif matchStart += start; - text->replace(matchStart, len, textNew); + result.append(textNew); countRepl++; - matchStart += textNew.length(); + matchStart += len; } +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, wxString::npos); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent)); +#endif + *text = result; + return countRepl; } @@ -453,7 +494,6 @@ void wxRegEx::Init() m_impl = NULL; } - wxRegEx::~wxRegEx() { delete m_impl; @@ -482,7 +522,11 @@ bool wxRegEx::Matches(const wxChar *str, int flags) const { wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - return m_impl->Matches(str, flags); +#ifndef WXREGEX_CONVERT_TO_MB + return m_impl->Matches(str, flags, wxStrlen(str)); +#else + return m_impl->Matches(wxConvertWX2MB(str), flags, wxStrlen(str)); +#endif } bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const