aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/sed.test6
-rw-r--r--toys/posix/sed.c23
2 files changed, 20 insertions, 9 deletions
diff --git a/tests/sed.test b/tests/sed.test
index e5ec11bd..98c109ad 100755
--- a/tests/sed.test
+++ b/tests/sed.test
@@ -151,6 +151,12 @@ testing "trailing a\ (for debian)" "sed 'a\\'" "hello\n" "" "hello"
# You have to match the first line of a range in order to activate
# the range, numeric and ascii work the same way
testing "skip start of range" "sed -e n -e '1,2s/b/c/'" "a\nb\n" "" "a\nb\n"
+testing "range +1" "sed -ne '/blah/,+1p'" "blah\n6\n" "" \
+ "1\n2\n3\n4\n5\nblah\n6\n7\n8\n9\n"
+testing "range +0" "sed -ne '/blah/,+0p'" "blah\n" "" \
+ "1\n2\n3\n4\n5\nblah\n6\n7\n8\n9\n"
+testing "range +3" "sed -ne '2,+3p'" "2\n3\n4\n5\n" "" \
+ "1\n2\n3\n4\n5\nblah\n6\n7\n8\n9\n"
#echo meep | sed/sed -e '1a\' -e 'huh'
#echo blah | sed/sed -f <(echo -e "1a\\\\\nboom")
diff --git a/toys/posix/sed.c b/toys/posix/sed.c
index 4e81001a..979a6eb8 100644
--- a/toys/posix/sed.c
+++ b/toys/posix/sed.c
@@ -49,7 +49,7 @@ config SED
address matches one line, a pair of comma separated addresses match
everything from the first address to the second address (inclusive). If
both addresses are regular expressions, more than one range of lines in
- each file can match.
+ each file can match. The second address can be +N to end N lines later.
REGULAR EXPRESSIONS in sed are started and ended by the same character
(traditionally / but anything except a backslash or a newline works).
@@ -214,7 +214,7 @@ static int emit(char *line, long len, int eol)
l = writeall(TT.fdout, line, len);
if (eol) line[len-1] = old;
if (l != len) {
- perror_msg("short write");
+ if (TT.fdout != 1) perror_msg("short write");
return 1;
}
@@ -304,20 +304,23 @@ static void sed_line(char **pline, long plen)
if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
}
} else if (lm > 0 && lm < TT.count) command->hit = 0;
+ else if (lm < -1 && TT.count == command->hit+(-lm-1)) command->hit = 0;
// Start a new match?
} else {
if (!(lm = *command->lmatch)) {
void *rm = get_regex(command, *command->rmatch);
- if (line && !regexec0(rm, line, len, 0, 0, 0)) command->hit++;
- } else if (lm == TT.count || (lm == -1 && !pline)) command->hit++;
+ if (line && !regexec0(rm, line, len, 0, 0, 0))
+ command->hit = TT.count;
+ } else if (lm == TT.count || (lm == -1 && !pline))
+ command->hit = TT.count;
if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
}
// Didn't match?
- lm = !(command->hit ^ command->not);
+ lm = !(command->not^!!command->hit);
// Deferred disable from regex end match
if (miss || command->lmatch[1] == TT.count) command->hit = 0;
@@ -779,8 +782,7 @@ static void parse_pattern(char **pline, long len)
}
if (!*line) return;
- // We start by writing data into toybuf. Later we'll allocate the
- // ex
+ // Start by writing data into toybuf.
errstart = line;
memset(toybuf, 0, sizeof(struct sedcmd));
@@ -792,7 +794,10 @@ static void parse_pattern(char **pline, long len)
if (*line == ',') line++;
else if (i) break;
- if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
+ if (i && *line == '+' && isdigit(line[1])) {
+ line++;
+ command->lmatch[i] = -2-strtol(line, &line, 0);
+ } else if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
else if (*line == '$') {
command->lmatch[i] = -1;
line++;
@@ -823,7 +828,7 @@ static void parse_pattern(char **pline, long len)
if (strchr("}:", c) && i) break;
if (strchr("aiqr=", c) && i>1) break;
- // Add step to pattern
+ // Allocate memory and copy out of toybuf now that we know how big it is
command = xmemdup(toybuf, reg-toybuf);
reg = (reg-toybuf) + (char *)command;