diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 17:58:10 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 17:58:10 +0000 |
commit | 8b22b07bc599ca39d1b42cabef98189894b2162f (patch) | |
tree | 64ba681d4e88c20dcb36b2c0c2269e8d4aa5eba5 /editors/sed.c | |
parent | becd8c538cc689460dca83ecc92222969059c5f4 (diff) | |
download | busybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.tar.gz busybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.tar.bz2 busybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.zip |
sed: improve handling of NULs
Diffstat (limited to 'editors/sed.c')
-rw-r--r-- | editors/sed.c | 110 |
1 files changed, 64 insertions, 46 deletions
diff --git a/editors/sed.c b/editors/sed.c index a16023945..630d6d792 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -80,8 +80,8 @@ typedef struct sed_cmd_s { | |||
80 | /* Bitfields (gcc won't group them if we don't) */ | 80 | /* Bitfields (gcc won't group them if we don't) */ |
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 no_newline:1; /* Last line written by (sw) had no '\n' */ | ||
84 | unsigned int sub_p:1; /* (s) print option */ | 83 | unsigned int sub_p:1; /* (s) print option */ |
84 | int last_char; /* Last line written by (sw) had no '\n' */ | ||
85 | 85 | ||
86 | /* GENERAL FIELDS */ | 86 | /* GENERAL FIELDS */ |
87 | char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */ | 87 | char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */ |
@@ -712,56 +712,73 @@ static void add_input_file(FILE *file) | |||
712 | /* Get next line of input from bbg.input_file_list, flushing append buffer and | 712 | /* Get next line of input from bbg.input_file_list, flushing append buffer and |
713 | * noting if we ran out of files without a newline on the last line we read. | 713 | * noting if we ran out of files without a newline on the last line we read. |
714 | */ | 714 | */ |
715 | static char *get_next_line(int *no_newline) | 715 | static char *get_next_line(int *last_char) |
716 | { | 716 | { |
717 | char *temp = NULL; | 717 | char *temp = NULL; |
718 | int len; | 718 | int len; |
719 | 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 | flush_append(); | 724 | flush_append(); |
721 | while (bbg.current_input_file < bbg.input_file_count) { | 725 | while (bbg.current_input_file < bbg.input_file_count) { |
722 | temp = bb_get_chunk_from_file(bbg.input_file_list[bbg.current_input_file],&len); | 726 | temp = bb_get_chunk_from_file( |
727 | bbg.input_file_list[bbg.current_input_file], &len); | ||
723 | if (temp) { | 728 | if (temp) { |
724 | *no_newline = !(len && temp[len-1] == '\n'); | 729 | /* len > 0 here, it's ok to do temp[len-1] */ |
725 | if (!*no_newline) temp[len-1] = 0; | 730 | char c = temp[len-1]; |
731 | if (c == '\n' || c == '\0') { | ||
732 | temp[len-1] = '\0'; | ||
733 | *last_char = (unsigned char)c; | ||
734 | } | ||
726 | break; | 735 | break; |
727 | // Close this file and advance to next one | 736 | } |
728 | } else | 737 | /* Close this file and advance to next one */ |
729 | fclose(bbg.input_file_list[bbg.current_input_file++]); | 738 | fclose(bbg.input_file_list[bbg.current_input_file++]); |
730 | } | 739 | } |
731 | |||
732 | return temp; | 740 | return temp; |
733 | } | 741 | } |
734 | 742 | ||
735 | /* Output line of text. missing_newline means the last line output did not | 743 | /* Output line of text. */ |
736 | end with a newline. no_newline means this line does not end with a | 744 | /* Note: |
737 | newline. */ | 745 | * echo -n thingy >z1 |
746 | * echo -n again >z2 | ||
747 | * >znull | ||
748 | * sed "s/i/z/" z1 z2 znull | hexdump -vC output: | ||
749 | * gnu sed 4.1.5: | ||
750 | * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| | ||
751 | * bbox: | ||
752 | * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| | ||
753 | * I am not sure that bbox is wrong here... | ||
754 | */ | ||
738 | 755 | ||
739 | static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline) | 756 | static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char) |
740 | { | 757 | { |
741 | if (missing_newline) fputc('\n',file); | 758 | fputs(s, file); |
742 | fputs(s,file); | 759 | if (last_char < 0x100) fputc(last_char, file); |
743 | if (!no_newline) fputc('\n',file); | ||
744 | 760 | ||
745 | if (ferror(file)) { | 761 | if (ferror(file)) { |
746 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ | 762 | xfunc_error_retval = 4; /* It's what gnu sed exits with... */ |
747 | bb_error_msg_and_die(bb_msg_write_error); | 763 | bb_error_msg_and_die(bb_msg_write_error); |
748 | } | 764 | } |
749 | 765 | ||
750 | return no_newline; | 766 | return last_char; |
751 | } | 767 | } |
752 | 768 | ||
753 | #define sed_puts(s,n) missing_newline=puts_maybe_newline(s,bbg.nonstdout,missing_newline,n) | 769 | #define sed_puts(s, n) \ |
770 | (prev_last_char = puts_maybe_newline(s, bbg.nonstdout, prev_last_char, n)) | ||
754 | 771 | ||
755 | /* Process all the lines in all the files */ | 772 | /* Process all the lines in all the files */ |
756 | 773 | ||
757 | static void process_files(void) | 774 | static void process_files(void) |
758 | { | 775 | { |
759 | char *pattern_space, *next_line; | 776 | char *pattern_space, *next_line; |
760 | int linenum = 0, missing_newline = 0; | 777 | int linenum = 0, prev_last_char = 0; |
761 | int no_newline,next_no_newline = 0; | 778 | int last_char, next_last_char = 0; |
762 | 779 | ||
763 | /* Prime the pump */ | 780 | /* Prime the pump */ |
764 | next_line = get_next_line(&next_no_newline); | 781 | next_line = get_next_line(&next_last_char); |
765 | 782 | ||
766 | /* go through every line in each file */ | 783 | /* go through every line in each file */ |
767 | for (;;) { | 784 | for (;;) { |
@@ -771,11 +788,11 @@ static void process_files(void) | |||
771 | /* Advance to next line. Stop if out of lines. */ | 788 | /* Advance to next line. Stop if out of lines. */ |
772 | pattern_space = next_line; | 789 | pattern_space = next_line; |
773 | if (!pattern_space) break; | 790 | if (!pattern_space) break; |
774 | no_newline = next_no_newline; | 791 | last_char = next_last_char; |
775 | 792 | ||
776 | /* Read one line in advance so we can act on the last line, | 793 | /* Read one line in advance so we can act on the last line, |
777 | * the '$' address */ | 794 | * the '$' address */ |
778 | next_line = get_next_line(&next_no_newline); | 795 | next_line = get_next_line(&next_last_char); |
779 | linenum++; | 796 | linenum++; |
780 | restart: | 797 | restart: |
781 | /* for every line, go through all the commands */ | 798 | /* for every line, go through all the commands */ |
@@ -858,7 +875,7 @@ restart: | |||
858 | 875 | ||
859 | /* Write the current pattern space to output */ | 876 | /* Write the current pattern space to output */ |
860 | case 'p': | 877 | case 'p': |
861 | sed_puts(pattern_space,no_newline); | 878 | sed_puts(pattern_space, last_char); |
862 | break; | 879 | break; |
863 | /* Delete up through first newline */ | 880 | /* Delete up through first newline */ |
864 | case 'D': | 881 | case 'D': |
@@ -878,25 +895,24 @@ restart: | |||
878 | 895 | ||
879 | /* Substitute with regex */ | 896 | /* Substitute with regex */ |
880 | case 's': | 897 | case 's': |
881 | if (do_subst_command(sed_cmd, &pattern_space)) { | 898 | if (!do_subst_command(sed_cmd, &pattern_space)) |
882 | substituted |= 1; | 899 | break; |
883 | 900 | substituted |= 1; | |
884 | /* handle p option */ | 901 | |
885 | if (sed_cmd->sub_p) | 902 | /* handle p option */ |
886 | sed_puts(pattern_space,no_newline); | 903 | if (sed_cmd->sub_p) |
887 | /* handle w option */ | 904 | sed_puts(pattern_space, last_char); |
888 | if (sed_cmd->file) | 905 | /* handle w option */ |
889 | sed_cmd->no_newline = puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline); | 906 | if (sed_cmd->file) |
890 | 907 | sed_cmd->last_char = puts_maybe_newline( | |
891 | } | 908 | pattern_space, sed_cmd->file, |
909 | sed_cmd->last_char, last_char); | ||
892 | break; | 910 | break; |
893 | 911 | ||
894 | /* Append line to linked list to be printed later */ | 912 | /* Append line to linked list to be printed later */ |
895 | case 'a': | 913 | case 'a': |
896 | { | ||
897 | append(sed_cmd->string); | 914 | append(sed_cmd->string); |
898 | break; | 915 | break; |
899 | } | ||
900 | 916 | ||
901 | /* Insert text before this line */ | 917 | /* Insert text before this line */ |
902 | case 'i': | 918 | case 'i': |
@@ -930,18 +946,20 @@ restart: | |||
930 | 946 | ||
931 | /* Write pattern space to file. */ | 947 | /* Write pattern space to file. */ |
932 | case 'w': | 948 | case 'w': |
933 | sed_cmd->no_newline = puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline); | 949 | sed_cmd->last_char = puts_maybe_newline( |
950 | pattern_space,sed_cmd->file, | ||
951 | sed_cmd->last_char, last_char); | ||
934 | break; | 952 | break; |
935 | 953 | ||
936 | /* Read next line from input */ | 954 | /* Read next line from input */ |
937 | case 'n': | 955 | case 'n': |
938 | if (!bbg.be_quiet) | 956 | if (!bbg.be_quiet) |
939 | sed_puts(pattern_space,no_newline); | 957 | sed_puts(pattern_space, last_char); |
940 | if (next_line) { | 958 | if (next_line) { |
941 | free(pattern_space); | 959 | free(pattern_space); |
942 | pattern_space = next_line; | 960 | pattern_space = next_line; |
943 | no_newline = next_no_newline; | 961 | last_char = next_last_char; |
944 | next_line = get_next_line(&next_no_newline); | 962 | next_line = get_next_line(&next_last_char); |
945 | linenum++; | 963 | linenum++; |
946 | break; | 964 | break; |
947 | } | 965 | } |
@@ -970,8 +988,8 @@ restart: | |||
970 | pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); | 988 | pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); |
971 | pattern_space[len] = '\n'; | 989 | pattern_space[len] = '\n'; |
972 | strcpy(pattern_space + len+1, next_line); | 990 | strcpy(pattern_space + len+1, next_line); |
973 | no_newline = next_no_newline; | 991 | last_char = next_last_char; |
974 | next_line = get_next_line(&next_no_newline); | 992 | next_line = get_next_line(&next_last_char); |
975 | linenum++; | 993 | linenum++; |
976 | } | 994 | } |
977 | break; | 995 | break; |
@@ -1029,7 +1047,7 @@ restart: | |||
1029 | strcat(pattern_space, "\n"); | 1047 | strcat(pattern_space, "\n"); |
1030 | if (bbg.hold_space) | 1048 | if (bbg.hold_space) |
1031 | strcat(pattern_space, bbg.hold_space); | 1049 | strcat(pattern_space, bbg.hold_space); |
1032 | no_newline = 0; | 1050 | last_char = 0x100; |
1033 | 1051 | ||
1034 | break; | 1052 | break; |
1035 | } | 1053 | } |
@@ -1061,7 +1079,7 @@ restart: | |||
1061 | { | 1079 | { |
1062 | char *tmp = pattern_space; | 1080 | char *tmp = pattern_space; |
1063 | pattern_space = bbg.hold_space ? : xzalloc(1); | 1081 | pattern_space = bbg.hold_space ? : xzalloc(1); |
1064 | no_newline = 0; | 1082 | last_char = 0x100; |
1065 | bbg.hold_space = tmp; | 1083 | bbg.hold_space = tmp; |
1066 | break; | 1084 | break; |
1067 | } | 1085 | } |
@@ -1075,7 +1093,7 @@ restart: | |||
1075 | discard_commands: | 1093 | discard_commands: |
1076 | /* we will print the line unless we were told to be quiet ('-n') | 1094 | /* we will print the line unless we were told to be quiet ('-n') |
1077 | or if the line was suppressed (ala 'd'elete) */ | 1095 | or if the line was suppressed (ala 'd'elete) */ |
1078 | if (!bbg.be_quiet) sed_puts(pattern_space,no_newline); | 1096 | if (!bbg.be_quiet) sed_puts(pattern_space, last_char); |
1079 | 1097 | ||
1080 | /* Delete and such jump here. */ | 1098 | /* Delete and such jump here. */ |
1081 | discard_line: | 1099 | discard_line: |