X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/db9db9cd182e0a48b20078505ce198339dde26fc..c2794afdbb17b46a677e28e73ac5e50a82e13399:/src/common/regex.cpp diff --git a/src/common/regex.cpp b/src/common/regex.cpp index b5b1fb49d4..2e0068f0a3 100644 --- a/src/common/regex.cpp +++ b/src/common/regex.cpp @@ -45,15 +45,100 @@ #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 +// WXREGEX_USING_BUILTIN defined when using the built-in regex lib +// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib +// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in +// or GNU regex +// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and +// wxChar is wide, so conversion must be done +// WXREGEX_CHAR(x) Convert wxChar to wxRegChar +// +#ifdef __REG_NOFRONT +# define WXREGEX_USING_BUILTIN +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_CHAR(x) x +#else +# ifdef HAVE_RE_SEARCH +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_USING_RE_SEARCH +# else +# define WXREGEX_IF_NEED_LEN(x) +# endif +# if wxUSE_UNICODE +# define WXREGEX_CONVERT_TO_MB +# endif +# define WXREGEX_CHAR(x) wxConvertWX2MB(x) +# define wx_regfree regfree +# define wx_regerror regerror #endif // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- +#ifndef WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the usual POSIX regmatch_t array. +class wxRegExMatches +{ +public: + typedef regmatch_t *match_type; + + wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; } + ~wxRegExMatches() { delete [] m_matches; } + + // we just use casts here because the fields of regmatch_t struct may be 64 + // bit but we're limited to size_t in our public API and are not going to + // change it because operating on strings longer than 4GB using it is + // absolutely impractical anyhow + size_t Start(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_so); + } + + size_t End(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_eo); + } + + regmatch_t *get() const { return m_matches; } + +private: + regmatch_t *m_matches; +}; + +#else // WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the struct used by the GNU lib +class wxRegExMatches +{ +public: + typedef re_registers *match_type; + + wxRegExMatches(size_t n) + { + m_matches.num_regs = n; + m_matches.start = new regoff_t[n]; + m_matches.end = new regoff_t[n]; + } + + ~wxRegExMatches() + { + delete [] m_matches.start; + delete [] m_matches.end; + } + + size_t Start(size_t n) const { return m_matches.start[n]; } + size_t End(size_t n) const { return m_matches.end[n]; } + + re_registers *get() { return &m_matches; } + +private: + re_registers m_matches; +}; + +#endif // WXREGEX_USING_RE_SEARCH + // the character type used by the regular expression engine #ifndef WXREGEX_CONVERT_TO_MB typedef wxChar wxRegChar; @@ -74,7 +159,8 @@ public: // RE operations bool Compile(const wxString& expr, int flags = 0); - bool Matches(const wxRegChar *str, int flags, size_t len) const; + bool Matches(const wxRegChar *str, int flags + WXREGEX_IF_NEED_LEN(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, @@ -97,10 +183,10 @@ private: { if ( IsValid() ) { - regfree(&m_RegEx); + wx_regfree(&m_RegEx); } - delete [] m_Matches; + delete m_Matches; } // free the RE if any and reinit the members @@ -110,18 +196,18 @@ private: Init(); } - // compiled RE - regex_t m_RegEx; + regex_t m_RegEx; // the subexpressions data - regmatch_t *m_Matches; - size_t m_nMatches; + wxRegExMatches *m_Matches; + size_t m_nMatches; // true if m_RegEx is valid - bool m_isCompiled; + bool m_isCompiled; }; + // ============================================================================ // implementation // ============================================================================ @@ -156,12 +242,12 @@ wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const wxString szError; // first get the string length needed - int len = regerror(errorcode, &m_RegEx, NULL, 0); + int len = wx_regerror(errorcode, &m_RegEx, NULL, 0); if ( len > 0 ) { char* szcmbError = new char[++len]; - (void)regerror(errorcode, &m_RegEx, szcmbError, len); + (void)wx_regerror(errorcode, &m_RegEx, szcmbError, len); szError = wxConvertMB2WX(szcmbError); delete [] szcmbError; @@ -205,7 +291,7 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) flagsRE |= REG_NEWLINE; // compile it -#ifdef __REG_NOFRONT +#ifdef WXREGEX_USING_BUILTIN bool conv = true; int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); #else @@ -267,7 +353,36 @@ bool wxRegExImpl::Compile(const wxString& expr, int flags) return IsValid(); } -bool wxRegExImpl::Matches(const wxRegChar *str, int flags, size_t len) const +#ifdef WXREGEX_USING_RE_SEARCH + +// On GNU, regexec is implemented as a wrapper around re_search. re_search +// requires a length parameter which the POSIX regexec does not have, +// therefore regexec must do a strlen on the search text each time it is +// called. This can drastically affect performance when matching is done in +// a loop along a string, such as during a search and replace. Therefore if +// re_search is detected by configure, it is used directly. +// +static int ReSearch(const regex_t *preg, + const char *text, + size_t len, + re_registers *matches, + int eflags) +{ + regex_t *pattern = wx_const_cast(regex_t*, preg); + + pattern->not_bol = (eflags & REG_NOTBOL) != 0; + pattern->not_eol = (eflags & REG_NOTEOL) != 0; + pattern->regs_allocated = REGS_FIXED; + + int ret = re_search(pattern, text, len, 0, len, matches); + return ret >= 0 ? 0 : REG_NOMATCH; +} + +#endif // WXREGEX_USING_RE_SEARCH + +bool wxRegExImpl::Matches(const wxRegChar *str, + int flags + WXREGEX_IF_NEED_LEN(size_t len)) const { wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); @@ -285,14 +400,18 @@ bool wxRegExImpl::Matches(const wxRegChar *str, int flags, size_t len) const wxRegExImpl *self = wxConstCast(this, wxRegExImpl); if ( !m_Matches && m_nMatches ) { - self->m_Matches = new regmatch_t[m_nMatches]; + self->m_Matches = new wxRegExMatches(m_nMatches); } + wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL; + // do match it -#ifdef __REG_NOFRONT - int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, m_Matches, flagsRE); +#if defined WXREGEX_USING_BUILTIN + int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE); +#elif defined WXREGEX_USING_RE_SEARCH + int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT; #else - int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, m_Matches, flagsRE) : REG_BADPAT; + int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT; #endif switch ( rc ) @@ -320,13 +439,10 @@ bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const 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 = wx_truncate_cast(size_t, match.rm_so); + *start = m_Matches->Start(index); if ( len ) - *len = wx_truncate_cast(size_t, match.rm_eo - match.rm_so); + *len = m_Matches->End(index) - m_Matches->Start(index); return true; } @@ -351,7 +467,7 @@ int wxRegExImpl::Replace(wxString *text, const wxChar *textstr = text->c_str(); size_t textlen = text->length(); #else - const wxWX2MBbuf textstr = wxConvertWX2MB(*text); + const wxWX2MBbuf textstr = WXREGEX_CHAR(*text); if (!textstr) { wxLogError(_("Failed to find match for regular expression: %s"), @@ -390,8 +506,8 @@ int wxRegExImpl::Replace(wxString *text, // use wxRE_NOTBOL to prevent it from happening while ( (!maxMatches || countRepl < maxMatches) && Matches(textstr + matchStart, - countRepl ? wxRE_NOTBOL : 0, - textlen - matchStart) ) + countRepl ? wxRE_NOTBOL : 0 + WXREGEX_IF_NEED_LEN(textlen - matchStart)) ) { // the string possibly contains back references: we need to calculate // the replacement text anew after each match @@ -518,15 +634,21 @@ bool wxRegEx::Compile(const wxString& expr, int flags) return true; } +bool wxRegEx::Matches(const wxChar *str, int flags, size_t len) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + (void)len; + + return m_impl->Matches(WXREGEX_CHAR(str), flags WXREGEX_IF_NEED_LEN(len)); +} + bool wxRegEx::Matches(const wxChar *str, int flags) const { wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); -#ifndef WXREGEX_CONVERT_TO_MB - return m_impl->Matches(str, flags, wxStrlen(str)); -#else - return m_impl->Matches(wxConvertWX2MB(str), flags, wxStrlen(str)); -#endif + return m_impl->Matches(WXREGEX_CHAR(str), + flags + WXREGEX_IF_NEED_LEN(wxStrlen(str))); } bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const