X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/86b79b93fbbb0c2e90e6595f7fea0f979b80881c..94e8d77cbb22041c133edaa00720dff0de45a68a:/src/common/regex.cpp?ds=sidebyside diff --git a/src/common/regex.cpp b/src/common/regex.cpp index 1837bfff30..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 { @@ -61,12 +69,12 @@ public: wxRegExImpl(); ~wxRegExImpl(); - // return TRUE if Compile() had been called successfully + // return true if Compile() had been called successfully bool IsValid() const { return m_isCompiled; } // 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, @@ -79,7 +87,7 @@ private: // init the members void Init() { - m_isCompiled = FALSE; + m_isCompiled = false; m_Matches = NULL; m_nMatches = 0; } @@ -110,7 +118,7 @@ private: regmatch_t *m_Matches; size_t m_nMatches; - // TRUE if m_RegEx is valid + // true if m_RegEx is valid bool m_isCompiled; }; @@ -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 ) { @@ -199,7 +207,7 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) // compile it #ifdef __REG_NOFRONT bool conv = true; - int errorcode = re_comp(&m_RegEx, expr, expr.length(), flagsRE); + int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); #else const wxWX2MBbuf conv = expr.mbc_str(); int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT; @@ -210,7 +218,7 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) wxLogError(_("Invalid regular expression '%s': %s"), expr.c_str(), GetErrorMsg(errorcode, !conv).c_str()); - m_isCompiled = FALSE; + m_isCompiled = false; } else // ok { @@ -253,15 +261,15 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) } } - m_isCompiled = TRUE; + m_isCompiled = true; } 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") ); + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); // translate our flags to regexec() ones wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)), @@ -282,46 +290,45 @@ bool wxRegExImpl::Matches(const wxChar *str, int flags) const // do match it #ifdef __REG_NOFRONT - bool conv = true; - int rc = 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 ) { case 0: // matched successfully - return TRUE; + return true; default: - // an error occured - wxLogError(_("Failed to match '%s' in regular expression: %s"), - str, GetErrorMsg(rc, !conv).c_str()); + // an error occurred + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(rc, !str).c_str()); // fall through case REG_NOMATCH: // no match - return FALSE; + return false; } } bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const { - wxCHECK_MSG( IsValid(), FALSE, _T("must successfully Compile() first") ); - wxCHECK_MSG( m_nMatches, FALSE, _T("can't use with wxRE_NOSUB") ); - wxCHECK_MSG( m_Matches, FALSE, _T("must call Matches() first") ); - wxCHECK_MSG( index < m_nMatches, FALSE, _T("invalid match index") ); + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + wxCHECK_MSG( m_nMatches, false, _T("can't use with wxRE_NOSUB") ); + wxCHECK_MSG( m_Matches, false, _T("must call Matches() first") ); + wxCHECK_MSG( index < m_nMatches, false, _T("invalid match index") ); const regmatch_t& match = m_Matches[index]; + // we need the casts because rm_so can be a 64 bit quantity if ( start ) - *start = match.rm_so; + *start = wx_truncate_cast(size_t, match.rm_so); if ( len ) - *len = match.rm_eo - match.rm_so; + *len = wx_truncate_cast(size_t, match.rm_eo - match.rm_so); - return TRUE; + return true; } size_t wxRegExImpl::GetMatchCount() const @@ -336,12 +343,32 @@ int wxRegExImpl::Replace(wxString *text, const wxString& replacement, size_t maxMatches) const { - wxCHECK_MSG( text, -1, _T("NULL text in wxRegEx::Replace") ); - wxCHECK_MSG( IsValid(), -1, _T("must successfully Compile() first") ); + 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 = @@ -353,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 @@ -366,13 +389,15 @@ 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 if ( mayHaveBackrefs ) { - mayHaveBackrefs = FALSE; + mayHaveBackrefs = false; textNew.clear(); textNew.reserve(replacement.length()); @@ -410,10 +435,10 @@ int wxRegExImpl::Replace(wxString *text, } else { - textNew += wxString(text->c_str() + matchStart + start, - len); + textNew += wxString(textstr + matchStart + start, + *wxConvCurrent, len); - mayHaveBackrefs = TRUE; + mayHaveBackrefs = true; } } else // ordinary character @@ -429,17 +454,34 @@ int wxRegExImpl::Replace(wxString *text, // we did have match as Matches() returned true above! wxFAIL_MSG( _T("internal logic error in wxRegEx::Replace") ); - return -1; + 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; } @@ -452,7 +494,6 @@ void wxRegEx::Init() m_impl = NULL; } - wxRegEx::~wxRegEx() { delete m_impl; @@ -471,22 +512,26 @@ bool wxRegEx::Compile(const wxString& expr, int flags) delete m_impl; m_impl = NULL; - return FALSE; + return false; } - return TRUE; + return true; } bool wxRegEx::Matches(const wxChar *str, int flags) const { - wxCHECK_MSG( IsValid(), FALSE, _T("must successfully Compile() first") ); + 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 { - wxCHECK_MSG( IsValid(), FALSE, _T("must successfully Compile() first") ); + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); return m_impl->GetMatch(start, len, index); } @@ -511,7 +556,7 @@ int wxRegEx::Replace(wxString *pattern, const wxString& replacement, size_t maxMatches) const { - wxCHECK_MSG( IsValid(), -1, _T("must successfully Compile() first") ); + wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); return m_impl->Replace(pattern, replacement, maxMatches); }