diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 20:12:12 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 20:12:12 +0000 |
commit | 1375bc7b678d143798823c719ebba55dce596585 (patch) | |
tree | 35ff0fbbe02e87bd8a638148172d972cb072555a /editors/sed.c | |
parent | 8b22b07bc599ca39d1b42cabef98189894b2162f (diff) | |
download | busybox-w32-1375bc7b678d143798823c719ebba55dce596585.tar.gz busybox-w32-1375bc7b678d143798823c719ebba55dce596585.tar.bz2 busybox-w32-1375bc7b678d143798823c719ebba55dce596585.zip |
sed: fix handling of files not ending in '\n'
Diffstat (limited to 'editors/sed.c')
-rw-r--r-- | editors/sed.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/editors/sed.c b/editors/sed.c index 630d6d792..94368aa68 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -81,6 +81,7 @@ typedef struct sed_cmd_s { | |||
81 | unsigned int invert:1; /* the '!' after the address */ | 81 | unsigned int invert:1; /* the '!' after the address */ |
82 | unsigned int in_match:1; /* Next line also included in match? */ | 82 | unsigned int in_match:1; /* Next line also included in match? */ |
83 | unsigned int sub_p:1; /* (s) print option */ | 83 | unsigned int sub_p:1; /* (s) print option */ |
84 | |||
84 | int last_char; /* Last line written by (sw) had no '\n' */ | 85 | int last_char; /* Last line written by (sw) had no '\n' */ |
85 | 86 | ||
86 | /* GENERAL FIELDS */ | 87 | /* GENERAL FIELDS */ |
@@ -715,12 +716,9 @@ static void add_input_file(FILE *file) | |||
715 | static char *get_next_line(int *last_char) | 716 | static char *get_next_line(int *last_char) |
716 | { | 717 | { |
717 | char *temp = NULL; | 718 | char *temp = NULL; |
718 | int len; | 719 | int len, lc; |
719 | |||
720 | /* will be returned if last line in the file | ||
721 | * doesn't end with either '\n' or '\0' */ | ||
722 | *last_char = 0x100; | ||
723 | 720 | ||
721 | lc = 0; | ||
724 | flush_append(); | 722 | flush_append(); |
725 | while (bbg.current_input_file < bbg.input_file_count) { | 723 | while (bbg.current_input_file < bbg.input_file_count) { |
726 | temp = bb_get_chunk_from_file( | 724 | temp = bb_get_chunk_from_file( |
@@ -730,18 +728,27 @@ static char *get_next_line(int *last_char) | |||
730 | char c = temp[len-1]; | 728 | char c = temp[len-1]; |
731 | if (c == '\n' || c == '\0') { | 729 | if (c == '\n' || c == '\0') { |
732 | temp[len-1] = '\0'; | 730 | temp[len-1] = '\0'; |
733 | *last_char = (unsigned char)c; | 731 | lc |= (unsigned char)c; |
732 | break; | ||
734 | } | 733 | } |
734 | /* will be returned if last line in the file | ||
735 | * doesn't end with either '\n' or '\0' */ | ||
736 | lc |= 0x100; | ||
735 | break; | 737 | break; |
736 | } | 738 | } |
737 | /* Close this file and advance to next one */ | 739 | /* Close this file and advance to next one */ |
738 | fclose(bbg.input_file_list[bbg.current_input_file++]); | 740 | fclose(bbg.input_file_list[bbg.current_input_file++]); |
741 | /* "this is the first line from new input file" */ | ||
742 | lc |= 0x200; | ||
739 | } | 743 | } |
744 | *last_char = lc; | ||
740 | return temp; | 745 | return temp; |
741 | } | 746 | } |
742 | 747 | ||
743 | /* Output line of text. */ | 748 | /* Output line of text. */ |
744 | /* Note: | 749 | /* Note: |
750 | * The tricks with 0x200 and last_puts_char are there to emulate gnu sed. | ||
751 | * Without them, we had this: | ||
745 | * echo -n thingy >z1 | 752 | * echo -n thingy >z1 |
746 | * echo -n again >z2 | 753 | * echo -n again >z2 |
747 | * >znull | 754 | * >znull |
@@ -750,13 +757,26 @@ static char *get_next_line(int *last_char) | |||
750 | * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| | 757 | * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| |
751 | * bbox: | 758 | * bbox: |
752 | * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| | 759 | * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| |
753 | * I am not sure that bbox is wrong here... | ||
754 | */ | 760 | */ |
755 | 761 | ||
756 | static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char) | 762 | static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char) |
757 | { | 763 | { |
764 | static char last_puts_char; | ||
765 | |||
766 | /* Is this a first line from new file | ||
767 | * and old file didn't end with '\n'? */ | ||
768 | if ((last_char & 0x200) && last_puts_char != '\n') { | ||
769 | fputc('\n', file); | ||
770 | last_puts_char = '\n'; | ||
771 | } | ||
758 | fputs(s, file); | 772 | fputs(s, file); |
759 | if (last_char < 0x100) fputc(last_char, file); | 773 | /* 'x': we don't care what is it, but we know it isn't '\n' */ |
774 | if (s[0]) last_puts_char = 'x'; | ||
775 | if (!(last_char & 0x100)) { /* had trailing '\n' or '\0'? */ | ||
776 | last_char &= 0xff; | ||
777 | fputc(last_char, file); | ||
778 | last_puts_char = last_char; | ||
779 | } | ||
760 | 780 | ||
761 | if (ferror(file)) { | 781 | if (ferror(file)) { |
762 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ | 782 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ |
@@ -1047,7 +1067,7 @@ restart: | |||
1047 | strcat(pattern_space, "\n"); | 1067 | strcat(pattern_space, "\n"); |
1048 | if (bbg.hold_space) | 1068 | if (bbg.hold_space) |
1049 | strcat(pattern_space, bbg.hold_space); | 1069 | strcat(pattern_space, bbg.hold_space); |
1050 | last_char = 0x100; | 1070 | last_char = '\n'; |
1051 | 1071 | ||
1052 | break; | 1072 | break; |
1053 | } | 1073 | } |
@@ -1079,7 +1099,7 @@ restart: | |||
1079 | { | 1099 | { |
1080 | char *tmp = pattern_space; | 1100 | char *tmp = pattern_space; |
1081 | pattern_space = bbg.hold_space ? : xzalloc(1); | 1101 | pattern_space = bbg.hold_space ? : xzalloc(1); |
1082 | last_char = 0x100; | 1102 | last_char = '\n'; |
1083 | bbg.hold_space = tmp; | 1103 | bbg.hold_space = tmp; |
1084 | break; | 1104 | break; |
1085 | } | 1105 | } |