aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-06-04 01:29:52 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-06-04 01:29:52 +0200
commitbf5f99ffb245e9039df62e5d3f77674fd7b3b2a7 (patch)
tree4e10b657ca0be2ec90d06442c45872db55fca41d
parent79b3d42e13814f984ec35ec632d34db301871567 (diff)
downloadbusybox-bf5f99ffb245e9039df62e5d3f77674fd7b3b2a7.tar.gz
sed: fix a case when one-line range matches past lines. Closes bug 1867.
function old new delta process_files 2096 2107 +11 add_cmd 1142 1132 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 11/-10) Total: 1 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/sed.c43
-rwxr-xr-xtestsuite/sed.tests5
2 files changed, 33 insertions, 15 deletions
diff --git a/editors/sed.c b/editors/sed.c
index 4bd6e0168..7fe2809b3 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -119,10 +119,10 @@ struct globals {
} pipeline;
} FIX_ALIASING;
#define G (*(struct globals*)&bb_common_bufsiz1)
-void BUG_sed_globals_too_big(void);
+struct BUG_G_too_big {
+ char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+};
#define INIT_G() do { \
- if (sizeof(struct globals) > COMMON_BUFSIZE) \
- BUG_sed_globals_too_big(); \
G.sed_cmd_tail = &G.sed_cmd_head; \
} while (0)
@@ -385,7 +385,8 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
break;
/* Comment */
case '#':
- while (substr[++idx]) /*skip all*/;
+ // while (substr[++idx]) continue;
+ idx += strlen(substr + idx); // same
/* Fall through */
/* End of command */
case ';':
@@ -395,7 +396,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
bb_error_msg_and_die("bad option in substitution expression");
}
}
-out:
+ out:
/* compile the match string into a regex */
if (*match != '\0') {
/* If match is empty, we use last regex used at runtime */
@@ -896,13 +897,32 @@ static void process_files(void)
/* Determine if this command matches this line: */
+ //bb_error_msg("match1:%d", sed_cmd->in_match);
+ //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
+ // && !sed_cmd->beg_match && !sed_cmd->end_match));
+ //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0
+ // && (sed_cmd->end_line || sed_cmd->end_match
+ // ? (sed_cmd->beg_line <= linenum)
+ // : (sed_cmd->beg_line == linenum)
+ // )
+ // )
+ //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space)));
+ //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
+
/* Are we continuing a previous multi-line match? */
sed_cmd->in_match = sed_cmd->in_match
/* Or is no range necessary? */
|| (!sed_cmd->beg_line && !sed_cmd->end_line
&& !sed_cmd->beg_match && !sed_cmd->end_match)
/* Or did we match the start of a numerical range? */
- || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line <= linenum))
+ || (sed_cmd->beg_line > 0
+ && (sed_cmd->end_line || sed_cmd->end_match
+ /* note: even if end numeric and is < linenum too,
+ * GNU sed matches! We match too */
+ ? (sed_cmd->beg_line <= linenum) /* N,end */
+ : (sed_cmd->beg_line == linenum) /* N */
+ )
+ )
/* Or does this line match our begin address regex? */
|| (beg_match(sed_cmd, pattern_space))
/* Or did we match last line of input? */
@@ -976,7 +996,6 @@ static void process_files(void)
case 'P':
{
char *tmp = strchr(pattern_space, '\n');
-
if (tmp) {
*tmp = '\0';
/* TODO: explain why '\n' below */
@@ -999,11 +1018,8 @@ static void process_files(void)
case 'D':
{
char *tmp = strchr(pattern_space, '\n');
-
if (tmp) {
- tmp = xstrdup(tmp+1);
- free(pattern_space);
- pattern_space = tmp;
+ overlapping_strcpy(pattern_space, tmp + 1);
goto restart;
}
}
@@ -1048,7 +1064,6 @@ static void process_files(void)
case 'r':
{
FILE *rfile;
-
rfile = fopen_for_read(sed_cmd->string);
if (rfile) {
char *line;
@@ -1097,12 +1112,11 @@ static void process_files(void)
int len;
/* If no next line, jump to end of script and exit. */
if (next_line == NULL) {
- /* Jump to end of script and exit */
free(next_line);
next_line = NULL;
goto discard_line;
- /* append next_line, read new next_line. */
}
+ /* Append next_line, read new next_line. */
len = strlen(pattern_space);
pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2);
pattern_space[len] = '\n';
@@ -1131,7 +1145,6 @@ static void process_files(void)
case 'y':
{
int i, j;
-
for (i = 0; pattern_space[i]; i++) {
for (j = 0; sed_cmd->string[j]; j += 2) {
if (pattern_space[i] == sed_cmd->string[j]) {
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 88b9c4e4b..3301a25f8 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -270,6 +270,11 @@ testing "sed a cmd ended by double backslash" \
| two \\
'
+# fisrt three lines are deleted; 4th line is matched and printed by "2,3" and by "4" ranges
+testing "sed with N skipping lines past ranges on next cmds" \
+ "sed -n '1{N;N;d};1p;2,3p;3p;4p'" \
+ "4\n4\n" "" "1\n2\n3\n4\n"
+
# testing "description" "arguments" "result" "infile" "stdin"
exit $FAILCOUNT