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-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.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 {
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)
122void BUG_sed_globals_too_big(void); 122struct 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 }
398out: 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
274testing "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
275exit $FAILCOUNT 280exit $FAILCOUNT