From 86811803e304b63b71d3ddac91ad4e1cd741344f Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 29 Jan 2007 17:10:19 +0000 Subject: [PATCH] add to testsuite and fix yet another sed corner case --- editors/sed.c | 30 ++++++++++++++++++++++++------ testsuite/sed.tests | 3 +++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index bf40877e4..695e5e974 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -724,6 +724,7 @@ static void add_input_file(FILE *file) */ enum { NO_EOL_CHAR = 1, + LAST_IS_NUL = 2, }; static char *get_next_line(char *gets_char) { @@ -737,17 +738,24 @@ static char *get_next_line(char *gets_char) * doesn't end with either '\n' or '\0' */ gc = NO_EOL_CHAR; while (bbg.current_input_file < bbg.input_file_count) { + FILE *fp = bbg.input_file_list[bbg.current_input_file]; /* Read line up to a newline or NUL byte, inclusive, * return malloc'ed char[]. length of the chunk read * is stored in len. NULL if EOF/error */ - temp = bb_get_chunk_from_file( - bbg.input_file_list[bbg.current_input_file], &len); + temp = bb_get_chunk_from_file(fp, &len); if (temp) { /* len > 0 here, it's ok to do temp[len-1] */ char c = temp[len-1]; if (c == '\n' || c == '\0') { temp[len-1] = '\0'; gc = c; + if (c == '\0') { + int ch = fgetc(fp); + if (ch != EOF) + ungetc(ch, fp); + else + gc = LAST_IS_NUL; + } } /* else we put NO_EOL_CHAR into *gets_char */ break; @@ -761,7 +769,8 @@ static char *get_next_line(char *gets_char) * (note: *no* newline after "b bang"!) */ } /* Close this file and advance to next one */ - fclose(bbg.input_file_list[bbg.current_input_file++]); + fclose(fp); + bbg.current_input_file++; } *gets_char = gc; return temp; @@ -785,20 +794,29 @@ static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char l { char lpc = *last_puts_char; - /* Is this a first line from new file - * and old file didn't end with '\n' or '\0'? */ + /* Need to insert a '\n' between two files because first file's + * last line wasn't terminated? */ if (lpc != '\n' && lpc != '\0') { fputc('\n', file); lpc = '\n'; } fputs(s, file); + /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */ if (s[0]) lpc = 'x'; - if (last_gets_char != NO_EOL_CHAR) { /* had trailing '\n' or '\0'? */ + + /* had trailing '\0' and it was last char of file? */ + if (last_gets_char == LAST_IS_NUL) { + fputc('\0', file); + lpc = 'x'; /* */ + } else + /* had trailing '\n' or '\0'? */ + if (last_gets_char != NO_EOL_CHAR) { fputc(last_gets_char, file); lpc = last_gets_char; } + if (ferror(file)) { xfunc_error_retval = 4; /* It's what gnu sed exits with... */ bb_error_msg_and_die(bb_msg_write_error); diff --git a/testsuite/sed.tests b/testsuite/sed.tests index cc200703d..9576b6c4b 100755 --- a/testsuite/sed.tests +++ b/testsuite/sed.tests @@ -143,6 +143,9 @@ testing "sed subst+write" \ "sed -e 's/i/z/' -e 'woutputw' input -; echo -n X; cat outputw" \ "thzngy\nagaznXthzngy\nagazn" "thingy" "again" rm outputw +testing "sed trailing NUL" \ + "sed 's/i/z/' input -" \ + "a\0b\0\nc" "a\0b\0" "c" # Test end-of-file matching behavior -- 2.25.1