1015
1012
return static_cast<char>(ch - 'A' + 'a');
1018
// Define a way for the Regular Expression code to access the document
1019
class DocumentIndexer : public CharacterIndexer {
1023
DocumentIndexer(Document *pdoc_, int end_) :
1024
pdoc(pdoc_), end(end_) {
1027
virtual ~DocumentIndexer() {
1030
virtual char CharAt(int index) {
1031
if (index < 0 || index >= end)
1034
return pdoc->CharAt(index);
1039
1016
* Find text in document, supporting both forward and backward
1040
1017
* searches (just pass minPos > maxPos to do a backward search)
1041
1018
* Has not been tested with backwards DBCS searches yet.
1043
1020
long Document::FindText(int minPos, int maxPos, const char *s,
1044
bool caseSensitive, bool word, bool wordStart, bool regExp, bool posix,
1021
bool caseSensitive, bool word, bool wordStart, bool regExp, int flags,
1048
pre = new RESearch(&charClass);
1052
int increment = (minPos <= maxPos) ? 1 : -1;
1054
int startPos = minPos;
1055
int endPos = maxPos;
1057
// Range endpoints should not be inside DBCS characters, but just in case, move them.
1058
startPos = MovePositionOutsideChar(startPos, 1, false);
1059
endPos = MovePositionOutsideChar(endPos, 1, false);
1061
const char *errmsg = pre->Compile(s, *length, caseSensitive, posix);
1065
// Find a variable in a property file: \$(\([A-Za-z0-9_.]+\))
1066
// Replace first '.' with '-' in each property file variable reference:
1067
// Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\))
1068
// Replace: $(\1-\2)
1069
int lineRangeStart = LineFromPosition(startPos);
1070
int lineRangeEnd = LineFromPosition(endPos);
1071
if ((increment == 1) &&
1072
(startPos >= LineEnd(lineRangeStart)) &&
1073
(lineRangeStart < lineRangeEnd)) {
1074
// the start position is at end of line or between line end characters.
1076
startPos = LineStart(lineRangeStart);
1080
char searchEnd = s[*length - 1];
1081
int lineRangeBreak = lineRangeEnd + increment;
1082
for (int line = lineRangeStart; line != lineRangeBreak; line += increment) {
1083
int startOfLine = LineStart(line);
1084
int endOfLine = LineEnd(line);
1085
if (increment == 1) {
1086
if (line == lineRangeStart) {
1087
if ((startPos != startOfLine) && (s[0] == '^'))
1088
continue; // Can't match start of line if start position after start of line
1089
startOfLine = startPos;
1091
if (line == lineRangeEnd) {
1092
if ((endPos != endOfLine) && (searchEnd == '$'))
1093
continue; // Can't match end of line if end position before end of line
1097
if (line == lineRangeEnd) {
1098
if ((endPos != startOfLine) && (s[0] == '^'))
1099
continue; // Can't match start of line if end position after start of line
1100
startOfLine = endPos;
1102
if (line == lineRangeStart) {
1103
if ((startPos != endOfLine) && (searchEnd == '$'))
1104
continue; // Can't match end of line if start position before end of line
1105
endOfLine = startPos;
1109
DocumentIndexer di(this, endOfLine);
1110
int success = pre->Execute(di, startOfLine, endOfLine);
1112
pos = pre->bopat[0];
1113
lenRet = pre->eopat[0] - pre->bopat[0];
1114
if (increment == -1) {
1115
// Check for the last match on this line.
1116
int repetitions = 1000; // Break out of infinite loop
1117
while (success && (pre->eopat[0] <= endOfLine) && (repetitions--)) {
1118
success = pre->Execute(di, pos+1, endOfLine);
1120
if (pre->eopat[0] <= minPos) {
1121
pos = pre->bopat[0];
1122
lenRet = pre->eopat[0] - pre->bopat[0];
1025
regex = CreateRegexSearch(&charClass);
1026
return regex->FindText(this, minPos, maxPos, s, caseSensitive, word, wordStart, flags, length);
1137
1029
bool forward = minPos <= maxPos;
1203
1095
const char *Document::SubstituteByPosition(const char *text, int *length) {
1206
delete []substituted;
1208
DocumentIndexer di(this, Length());
1209
if (!pre->GrabMatches(di))
1211
unsigned int lenResult = 0;
1212
for (int i = 0; i < *length; i++) {
1213
if (text[i] == '\\') {
1214
if (text[i + 1] >= '1' && text[i + 1] <= '9') {
1215
unsigned int patNum = text[i + 1] - '0';
1216
lenResult += pre->eopat[patNum] - pre->bopat[patNum];
1219
switch (text[i + 1]) {
1235
substituted = new char[lenResult + 1];
1238
char *o = substituted;
1239
for (int j = 0; j < *length; j++) {
1240
if (text[j] == '\\') {
1241
if (text[j + 1] >= '1' && text[j + 1] <= '9') {
1242
unsigned int patNum = text[j + 1] - '0';
1243
unsigned int len = pre->eopat[patNum] - pre->bopat[patNum];
1244
if (pre->pat[patNum]) // Will be null if try for a match that did not occur
1245
memcpy(o, pre->pat[patNum], len);
1282
*length = lenResult;
1096
return regex->SubstituteByPosition(this, text, length);
1286
1099
int Document::LinesTotal() const {
1448
* Implementation of RegexSearchBase for the default built-in regular expression engine
1450
class BuiltinRegex : public RegexSearchBase {
1452
BuiltinRegex(CharClassify *charClassTable) : search(charClassTable), substituted(NULL) {}
1454
virtual ~BuiltinRegex() {
1458
virtual long FindText(Document *doc, int minPos, int maxPos, const char *s,
1459
bool caseSensitive, bool word, bool wordStart, int flags,
1462
virtual const char *SubstituteByPosition(Document* doc, const char *text, int *length);
1469
// Define a way for the Regular Expression code to access the document
1470
class DocumentIndexer : public CharacterIndexer {
1474
DocumentIndexer(Document *pdoc_, int end_) :
1475
pdoc(pdoc_), end(end_) {
1478
virtual ~DocumentIndexer() {
1481
virtual char CharAt(int index) {
1482
if (index < 0 || index >= end)
1485
return pdoc->CharAt(index);
1489
long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s,
1490
bool caseSensitive, bool, bool, int flags,
1492
bool posix = (flags & SCFIND_POSIX) != 0;
1493
int increment = (minPos <= maxPos) ? 1 : -1;
1495
int startPos = minPos;
1496
int endPos = maxPos;
1498
// Range endpoints should not be inside DBCS characters, but just in case, move them.
1499
startPos = doc->MovePositionOutsideChar(startPos, 1, false);
1500
endPos = doc->MovePositionOutsideChar(endPos, 1, false);
1502
const char *errmsg = search.Compile(s, *length, caseSensitive, posix);
1506
// Find a variable in a property file: \$(\([A-Za-z0-9_.]+\))
1507
// Replace first '.' with '-' in each property file variable reference:
1508
// Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\))
1509
// Replace: $(\1-\2)
1510
int lineRangeStart = doc->LineFromPosition(startPos);
1511
int lineRangeEnd = doc->LineFromPosition(endPos);
1512
if ((increment == 1) &&
1513
(startPos >= doc->LineEnd(lineRangeStart)) &&
1514
(lineRangeStart < lineRangeEnd)) {
1515
// the start position is at end of line or between line end characters.
1517
startPos = doc->LineStart(lineRangeStart);
1521
char searchEnd = s[*length - 1];
1522
int lineRangeBreak = lineRangeEnd + increment;
1523
for (int line = lineRangeStart; line != lineRangeBreak; line += increment) {
1524
int startOfLine = doc->LineStart(line);
1525
int endOfLine = doc->LineEnd(line);
1526
if (increment == 1) {
1527
if (line == lineRangeStart) {
1528
if ((startPos != startOfLine) && (s[0] == '^'))
1529
continue; // Can't match start of line if start position after start of line
1530
startOfLine = startPos;
1532
if (line == lineRangeEnd) {
1533
if ((endPos != endOfLine) && (searchEnd == '$'))
1534
continue; // Can't match end of line if end position before end of line
1538
if (line == lineRangeEnd) {
1539
if ((endPos != startOfLine) && (s[0] == '^'))
1540
continue; // Can't match start of line if end position after start of line
1541
startOfLine = endPos;
1543
if (line == lineRangeStart) {
1544
if ((startPos != endOfLine) && (searchEnd == '$'))
1545
continue; // Can't match end of line if start position before end of line
1546
endOfLine = startPos;
1550
DocumentIndexer di(doc, endOfLine);
1551
int success = search.Execute(di, startOfLine, endOfLine);
1553
pos = search.bopat[0];
1554
lenRet = search.eopat[0] - search.bopat[0];
1555
if (increment == -1) {
1556
// Check for the last match on this line.
1557
int repetitions = 1000; // Break out of infinite loop
1558
while (success && (search.eopat[0] <= endOfLine) && (repetitions--)) {
1559
success = search.Execute(di, pos+1, endOfLine);
1561
if (search.eopat[0] <= minPos) {
1562
pos = search.bopat[0];
1563
lenRet = search.eopat[0] - search.bopat[0];
1577
const char *BuiltinRegex::SubstituteByPosition(Document* doc, const char *text, int *length) {
1578
delete []substituted;
1580
DocumentIndexer di(doc, doc->Length());
1581
if (!search.GrabMatches(di))
1583
unsigned int lenResult = 0;
1584
for (int i = 0; i < *length; i++) {
1585
if (text[i] == '\\') {
1586
if (text[i + 1] >= '1' && text[i + 1] <= '9') {
1587
unsigned int patNum = text[i + 1] - '0';
1588
lenResult += search.eopat[patNum] - search.bopat[patNum];
1591
switch (text[i + 1]) {
1607
substituted = new char[lenResult + 1];
1610
char *o = substituted;
1611
for (int j = 0; j < *length; j++) {
1612
if (text[j] == '\\') {
1613
if (text[j + 1] >= '1' && text[j + 1] <= '9') {
1614
unsigned int patNum = text[j + 1] - '0';
1615
unsigned int len = search.eopat[patNum] - search.bopat[patNum];
1616
if (search.pat[patNum]) // Will be null if try for a match that did not occur
1617
memcpy(o, search.pat[patNum], len);
1654
*length = lenResult;
1658
#ifndef SCI_OWNREGEX
1660
RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable) {
1661
return new BuiltinRegex(charClassTable);