aboutsummaryrefslogtreecommitdiff
path: root/editors/sed.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-02 17:58:10 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-02 17:58:10 +0000
commit8b22b07bc599ca39d1b42cabef98189894b2162f (patch)
tree64ba681d4e88c20dcb36b2c0c2269e8d4aa5eba5 /editors/sed.c
parentbecd8c538cc689460dca83ecc92222969059c5f4 (diff)
downloadbusybox-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.c110
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 */
715static char *get_next_line(int *no_newline) 715static 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
739static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline) 756static 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
757static void process_files(void) 774static 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++;
780restart: 797restart:
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:
1075discard_commands: 1093discard_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. */
1081discard_line: 1099discard_line: