aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZufu Liu <unknown>2023-12-12 09:45:46 +1100
committerZufu Liu <unknown>2023-12-12 09:45:46 +1100
commit50f053ff0f1d1a2b45a20e65f25a21a2a10c1bc4 (patch)
tree6394af33566c632c73cf5f035abf5d176f61e946
parent1b83a38def5c210c39421593b0a73c23495bcd54 (diff)
downloadscintilla-mirror-50f053ff0f1d1a2b45a20e65f25a21a2a10c1bc4.tar.gz
Bug [#2405]. Fix regular expression assertion (^, $, \b. \B) failures when using
SCFIND_CXX11REGEX.
-rw-r--r--doc/ScintillaHistory.html4
-rw-r--r--src/Document.cxx61
-rw-r--r--test/unit/testDocument.cxx37
3 files changed, 69 insertions, 33 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 38cd4e3fa..dc2a8415e 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -614,6 +614,10 @@
<a href="https://sourceforge.net/p/scintilla/bugs/2413/">Bug #2413</a>.
</li>
<li>
+ Fix regular expression assertion (^, $, \b. \B) failures when using SCFIND_CXX11REGEX.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2405/">Bug #2405</a>.
+ </li>
+ <li>
With a document that does not have the SC_DOCUMENTOPTION_TEXT_LARGE option set,
allocating more than 2G (calling SCI_ALLOCATE or similar) will now fail with SC_STATUS_FAILURE.
</li>
diff --git a/src/Document.cxx b/src/Document.cxx
index 16595eafa..84eea1394 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -2843,8 +2843,8 @@ public:
lineRangeEnd = doc->SciLineFromPosition(endPos);
lineRangeBreak = lineRangeEnd + increment;
}
- Range LineRange(Sci::Line line) const {
- Range range(doc->LineStart(line), doc->LineEnd(line));
+ Range LineRange(Sci::Line line, Sci::Position lineStartPos, Sci::Position lineEndPos) const noexcept {
+ Range range(lineStartPos, lineEndPos);
if (increment == 1) {
if (line == lineRangeStart)
range.start = startPos;
@@ -3082,12 +3082,24 @@ public:
#endif
-std::regex_constants::match_flag_type MatchFlags(const Document *doc, Sci::Position startPos, Sci::Position endPos) noexcept {
+std::regex_constants::match_flag_type MatchFlags(const Document *doc, Sci::Position startPos, Sci::Position endPos, Sci::Position lineStartPos, Sci::Position lineEndPos) noexcept {
std::regex_constants::match_flag_type flagsMatch = std::regex_constants::match_default;
- if (!doc->IsLineStartPosition(startPos))
+ if (startPos != lineStartPos) {
+#ifdef _LIBCPP_VERSION
flagsMatch |= std::regex_constants::match_not_bol;
- if (!doc->IsLineEndPosition(endPos))
+ if (!doc->IsWordStartAt(startPos)) {
+ flagsMatch |= std::regex_constants::match_not_bow;
+ }
+#else
+ flagsMatch |= std::regex_constants::match_prev_avail;
+#endif
+ }
+ if (endPos != lineEndPos) {
flagsMatch |= std::regex_constants::match_not_eol;
+ if (!doc->IsWordEndAt(endPos)) {
+ flagsMatch |= std::regex_constants::match_not_eow;
+ }
+ }
return flagsMatch;
}
@@ -3101,39 +3113,33 @@ bool MatchOnLines(const Document *doc, const Regex &regexp, const RESearchRange
// has not been implemented by compiler runtimes with MSVC always in multiline
// mode and libc++ and libstdc++ always in single-line mode.
// If multiline regex worked well then the line by line iteration could be removed
- // for the forwards case and replaced with the following 4 lines:
+ // for the forwards case and replaced with the following:
#ifdef REGEX_MULTILINE
+ const Sci::Position lineStartPos = doc->LineStart(resr.lineRangeStart);
+ const Sci::Position lineEndPos = doc->LineEnd(resr.lineRangeEnd);
Iterator itStart(doc, resr.startPos);
Iterator itEnd(doc, resr.endPos);
- const std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, resr.startPos, resr.endPos);
+ const std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, resr.startPos, resr.endPos, lineStartPos, lineEndPos);
const bool matched = std::regex_search(itStart, itEnd, match, regexp, flagsMatch);
#else
// Line by line.
bool matched = false;
for (Sci::Line line = resr.lineRangeStart; line != resr.lineRangeBreak; line += resr.increment) {
- const Range lineRange = resr.LineRange(line);
+ const Sci::Position lineStartPos = doc->LineStart(line);
+ const Sci::Position lineEndPos = doc->LineEnd(line);
+ const Range lineRange = resr.LineRange(line, lineStartPos, lineEndPos);
Iterator itStart(doc, lineRange.start);
Iterator itEnd(doc, lineRange.end);
- std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, lineRange.start, lineRange.end);
- matched = std::regex_search(itStart, itEnd, match, regexp, flagsMatch);
- // Check for the last match on this line.
- if (matched) {
- if (resr.increment == -1) {
- while (matched) {
- Iterator itNext(doc, match[0].second.PosRoundUp());
- flagsMatch = MatchFlags(doc, itNext.Pos(), lineRange.end);
- std::match_results<Iterator> matchNext;
- matched = std::regex_search(itNext, itEnd, matchNext, regexp, flagsMatch);
- if (matched) {
- if (match[0].first == match[0].second) {
- // Empty match means failure so exit
- return false;
- }
- match = matchNext;
- }
- }
- matched = true;
+ const std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, lineRange.start, lineRange.end, lineStartPos, lineEndPos);
+ std::regex_iterator<Iterator> it(itStart, itEnd, regexp, flagsMatch);
+ for (const std::regex_iterator<Iterator> last; it != last; ++it) {
+ match = *it;
+ matched = true;
+ if (resr.increment > 0) {
+ break;
}
+ }
+ if (matched) {
break;
}
}
@@ -3171,7 +3177,6 @@ Sci::Position Cxx11RegexFindText(const Document *doc, Sci::Position minPos, Sci:
std::wregex regexp;
regexp.assign(ws, flagsRe);
matched = MatchOnLines<UTF8Iterator>(doc, regexp, resr, search);
-
} else {
std::regex regexp;
regexp.assign(s, flagsRe);
diff --git a/test/unit/testDocument.cxx b/test/unit/testDocument.cxx
index ca95bda66..52af45167 100644
--- a/test/unit/testDocument.cxx
+++ b/test/unit/testDocument.cxx
@@ -555,6 +555,10 @@ TEST_CASE("Document") {
REQUIRE(match == Match(0));
match = doc.FindString(1, docLength, findingBOL, reCxx11);
REQUIRE(match == Match(10));
+ match = doc.FindString(docLength, 0, findingBOL, reCxx11);
+ REQUIRE(match == Match(10));
+ match = doc.FindString(docLength - 1, 0, findingBOL, reCxx11);
+ REQUIRE(match == Match(10));
#endif
constexpr std::string_view findingEOL = "$";
@@ -567,11 +571,15 @@ TEST_CASE("Document") {
match = doc.FindString(docLength - 1, 0, findingEOL, rePosix);
REQUIRE(match == Match(8));
- #ifndef NO_CXX11_REGEX
+ #if !defined(NO_CXX11_REGEX) && !defined(_LIBCPP_VERSION)
match = doc.FindString(0, docLength, findingEOL, reCxx11);
REQUIRE(match == Match(8));
match = doc.FindString(1, docLength, findingEOL, reCxx11);
REQUIRE(match == Match(8));
+ match = doc.FindString(docLength, 0, findingEOL, reCxx11);
+ REQUIRE(match == Match(18));
+ match = doc.FindString(docLength - 1, 0, findingEOL, reCxx11);
+ REQUIRE(match == Match(8));
#endif
constexpr std::string_view findingBOW = "\\<";
@@ -605,13 +613,32 @@ TEST_CASE("Document") {
match = doc.FindString(0, docLength, findingWB, reCxx11);
REQUIRE(match == Match(0));
match = doc.FindString(1, docLength, findingWB, reCxx11);
- REQUIRE(match == Match(1));
+ REQUIRE(match == Match(2));
+ match = doc.FindString(docLength, 0, findingWB, reCxx11);
+ #ifdef _LIBCPP_VERSION
+ REQUIRE(match == Match(16));
+ #else
+ REQUIRE(match == Match(18));
+ #endif
+ match = doc.FindString(docLength - 1, 0, findingWB, reCxx11);
+ REQUIRE(match == Match(16));
constexpr std::string_view findingNWB = "\\B";
match = doc.FindString(0, docLength, findingNWB, reCxx11);
REQUIRE(match == Match(1));
match = doc.FindString(1, docLength, findingNWB, reCxx11);
- REQUIRE(match == Match(4));
+ REQUIRE(match == Match(1));
+ #ifdef _LIBCPP_VERSION
+ match = doc.FindString(docLength, 0, findingNWB, reCxx11);
+ REQUIRE(match == Match(18));
+ match = doc.FindString(docLength - 1, 0, findingNWB, reCxx11);
+ REQUIRE(match == Match(14));
+ #else
+ match = doc.FindString(docLength, 0, findingNWB, reCxx11);
+ REQUIRE(match == Match(17));
+ match = doc.FindString(docLength - 1, 0, findingNWB, reCxx11);
+ REQUIRE(match == Match(17));
+ #endif
#endif
}
@@ -637,7 +664,7 @@ TEST_CASE("Document") {
match = doc.FindString(0, docLength, "\\b[a-z]", reCxx11);
REQUIRE(match == Match(0, 1));
match = doc.FindString(1, docLength, "\\b[a-z]", reCxx11);
- REQUIRE(match == Match(1, 1)); // Should be (3,1)
+ REQUIRE(match == Match(3, 1));
match = doc.FindString(0, docLength, "[a-z]\\b", reCxx11);
REQUIRE(match == Match(1, 1));
match = doc.FindString(2, docLength, "[a-z]\\b", reCxx11);
@@ -646,7 +673,7 @@ TEST_CASE("Document") {
match = doc.FindString(0, docLength, "\\B[a-z]", reCxx11);
REQUIRE(match == Match(1, 1));
match = doc.FindString(1, docLength, "\\B[a-z]", reCxx11);
- REQUIRE(match == Match(4, 1)); // Should be (1,1)
+ REQUIRE(match == Match(1, 1));
match = doc.FindString(0, docLength, "[a-z]\\B", reCxx11);
REQUIRE(match == Match(0, 1));
match = doc.FindString(2, docLength, "[a-z]\\B", reCxx11);