aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2022-01-04 19:42:36 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2022-01-04 19:42:36 +0100
commit286b33721d5f6afd615f752ea83bbd72658c6bb9 (patch)
tree93c9efb8b08a9674eca57c5ce1f30bdc6f54f9b3
parented2af2e82dbcfccb7392e9fbc3f837de1594c103 (diff)
downloadbusybox-w32-286b33721d5f6afd615f752ea83bbd72658c6bb9.tar.gz
busybox-w32-286b33721d5f6afd615f752ea83bbd72658c6bb9.tar.bz2
busybox-w32-286b33721d5f6afd615f752ea83bbd72658c6bb9.zip
sed: correctly handle 'w FILE' commands writing to the same file
function old new delta sed_xfopen_w - 84 +84 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/sed.c31
-rwxr-xr-xtestsuite/sed.tests9
2 files changed, 38 insertions, 2 deletions
diff --git a/editors/sed.c b/editors/sed.c
index e8c82ac63..48b0dbf67 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -97,6 +97,12 @@ enum {
97 OPT_in_place = 1 << 0, 97 OPT_in_place = 1 << 0,
98}; 98};
99 99
100struct sed_FILE {
101 struct sed_FILE *next; /* Next (linked list, NULL terminated) */
102 const char *fname;
103 FILE *fp;
104};
105
100/* Each sed command turns into one of these structures. */ 106/* Each sed command turns into one of these structures. */
101typedef struct sed_cmd_s { 107typedef struct sed_cmd_s {
102 /* Ordered by alignment requirements: currently 36 bytes on x86 */ 108 /* Ordered by alignment requirements: currently 36 bytes on x86 */
@@ -151,6 +157,11 @@ struct globals {
151 /* linked list of append lines */ 157 /* linked list of append lines */
152 llist_t *append_head; 158 llist_t *append_head;
153 159
160 /* linked list of FILEs opened for 'w' and s///w'.
161 * Needed to handle duplicate fnames: sed '/a/w F;/b/w F'
162 */
163 struct sed_FILE *FILE_head;
164
154 char *add_cmd_line; 165 char *add_cmd_line;
155 166
156 struct pipeline { 167 struct pipeline {
@@ -211,6 +222,22 @@ static void sed_free_and_close_stuff(void)
211void sed_free_and_close_stuff(void); 222void sed_free_and_close_stuff(void);
212#endif 223#endif
213 224
225static FILE *sed_xfopen_w(const char *fname)
226{
227 struct sed_FILE **pp = &G.FILE_head;
228 struct sed_FILE *cur;
229 while ((cur = *pp) != NULL) {
230 if (strcmp(cur->fname, fname) == 0)
231 return cur->fp;
232 pp = &cur->next;
233 }
234 *pp = cur = xzalloc(sizeof(*cur));
235 /*cur->next = NULL; - already is */
236 cur->fname = xstrdup(fname);
237 cur->fp = xfopen_for_write(fname);
238 return cur->fp;
239}
240
214/* If something bad happens during -i operation, delete temp file */ 241/* If something bad happens during -i operation, delete temp file */
215 242
216static void cleanup_outname(void) 243static void cleanup_outname(void)
@@ -446,7 +473,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
446 { 473 {
447 char *fname; 474 char *fname;
448 idx += parse_file_cmd(/*sed_cmd,*/ substr+idx+1, &fname); 475 idx += parse_file_cmd(/*sed_cmd,*/ substr+idx+1, &fname);
449 sed_cmd->sw_file = xfopen_for_write(fname); 476 sed_cmd->sw_file = sed_xfopen_w(fname);
450 sed_cmd->sw_last_char = '\n'; 477 sed_cmd->sw_last_char = '\n';
451 free(fname); 478 free(fname);
452 break; 479 break;
@@ -561,7 +588,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
561 } 588 }
562 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); 589 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
563 if (sed_cmd->cmd == 'w') { 590 if (sed_cmd->cmd == 'w') {
564 sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); 591 sed_cmd->sw_file = sed_xfopen_w(sed_cmd->string);
565 sed_cmd->sw_last_char = '\n'; 592 sed_cmd->sw_last_char = '\n';
566 } 593 }
567 } 594 }
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 2b78c9b12..e62b839f7 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -405,6 +405,15 @@ testing "sed ^ OR not^" \
405 "" \ 405 "" \
406 "abca\n" 406 "abca\n"
407 407
408# This only works if file name is exactly the same.
409# For example, w FILE; w ./FILE won't work.
410testing "sed understands duplicate file name" \
411 "sed -n -e '/a/w sed.output' -e '/c/w sed.output' 2>&1 && cat sed.output && rm sed.output" \
412 "a\nc\n" \
413 "" \
414 "a\nb\nc\n"
415
416
408# testing "description" "commands" "result" "infile" "stdin" 417# testing "description" "commands" "result" "infile" "stdin"
409 418
410exit $FAILCOUNT 419exit $FAILCOUNT