diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-04-17 14:24:55 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-04-17 14:24:55 +0200 |
commit | 63f4d32c9859c1ed341debefddad4b9c0ae944cc (patch) | |
tree | f386542a9330a9b480519d94779e0e6caf2664dd | |
parent | 71a5b67ba0339265153217df646827a1213e03f5 (diff) | |
download | busybox-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.c | 41 | ||||
-rwxr-xr-x | testsuite/sed.tests | 32 |
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 | ||
336 | testing "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 | |||
342 | testing "sed /regex/,+N{...} addresses work" \ | ||
343 | "sed /^2/,+2{d}" \ | ||
344 | "1\n5\n" \ | ||
345 | "" \ | ||
346 | "1\n2\n3\n4\n5\n" | ||
347 | |||
348 | testing "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 | ||
355 | testing "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 | ||
362 | testing "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 | ||
338 | exit $FAILCOUNT | 370 | exit $FAILCOUNT |