aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2015-04-17 14:24:55 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2015-04-17 14:24:55 +0200
commit63f4d32c9859c1ed341debefddad4b9c0ae944cc (patch)
treef386542a9330a9b480519d94779e0e6caf2664dd
parent71a5b67ba0339265153217df646827a1213e03f5 (diff)
downloadbusybox-w32-63f4d32c9859c1ed341debefddad4b9c0ae944cc.tar.gz
busybox-w32-63f4d32c9859c1ed341debefddad4b9c0ae944cc.tar.bz2
busybox-w32-63f4d32c9859c1ed341debefddad4b9c0ae944cc.zip
sed: implement ",+N" range end
function old new delta add_cmd 1115 1173 +58 process_files 2226 2253 +27 sed_main 696 702 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 91/0) Total: 91 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/sed.c41
-rwxr-xr-xtestsuite/sed.tests32
2 files changed, 68 insertions, 5 deletions
diff --git a/editors/sed.c b/editors/sed.c
index 2c64ad500..7bbf820d8 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -53,6 +53,7 @@
53 * Reference 53 * Reference
54 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html 54 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
55 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html 55 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
56 * http://sed.sourceforge.net/sedfaq3.html
56 */ 57 */
57 58
58//config:config SED 59//config:config SED
@@ -109,7 +110,8 @@ typedef struct sed_cmd_s {
109 regex_t *sub_match; /* For 's/sub_match/string/' */ 110 regex_t *sub_match; /* For 's/sub_match/string/' */
110 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ 111 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */
111 int beg_line_orig; /* copy of the above, needed for -i */ 112 int beg_line_orig; /* copy of the above, needed for -i */
112 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ 113 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($). -2-N = +N */
114 int end_line_orig;
113 115
114 FILE *sw_file; /* File (sw) command writes to, -1 for none. */ 116 FILE *sw_file; /* File (sw) command writes to, -1 for none. */
115 char *string; /* Data string for (saicytb) commands. */ 117 char *string; /* Data string for (saicytb) commands. */
@@ -640,10 +642,29 @@ static void add_cmd(const char *cmdstr)
640 int idx; 642 int idx;
641 643
642 cmdstr++; 644 cmdstr++;
643 idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match); 645 if (*cmdstr == '+' && isdigit(cmdstr[1])) {
644 if (!idx) 646 /* http://sed.sourceforge.net/sedfaq3.html#s3.3
647 * Under GNU sed 3.02+, ssed, and sed15+, <address2>
648 * may also be a notation of the form +num,
649 * indicating the next num lines after <address1> is
650 * matched.
651 * GNU sed 4.2.1 accepts even "+" (meaning "+0").
652 * We don't (we check for isdigit, see above), think
653 * about the "+-3" case.
654 */
655 char *end;
656 /* code is smaller compared to using &cmdstr here: */
657 idx = strtol(cmdstr+1, &end, 10);
658 sed_cmd->end_line = -2 - idx;
659 cmdstr = end;
660 } else {
661 idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
662 cmdstr += idx;
663 idx--; /* if 0, trigger error check below */
664 }
665 if (idx < 0)
645 bb_error_msg_and_die("no address after comma"); 666 bb_error_msg_and_die("no address after comma");
646 cmdstr += idx; 667 sed_cmd->end_line_orig = sed_cmd->end_line;
647 } 668 }
648 669
649 /* skip whitespace before the command */ 670 /* skip whitespace before the command */
@@ -1089,10 +1110,19 @@ static void process_files(void)
1089 /* Is this line the end of the current match? */ 1110 /* Is this line the end of the current match? */
1090 1111
1091 if (matched) { 1112 if (matched) {
1113 if (sed_cmd->end_line <= -2) {
1114 /* address2 is +N, i.e. N lines from beg_line */
1115 sed_cmd->end_line = linenum + (-sed_cmd->end_line - 2);
1116 }
1092 /* once matched, "n,xxx" range is dead, disabling it */ 1117 /* once matched, "n,xxx" range is dead, disabling it */
1093 if (sed_cmd->beg_line > 0) { 1118 if (sed_cmd->beg_line > 0) {
1094 sed_cmd->beg_line = -2; 1119 sed_cmd->beg_line = -2;
1095 } 1120 }
1121 dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1
1122 ? !next_line : (sed_cmd->end_line <= linenum)
1123 : !sed_cmd->end_match);
1124 dbg("end2:%d", sed_cmd->end_match && old_matched
1125 && !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0));
1096 sed_cmd->in_match = !( 1126 sed_cmd->in_match = !(
1097 /* has the ending line come, or is this a single address command? */ 1127 /* has the ending line come, or is this a single address command? */
1098 (sed_cmd->end_line 1128 (sed_cmd->end_line
@@ -1551,9 +1581,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1551 free(G.outname); 1581 free(G.outname);
1552 G.outname = NULL; 1582 G.outname = NULL;
1553 1583
1554 /* Re-enable disabled range matches */ 1584 /* Fix disabled range matches and mangled ",+N" ranges */
1555 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { 1585 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
1556 sed_cmd->beg_line = sed_cmd->beg_line_orig; 1586 sed_cmd->beg_line = sed_cmd->beg_line_orig;
1587 sed_cmd->end_line = sed_cmd->end_line_orig;
1557 } 1588 }
1558 } 1589 }
1559 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1590 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 19f2915ce..34479e55f 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -333,6 +333,38 @@ testing "sed s///NUM test" \
333 "sed -e 's/a/b/2; s/a/c/g'" \ 333 "sed -e 's/a/b/2; s/a/c/g'" \
334 "cb\n" "" "aa\n" 334 "cb\n" "" "aa\n"
335 335
336testing "sed /regex/,N{...} addresses work" \
337 "sed /^2/,2{d}" \
338 "1\n3\n4\n5\n" \
339 "" \
340 "1\n2\n3\n4\n5\n"
341
342testing "sed /regex/,+N{...} addresses work" \
343 "sed /^2/,+2{d}" \
344 "1\n5\n" \
345 "" \
346 "1\n2\n3\n4\n5\n"
347
348testing "sed /regex/,+N{...} -i works" \
349 "cat - >input2; sed /^4/,+2{d} -i input input2; echo \$?; cat input input2; rm input2" \
350 "0\n""1\n2\n3\n7\n8\n""1\n2\n7\n8\n" \
351 "1\n2\n3\n4\n5\n6\n7\n8\n" \
352 "1\n2\n4\n5\n6\n7\n8\n" \
353
354# GNU sed 4.2.1 would also accept "/^4/,+{d}" with the same meaning, we don't
355testing "sed /regex/,+0{...} -i works" \
356 "cat - >input2; sed /^4/,+0{d} -i input input2; echo \$?; cat input input2; rm input2" \
357 "0\n""1\n2\n3\n5\n6\n7\n8\n""1\n2\n5\n6\n7\n8\n" \
358 "1\n2\n3\n4\n5\n6\n7\n8\n" \
359 "1\n2\n4\n5\n6\n7\n8\n" \
360
361# GNU sed 4.2.1 would also accept "/^4/,+d" with the same meaning, we don't
362testing "sed /regex/,+0<cmd> -i works" \
363 "cat - >input2; sed /^4/,+0d -i input input2; echo \$?; cat input input2; rm input2" \
364 "0\n""1\n2\n3\n5\n6\n7\n8\n""1\n2\n5\n6\n7\n8\n" \
365 "1\n2\n3\n4\n5\n6\n7\n8\n" \
366 "1\n2\n4\n5\n6\n7\n8\n" \
367
336# testing "description" "commands" "result" "infile" "stdin" 368# testing "description" "commands" "result" "infile" "stdin"
337 369
338exit $FAILCOUNT 370exit $FAILCOUNT