summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Smith <chris@jalakai.co.uk>2015-05-28 16:37:32 +0100
committerChristopher Smith <chris@jalakai.co.uk>2015-05-28 17:03:06 +0100
commit9a734b7aaba1445e06c1ccb95e59f54e01688d45 (patch)
tree1a84c75c8f7c98de1c149c443f17a9422a8be5df
parent2b71c2eece46d1e977fa596ed57b74e04a9aaf6b (diff)
downloadrpg-9a734b7aaba1445e06c1ccb95e59f54e01688d45.tar.gz
rpg-9a734b7aaba1445e06c1ccb95e59f54e01688d45.tar.bz2
Refactor code to make it simpler.
The changes should also: - fix unlikely edge case when replacement line is the same as the old line (would have resulted in timeout) - reduce memory footprint - avoid applying string search beyond maxlines replacement limit
-rw-r--r--_test/tests/inc/io_replaceinfile.test.php28
-rw-r--r--inc/io.php35
2 files changed, 41 insertions, 22 deletions
diff --git a/_test/tests/inc/io_replaceinfile.test.php b/_test/tests/inc/io_replaceinfile.test.php
index 98f21868f..c2dbc0dd4 100644
--- a/_test/tests/inc/io_replaceinfile.test.php
+++ b/_test/tests/inc/io_replaceinfile.test.php
@@ -2,6 +2,8 @@
class io_replaceinfile_test extends DokuWikiTest {
+ protected $contents = "The\012Delete\012Delete\012Delete01\012Delete02\012Delete\012DeleteX\012Test\012";
+
/*
* dependency for tests needing zlib extension to pass
*/
@@ -21,8 +23,8 @@ class io_replaceinfile_test extends DokuWikiTest {
}
function _write($file){
- $contents = "The\012Delete\012Delete\012Delete01\012Delete02\012Delete\012DeleteX\012Test\012";
- io_saveFile($file, $contents);
+
+ io_saveFile($file, $this->contents);
// Replace one, no regex
$this->assertTrue(io_replaceInFile($file, "Delete\012", "Delete00\012", false, 1));
$this->assertEquals("The\012Delete00\012Delete\012Delete01\012Delete02\012Delete\012DeleteX\012Test\012", io_readFile($file));
@@ -41,6 +43,7 @@ class io_replaceinfile_test extends DokuWikiTest {
$this->_write(TMP_DIR.'/test.txt');
}
+
/**
* @depends test_ext_zlib
*/
@@ -55,4 +58,25 @@ class io_replaceinfile_test extends DokuWikiTest {
$this->_write(TMP_DIR.'/test.txt.bz2');
}
+ /**
+ *
+ */
+ function test_edgecase1()
+ {
+ $file = TMP_DIR . '/test.txt';
+ // Replace all, no regex, backreference like construct in replacement line
+ io_saveFile($file, $this->contents);
+ $this->assertTrue(io_replaceInFile($file, "Delete\012", "Delete\\00\012", false, -1));
+ $this->assertEquals("The\012Delete\\00\012Delete\\00\012Delete01\012Delete02\012Delete\\00\012DeleteX\012Test\012", io_readFile($file), "Edge case: backreference like construct in replacement line");
+ }
+ /**
+ * @small
+ */
+ function test_edgecase2() {
+ $file = TMP_DIR.'/test.txt';
+ // Replace all, no regex, replacement line == search line
+ io_saveFile($file, $this->contents);
+ $this->assertTrue(io_replaceInFile($file, "Delete\012", "Delete\012", false, -1));
+ $this->assertEquals("The\012Delete\012Delete\012Delete01\012Delete02\012Delete\012DeleteX\012Test\012", io_readFile($file), "Edge case: new line the same as old line");
+ }
}
diff --git a/inc/io.php b/inc/io.php
index dbb42114b..51ca2ea14 100644
--- a/inc/io.php
+++ b/inc/io.php
@@ -311,28 +311,23 @@ function io_replaceInFile($file, $oldline, $newline, $regex=false, $maxlines=0)
$lines = file($file);
}
- // remove all matching lines
- if ($regex) {
- if($maxlines > 0) {
- $matches = preg_grep($oldline, $lines);
- $count = 0;
- foreach($matches as $ix=>$m) {
- $lines[$ix] = preg_replace($oldline, $newline, $m);
- if(++$count >= $maxlines) break;
- }
- } else {
- $lines = ($maxlines == 0) ? preg_grep($oldline, $lines, PREG_GREP_INVERT)
- : preg_replace($oldline, $newline, $lines, $maxlines);
- }
- } else {
+ // make non-regexes into regexes
+ $pattern = $regex ? $oldline : '/'.preg_quote($oldline,'/').'/';
+ $replace = $regex ? $newline : addcslashes($newline, '\$');
+
+ // remove matching lines
+ if ($maxlines > 0) {
$count = 0;
- $replaceline = $maxlines == 0 ? '' : $newline;
- $pos = array_search($oldline,$lines); //return null or false if not found
- while(is_int($pos)){
- $lines[$pos] = $replaceline;
- if($maxlines > 0 && ++$count >= $maxlines) break;
- $pos = array_search($oldline,$lines);
+ $matched = 0;
+ while (($count < $maxlines) && (list($i,$line) = each($lines))) {
+ // $matched will be set to 0|1 depending on whether pattern is matched and line replaced
+ $lines[$i] = preg_replace($pattern, $replace, $line, -1, $matched);
+ if ($matched) $count++;
}
+ } else {
+ $lines = ($maxlines == 0) ?
+ preg_grep($pattern, $lines, PREG_GREP_INVERT) :
+ preg_replace($pattern, $replace, $lines);
}
if($maxlines == 0 && ((string)$newline) !== '') {