void ScintillaWrapper::pyreplace(boost::python::object searchExp, boost::python::object replaceStr, boost::python::object count, boost::python::object flags, boost::python::object startLine, boost::python::object endLine) { boost::python::object re_module( (boost::python::handle<>(PyImport_ImportModule("re"))) ); if (!re_module.is_none()) { BeginUndoAction(); const char *strCount = boost::python::extract<const char *>(count.attr("__str__")()); int iCount; int iFlags = 0; if (!flags.is_none()) { iFlags = boost::python::extract<int>(flags); } int start = 0; if (!startLine.is_none()) { start = boost::python::extract<int>(startLine); } int end = -1; if (!startLine.is_none()) { end = boost::python::extract<int>(endLine); } iCount = atoi(strCount); bool ignoreCount = (iCount == 0); bool includeLineEndings = (iFlags & RE_INCLUDELINEENDINGS) == RE_INCLUDELINEENDINGS; long lineCount = GetLineCount(); boost::python::object re = re_module.attr("compile")(searchExp, flags); size_t bufferLength = 0; Sci_TextRange range; range.chrg.cpMin = 0; range.lpstrText = NULL; boost::python::tuple result; idx_t currentStartPosition; int infiniteLoopCheck = 0; int previousLine = -1; for(int line = start; line < lineCount && (ignoreCount || iCount > 0) && (-1 == end || line <= end); ++line) { if (line == previousLine) { if (++infiniteLoopCheck >= 1000) { EndUndoAction(); PyErr_SetString(PyExc_SystemError, "Infinite loop detected in pyreplace"); if (range.lpstrText) { delete[] range.lpstrText; } throw boost::python::error_already_set(); } } previousLine = line; if (includeLineEndings) { result = boost::python::extract<boost::python::tuple>(re.attr("subn")(replaceStr, GetLine(line), ignoreCount ? 0 : iCount)); } else { range.chrg.cpMin = PositionFromLine(line); range.chrg.cpMax = GetLineEndPosition(line); if (bufferLength < (size_t)((range.chrg.cpMax - range.chrg.cpMin) + 1)) { if (range.lpstrText) delete [] range.lpstrText; bufferLength = (size_t)((range.chrg.cpMax - range.chrg.cpMin) + 1); range.lpstrText = new char[bufferLength + 1]; } callScintilla(SCI_GETTEXTRANGE, 0, reinterpret_cast<LPARAM>(&range)); result = boost::python::extract<boost::python::tuple>(re.attr("subn")(replaceStr, const_cast<const char *>(range.lpstrText), ignoreCount ? 0 : iCount)); } int numSubs = boost::python::extract<int>(result[1]); if (numSubs != 0) { size_t resultLength = _len(result[0]); if (includeLineEndings) { currentStartPosition = (idx_t)PositionFromLine(line); replaceWholeLine(line, result[0]); } else { currentStartPosition = (idx_t)range.chrg.cpMin; replaceLine(line, result[0]); } int newLine = LineFromPosition((int)(currentStartPosition + resultLength)); // If the line number has moved on more than one // there must have been one or more new lines in the // replacement, or no newline, hence the lines have become less if ((newLine - line) != (includeLineEndings ? 1 : 0)) { line = newLine - (includeLineEndings ? 1 : 0); lineCount = GetLineCount(); } iCount -= numSubs; } } if (range.lpstrText) delete[] range.lpstrText; EndUndoAction(); } }
void ScintillaWrapper::pymlreplace(boost::python::object searchExp, boost::python::object replaceStr, boost::python::object count, boost::python::object flags, boost::python::object startPosition, boost::python::object endPosition) { boost::python::str contents; offset_t currentOffset = 0; if (startPosition.is_none() && endPosition.is_none()) { contents = GetCharacterPointer(); } else { Sci_TextRange range; if (!startPosition.is_none()) { range.chrg.cpMin = boost::python::extract<int>(startPosition); } else { range.chrg.cpMin = 0; } if (!endPosition.is_none()) { range.chrg.cpMax = boost::python::extract<int>(endPosition); } else { range.chrg.cpMax = GetLength(); } currentOffset = (offset_t)range.chrg.cpMin; range.lpstrText = new char[size_t((range.chrg.cpMax - range.chrg.cpMin) + 1)]; callScintilla(SCI_GETTEXTRANGE, 0, reinterpret_cast<LPARAM>(&range)); contents = boost::python::str(const_cast<const char *>(range.lpstrText)); delete[] range.lpstrText; } boost::python::object re_module( (boost::python::handle<>(PyImport_ImportModule("re"))) ); int iFlags = 0; int iCount = 0; if (!flags.is_none()) { iFlags = boost::python::extract<int>(flags); } if (!count.is_none()) { iCount = boost::python::extract<int>(count); } if (0 == iCount) iCount = -1; boost::python::object re = re_module.attr("compile")(searchExp, iFlags | boost::python::extract<int>(re_module.attr("MULTILINE"))); if (!re_module.is_none()) { boost::python::object match; BeginUndoAction(); boost::python::object oreplacement; size_t replacementLength; idx_t matchStart, matchEnd; idx_t startPos = 0; do { match = re.attr("search")(contents, startPos); if (!match.is_none()) { // Get expanded replacement string oreplacement = match.attr("expand")(replaceStr); // Calculate offsets matchStart = (idx_t)boost::python::extract<int>(match.attr("start")()); matchEnd = (idx_t)boost::python::extract<int>(match.attr("end")()); // Extract text replacement const char *replacement = boost::python::extract<const char *>(oreplacement); replacementLength = _len(oreplacement); // Replace text in Scintilla callScintilla(SCI_SETTARGETSTART, static_cast<offset_t>(matchStart) + currentOffset); callScintilla(SCI_SETTARGETEND, static_cast<offset_t>(matchEnd) + currentOffset); callScintilla(SCI_REPLACETARGET, replacementLength, reinterpret_cast<LPARAM>(replacement)); // Calculate the difference between the old string, // and the new replacement, and add it to the currentOffset currentOffset += static_cast<offset_t>(replacementLength - (matchEnd - matchStart)); // Set startPos to the end of the last match - startPos is with the original document startPos = matchEnd; } } while(!match.is_none() && (iCount == -1 || --iCount > 0)); EndUndoAction(); } }
String& String::insert (int pos, String str) { if (_ref (buf) > 1) splice (); if (pos < 0) pos += _len (buf); if (pos < 0) pos = 0; if (pos > _len (buf)) pos = _len (buf); realloc (_len (buf) + _len (str.buf)); if (pos < _len (buf)) memmove (buf + pos + _len (str.buf), buf + pos, _len (buf) - pos); if (_len (str.buf)) memcpy (buf + pos, str.buf, _len (str.buf)); buf[_len (buf) += _len (str.buf)] = 0; return *this; }
String& String::replace (int start, int len, char const* str) { if (_ref (buf) > 1) splice (); int strLength = (int) strlen (str); if (start < 0) start += _len (buf); if (start < 0) start = 0; if (start > _len (buf)) start = _len (buf); if (len == toTheEnd) len = _len (buf) - start; else if (len < 0) len += _len (buf) - start; else if (start + len > _len (buf)) len = _len (buf) - start; if (len < 0) len = 0; int newlen = _len (buf) - len + strLength; realloc (newlen); int b = start + len; int bnew = start + strLength; if (b < _len (buf)) memmove (buf + bnew, buf + b, _len (buf) - b); if (strLength) memcpy (buf + start, str, strLength); buf[newlen] = 0; _len (buf) = newlen; return *this; }
int String::find (char const* str, int start, int options) const { static int kmpbuf[256]; #define comp(a,b) (options&FIND_CASE_INSENSITIVE?tolower((unsigned char)a)==tolower((unsigned char)b):(a)==(b)) if (start < 0) start += _len (buf); if (start < 0) start = 0; if (start > _len (buf)) start = _len (buf); if (*str == 0) return start; int len = (int) strlen (str); int* kmp = kmpbuf; if (len > 256) kmp = new int[len]; kmp[0] = 0; int result = -1; if (options & FIND_REVERSE) { for (int i = 1; i < len; i++) { kmp[i] = kmp[i - 1]; while (kmp[i] && !comp (str[len - 1 - kmp[i]], str[len - 1 - i])) kmp[i] = kmp[kmp[i] - 1]; if (comp (str[len - 1 - kmp[i]], str[len - 1 - i])) kmp[i]++; } int cur = 0; for (int i = start - 1; i >= 0; i--) { while (cur && !comp (str[len - 1 - cur], buf[_len (buf) - 1 - i])) cur = kmp[cur - 1]; if (comp (str[len - 1 - cur], buf[_len (buf) - 1 - i])) cur++; if (cur == len) { if ((options & FIND_WHOLE_WORD) == 0 || ( isWordBoundary (i) && isWordBoundary (i + len))) { result = i; break; } } } } else { for (int i = 1; i < len; i++) { kmp[i] = kmp[i - 1]; while (kmp[i] && !comp (str[kmp[i]], str[i])) kmp[i] = kmp[kmp[i] - 1]; if (comp (str[kmp[i]], str[i])) kmp[i]++; } int cur = 0; for (int i = start; i < _len (buf); i++) { while (cur && !comp (str[cur], buf[i])) cur = kmp[cur - 1]; if (comp (str[cur], buf[i])) cur++; if (cur == len) { if ((options & FIND_WHOLE_WORD) == 0 || ( isWordBoundary (i - len + 1) && isWordBoundary (i + 1))) { result = i - len + 1; break; } } } } if (kmp != kmpbuf) delete[] kmp; return result; }
bool String::isWordBoundary (int pos) const { return pos <= 0 || pos >= _len (buf) || isIdChar (buf[pos]) != isIdChar (buf[pos - 1]); }