diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-04 01:29:52 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-04 01:29:52 +0200 |
commit | bf5f99ffb245e9039df62e5d3f77674fd7b3b2a7 (patch) | |
tree | 4e10b657ca0be2ec90d06442c45872db55fca41d | |
parent | 79b3d42e13814f984ec35ec632d34db301871567 (diff) | |
download | busybox-w32-bf5f99ffb245e9039df62e5d3f77674fd7b3b2a7.tar.gz busybox-w32-bf5f99ffb245e9039df62e5d3f77674fd7b3b2a7.tar.bz2 busybox-w32-bf5f99ffb245e9039df62e5d3f77674fd7b3b2a7.zip |
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.c | 43 | ||||
-rwxr-xr-x | testsuite/sed.tests | 5 |
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 { | |||
119 | } pipeline; | 119 | } pipeline; |
120 | } FIX_ALIASING; | 120 | } FIX_ALIASING; |
121 | #define G (*(struct globals*)&bb_common_bufsiz1) | 121 | #define G (*(struct globals*)&bb_common_bufsiz1) |
122 | void BUG_sed_globals_too_big(void); | 122 | struct BUG_G_too_big { |
123 | char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; | ||
124 | }; | ||
123 | #define INIT_G() do { \ | 125 | #define INIT_G() do { \ |
124 | if (sizeof(struct globals) > COMMON_BUFSIZE) \ | ||
125 | BUG_sed_globals_too_big(); \ | ||
126 | G.sed_cmd_tail = &G.sed_cmd_head; \ | 126 | G.sed_cmd_tail = &G.sed_cmd_head; \ |
127 | } while (0) | 127 | } while (0) |
128 | 128 | ||
@@ -385,7 +385,8 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) | |||
385 | break; | 385 | break; |
386 | /* Comment */ | 386 | /* Comment */ |
387 | case '#': | 387 | case '#': |
388 | while (substr[++idx]) /*skip all*/; | 388 | // while (substr[++idx]) continue; |
389 | idx += strlen(substr + idx); // same | ||
389 | /* Fall through */ | 390 | /* Fall through */ |
390 | /* End of command */ | 391 | /* End of command */ |
391 | case ';': | 392 | case ';': |
@@ -395,7 +396,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) | |||
395 | bb_error_msg_and_die("bad option in substitution expression"); | 396 | bb_error_msg_and_die("bad option in substitution expression"); |
396 | } | 397 | } |
397 | } | 398 | } |
398 | out: | 399 | out: |
399 | /* compile the match string into a regex */ | 400 | /* compile the match string into a regex */ |
400 | if (*match != '\0') { | 401 | if (*match != '\0') { |
401 | /* If match is empty, we use last regex used at runtime */ | 402 | /* If match is empty, we use last regex used at runtime */ |
@@ -896,13 +897,32 @@ static void process_files(void) | |||
896 | 897 | ||
897 | /* Determine if this command matches this line: */ | 898 | /* Determine if this command matches this line: */ |
898 | 899 | ||
900 | //bb_error_msg("match1:%d", sed_cmd->in_match); | ||
901 | //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line | ||
902 | // && !sed_cmd->beg_match && !sed_cmd->end_match)); | ||
903 | //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 | ||
904 | // && (sed_cmd->end_line || sed_cmd->end_match | ||
905 | // ? (sed_cmd->beg_line <= linenum) | ||
906 | // : (sed_cmd->beg_line == linenum) | ||
907 | // ) | ||
908 | // ) | ||
909 | //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); | ||
910 | //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); | ||
911 | |||
899 | /* Are we continuing a previous multi-line match? */ | 912 | /* Are we continuing a previous multi-line match? */ |
900 | sed_cmd->in_match = sed_cmd->in_match | 913 | sed_cmd->in_match = sed_cmd->in_match |
901 | /* Or is no range necessary? */ | 914 | /* Or is no range necessary? */ |
902 | || (!sed_cmd->beg_line && !sed_cmd->end_line | 915 | || (!sed_cmd->beg_line && !sed_cmd->end_line |
903 | && !sed_cmd->beg_match && !sed_cmd->end_match) | 916 | && !sed_cmd->beg_match && !sed_cmd->end_match) |
904 | /* Or did we match the start of a numerical range? */ | 917 | /* Or did we match the start of a numerical range? */ |
905 | || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line <= linenum)) | 918 | || (sed_cmd->beg_line > 0 |
919 | && (sed_cmd->end_line || sed_cmd->end_match | ||
920 | /* note: even if end numeric and is < linenum too, | ||
921 | * GNU sed matches! We match too */ | ||
922 | ? (sed_cmd->beg_line <= linenum) /* N,end */ | ||
923 | : (sed_cmd->beg_line == linenum) /* N */ | ||
924 | ) | ||
925 | ) | ||
906 | /* Or does this line match our begin address regex? */ | 926 | /* Or does this line match our begin address regex? */ |
907 | || (beg_match(sed_cmd, pattern_space)) | 927 | || (beg_match(sed_cmd, pattern_space)) |
908 | /* Or did we match last line of input? */ | 928 | /* Or did we match last line of input? */ |
@@ -976,7 +996,6 @@ static void process_files(void) | |||
976 | case 'P': | 996 | case 'P': |
977 | { | 997 | { |
978 | char *tmp = strchr(pattern_space, '\n'); | 998 | char *tmp = strchr(pattern_space, '\n'); |
979 | |||
980 | if (tmp) { | 999 | if (tmp) { |
981 | *tmp = '\0'; | 1000 | *tmp = '\0'; |
982 | /* TODO: explain why '\n' below */ | 1001 | /* TODO: explain why '\n' below */ |
@@ -999,11 +1018,8 @@ static void process_files(void) | |||
999 | case 'D': | 1018 | case 'D': |
1000 | { | 1019 | { |
1001 | char *tmp = strchr(pattern_space, '\n'); | 1020 | char *tmp = strchr(pattern_space, '\n'); |
1002 | |||
1003 | if (tmp) { | 1021 | if (tmp) { |
1004 | tmp = xstrdup(tmp+1); | 1022 | overlapping_strcpy(pattern_space, tmp + 1); |
1005 | free(pattern_space); | ||
1006 | pattern_space = tmp; | ||
1007 | goto restart; | 1023 | goto restart; |
1008 | } | 1024 | } |
1009 | } | 1025 | } |
@@ -1048,7 +1064,6 @@ static void process_files(void) | |||
1048 | case 'r': | 1064 | case 'r': |
1049 | { | 1065 | { |
1050 | FILE *rfile; | 1066 | FILE *rfile; |
1051 | |||
1052 | rfile = fopen_for_read(sed_cmd->string); | 1067 | rfile = fopen_for_read(sed_cmd->string); |
1053 | if (rfile) { | 1068 | if (rfile) { |
1054 | char *line; | 1069 | char *line; |
@@ -1097,12 +1112,11 @@ static void process_files(void) | |||
1097 | int len; | 1112 | int len; |
1098 | /* If no next line, jump to end of script and exit. */ | 1113 | /* If no next line, jump to end of script and exit. */ |
1099 | if (next_line == NULL) { | 1114 | if (next_line == NULL) { |
1100 | /* Jump to end of script and exit */ | ||
1101 | free(next_line); | 1115 | free(next_line); |
1102 | next_line = NULL; | 1116 | next_line = NULL; |
1103 | goto discard_line; | 1117 | goto discard_line; |
1104 | /* append next_line, read new next_line. */ | ||
1105 | } | 1118 | } |
1119 | /* Append next_line, read new next_line. */ | ||
1106 | len = strlen(pattern_space); | 1120 | len = strlen(pattern_space); |
1107 | pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); | 1121 | pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); |
1108 | pattern_space[len] = '\n'; | 1122 | pattern_space[len] = '\n'; |
@@ -1131,7 +1145,6 @@ static void process_files(void) | |||
1131 | case 'y': | 1145 | case 'y': |
1132 | { | 1146 | { |
1133 | int i, j; | 1147 | int i, j; |
1134 | |||
1135 | for (i = 0; pattern_space[i]; i++) { | 1148 | for (i = 0; pattern_space[i]; i++) { |
1136 | for (j = 0; sed_cmd->string[j]; j += 2) { | 1149 | for (j = 0; sed_cmd->string[j]; j += 2) { |
1137 | if (pattern_space[i] == sed_cmd->string[j]) { | 1150 | 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" \ | |||
270 | | two \\ | 270 | | two \\ |
271 | ' | 271 | ' |
272 | 272 | ||
273 | # fisrt three lines are deleted; 4th line is matched and printed by "2,3" and by "4" ranges | ||
274 | testing "sed with N skipping lines past ranges on next cmds" \ | ||
275 | "sed -n '1{N;N;d};1p;2,3p;3p;4p'" \ | ||
276 | "4\n4\n" "" "1\n2\n3\n4\n" | ||
277 | |||
273 | # testing "description" "arguments" "result" "infile" "stdin" | 278 | # testing "description" "arguments" "result" "infile" "stdin" |
274 | 279 | ||
275 | exit $FAILCOUNT | 280 | exit $FAILCOUNT |