[PATCH 1/1] sed: /regex/,+N ranges

Bernhard Reutner-Fischer rep.dot.nop at gmail.com
Tue Apr 14 23:35:54 UTC 2015


function                                             old     new   delta
add_cmd                                             1207    1359    +152
process_files                                       2502    2530     +28
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 180/0)             Total: 180 bytes

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
---
 editors/sed.c       | 36 +++++++++++++++++++++++++++++++-----
 testsuite/sed.tests | 12 ++++++++++++
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/editors/sed.c b/editors/sed.c
index 2c64ad5..7d7e17c 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -640,10 +640,25 @@ static void add_cmd(const char *cmdstr)
 			int idx;
 
 			cmdstr++;
-			idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
+			if (*cmdstr == '+') {
+				/* http://sed.sourceforge.net/sedfaq3.html#s3.3
+				 * Under GNU sed 3.02+, ssed, and sed15+, <address2>
+				 * may also be a notation of the form +num,
+				 * indicating the next num lines after <address1> is
+				 * matched. */
+				/* Set both end_line and end_match to distinguish this case */
+				idx = strtol(cmdstr, (char**)&cmdstr, 10);
+				if (cmdstr == NULL)
+					idx = 0;
+				sed_cmd->end_line = idx;
+				sed_cmd->end_match = xzalloc(sizeof(regex_t));
+				xregcomp(sed_cmd->end_match, ".*", REG_EXTENDED);
+			} else {
+				idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
+				cmdstr += idx;
+			}
 			if (!idx)
 				bb_error_msg_and_die("no address after comma");
-			cmdstr += idx;
 		}
 
 		/* skip whitespace before the command */
@@ -1089,10 +1104,21 @@ static void process_files(void)
 		/* Is this line the end of the current match? */
 
 		if (matched) {
-			/* once matched, "n,xxx" range is dead, disabling it */
-			if (sed_cmd->beg_line > 0) {
-				sed_cmd->beg_line = -2;
+			if (sed_cmd->end_line && sed_cmd->end_match) {
+				/* address2 is +N, i.e. N lines from beg_line */
+				sed_cmd->end_line--;
+				sed_cmd->beg_line++;
+			} else {
+				/* once matched, "n,xxx" range is dead, disabling it */
+				if (sed_cmd->beg_line > 0) {
+					sed_cmd->beg_line = -2;
+				}
 			}
+			dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1
+						? !next_line : (sed_cmd->end_line <= linenum)
+					: !sed_cmd->end_match);
+			dbg("end2:%d", sed_cmd->end_match && old_matched
+					&& !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0));
 			sed_cmd->in_match = !(
 				/* has the ending line come, or is this a single address command? */
 				(sed_cmd->end_line
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 19f2915..399230f 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -333,6 +333,18 @@ testing "sed s///NUM test" \
 	"sed -e 's/a/b/2; s/a/c/g'" \
 	"cb\n" "" "aa\n"
 
+testing "sed /regex/,N/{} addresses work" \
+	"sed /^2/,2{d}" \
+	"1\n3\n4\n5\n" \
+	"" \
+	"1\n2\n3\n4\n5\n"
+
+testing "sed /regex/,+N/{} addresses work" \
+	"sed /^2/,+2{d}" \
+	"1\n5\n" \
+	"" \
+	"1\n2\n3\n4\n5\n"
+
 # testing "description" "commands" "result" "infile" "stdin"
 
 exit $FAILCOUNT
-- 
2.1.4



More information about the busybox mailing list