aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-29 17:10:19 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-29 17:10:19 +0000
commit86811803e304b63b71d3ddac91ad4e1cd741344f (patch)
tree3ecbd8b554f6a4c82f9b03d29087914f3d8a9623
parentc562bb74877f68edebfa31515c17d63fc4769a60 (diff)
downloadbusybox-86811803e304b63b71d3ddac91ad4e1cd741344f.tar.gz
add to testsuite and fix yet another sed corner case
-rw-r--r--editors/sed.c30
-rwxr-xr-xtestsuite/sed.tests3
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