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 |
