diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-29 17:10:19 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-29 17:10:19 +0000 |
| commit | 86811803e304b63b71d3ddac91ad4e1cd741344f (patch) | |
| tree | 3ecbd8b554f6a4c82f9b03d29087914f3d8a9623 | |
| parent | c562bb74877f68edebfa31515c17d63fc4769a60 (diff) | |
| download | busybox-w32-86811803e304b63b71d3ddac91ad4e1cd741344f.tar.gz busybox-w32-86811803e304b63b71d3ddac91ad4e1cd741344f.tar.bz2 busybox-w32-86811803e304b63b71d3ddac91ad4e1cd741344f.zip | |
add to testsuite and fix yet another sed corner case
| -rw-r--r-- | editors/sed.c | 30 | ||||
| -rwxr-xr-x | 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) | |||
| 724 | */ | 724 | */ |
| 725 | enum { | 725 | enum { |
| 726 | NO_EOL_CHAR = 1, | 726 | NO_EOL_CHAR = 1, |
| 727 | LAST_IS_NUL = 2, | ||
| 727 | }; | 728 | }; |
| 728 | static char *get_next_line(char *gets_char) | 729 | static char *get_next_line(char *gets_char) |
| 729 | { | 730 | { |
| @@ -737,17 +738,24 @@ static char *get_next_line(char *gets_char) | |||
| 737 | * doesn't end with either '\n' or '\0' */ | 738 | * doesn't end with either '\n' or '\0' */ |
| 738 | gc = NO_EOL_CHAR; | 739 | gc = NO_EOL_CHAR; |
| 739 | while (bbg.current_input_file < bbg.input_file_count) { | 740 | while (bbg.current_input_file < bbg.input_file_count) { |
| 741 | FILE *fp = bbg.input_file_list[bbg.current_input_file]; | ||
| 740 | /* Read line up to a newline or NUL byte, inclusive, | 742 | /* Read line up to a newline or NUL byte, inclusive, |
| 741 | * return malloc'ed char[]. length of the chunk read | 743 | * return malloc'ed char[]. length of the chunk read |
| 742 | * is stored in len. NULL if EOF/error */ | 744 | * is stored in len. NULL if EOF/error */ |
| 743 | temp = bb_get_chunk_from_file( | 745 | temp = bb_get_chunk_from_file(fp, &len); |
| 744 | bbg.input_file_list[bbg.current_input_file], &len); | ||
| 745 | if (temp) { | 746 | if (temp) { |
| 746 | /* len > 0 here, it's ok to do temp[len-1] */ | 747 | /* len > 0 here, it's ok to do temp[len-1] */ |
| 747 | char c = temp[len-1]; | 748 | char c = temp[len-1]; |
| 748 | if (c == '\n' || c == '\0') { | 749 | if (c == '\n' || c == '\0') { |
| 749 | temp[len-1] = '\0'; | 750 | temp[len-1] = '\0'; |
| 750 | gc = c; | 751 | gc = c; |
| 752 | if (c == '\0') { | ||
| 753 | int ch = fgetc(fp); | ||
| 754 | if (ch != EOF) | ||
| 755 | ungetc(ch, fp); | ||
| 756 | else | ||
| 757 | gc = LAST_IS_NUL; | ||
| 758 | } | ||
| 751 | } | 759 | } |
| 752 | /* else we put NO_EOL_CHAR into *gets_char */ | 760 | /* else we put NO_EOL_CHAR into *gets_char */ |
| 753 | break; | 761 | break; |
| @@ -761,7 +769,8 @@ static char *get_next_line(char *gets_char) | |||
| 761 | * (note: *no* newline after "b bang"!) */ | 769 | * (note: *no* newline after "b bang"!) */ |
| 762 | } | 770 | } |
| 763 | /* Close this file and advance to next one */ | 771 | /* Close this file and advance to next one */ |
| 764 | fclose(bbg.input_file_list[bbg.current_input_file++]); | 772 | fclose(fp); |
| 773 | bbg.current_input_file++; | ||
| 765 | } | 774 | } |
| 766 | *gets_char = gc; | 775 | *gets_char = gc; |
| 767 | return temp; | 776 | return temp; |
| @@ -785,20 +794,29 @@ static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char l | |||
| 785 | { | 794 | { |
| 786 | char lpc = *last_puts_char; | 795 | char lpc = *last_puts_char; |
| 787 | 796 | ||
| 788 | /* Is this a first line from new file | 797 | /* Need to insert a '\n' between two files because first file's |
| 789 | * and old file didn't end with '\n' or '\0'? */ | 798 | * last line wasn't terminated? */ |
| 790 | if (lpc != '\n' && lpc != '\0') { | 799 | if (lpc != '\n' && lpc != '\0') { |
| 791 | fputc('\n', file); | 800 | fputc('\n', file); |
| 792 | lpc = '\n'; | 801 | lpc = '\n'; |
| 793 | } | 802 | } |
| 794 | fputs(s, file); | 803 | fputs(s, file); |
| 804 | |||
| 795 | /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */ | 805 | /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */ |
| 796 | if (s[0]) | 806 | if (s[0]) |
| 797 | lpc = 'x'; | 807 | lpc = 'x'; |
| 798 | if (last_gets_char != NO_EOL_CHAR) { /* had trailing '\n' or '\0'? */ | 808 | |
| 809 | /* had trailing '\0' and it was last char of file? */ | ||
| 810 | if (last_gets_char == LAST_IS_NUL) { | ||
| 811 | fputc('\0', file); | ||
| 812 | lpc = 'x'; /* */ | ||
| 813 | } else | ||
| 814 | /* had trailing '\n' or '\0'? */ | ||
| 815 | if (last_gets_char != NO_EOL_CHAR) { | ||
| 799 | fputc(last_gets_char, file); | 816 | fputc(last_gets_char, file); |
| 800 | lpc = last_gets_char; | 817 | lpc = last_gets_char; |
| 801 | } | 818 | } |
| 819 | |||
| 802 | if (ferror(file)) { | 820 | if (ferror(file)) { |
| 803 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ | 821 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ |
| 804 | bb_error_msg_and_die(bb_msg_write_error); | 822 | 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" \ | |||
| 143 | "sed -e 's/i/z/' -e 'woutputw' input -; echo -n X; cat outputw" \ | 143 | "sed -e 's/i/z/' -e 'woutputw' input -; echo -n X; cat outputw" \ |
| 144 | "thzngy\nagaznXthzngy\nagazn" "thingy" "again" | 144 | "thzngy\nagaznXthzngy\nagazn" "thingy" "again" |
| 145 | rm outputw | 145 | rm outputw |
| 146 | testing "sed trailing NUL" \ | ||
| 147 | "sed 's/i/z/' input -" \ | ||
| 148 | "a\0b\0\nc" "a\0b\0" "c" | ||
| 146 | 149 | ||
| 147 | # Test end-of-file matching behavior | 150 | # Test end-of-file matching behavior |
| 148 | 151 | ||
