aboutsummaryrefslogtreecommitdiff
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
parentbecd8c538cc689460dca83ecc92222969059c5f4 (diff)
downloadbusybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.tar.gz
busybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.tar.bz2
busybox-w32-8b22b07bc599ca39d1b42cabef98189894b2162f.zip
sed: improve handling of NULs
-rw-r--r--editors/sed.c110
-rw-r--r--libbb/get_line_from_file.c10
2 files changed, 69 insertions, 51 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:
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index b424d59e9..3f2c6096e 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -11,8 +11,8 @@
11 11
12#include "libbb.h" 12#include "libbb.h"
13 13
14/* This function reads an entire line from a text file, 14/* This function reads an entire line from a text file, up to a newline
15 * up to a newline or NUL byte. It returns a malloc'ed char * which must be 15 * or NUL byte, inclusive. It returns a malloc'ed char * which must be
16 * stored and free'ed by the caller. If end is null '\n' isn't considered 16 * stored and free'ed by the caller. If end is null '\n' isn't considered
17 * end of line. If end isn't null, length of the chunk read is stored in it. */ 17 * end of line. If end isn't null, length of the chunk read is stored in it. */
18 18
@@ -25,7 +25,7 @@ char *bb_get_chunk_from_file(FILE * file, int *end)
25 25
26 while ((ch = getc(file)) != EOF) { 26 while ((ch = getc(file)) != EOF) {
27 /* grow the line buffer as necessary */ 27 /* grow the line buffer as necessary */
28 if (idx > linebufsz - 2) { 28 if (idx >= linebufsz) {
29 linebuf = xrealloc(linebuf, linebufsz += 80); 29 linebuf = xrealloc(linebuf, linebufsz += 80);
30 } 30 }
31 linebuf[idx++] = (char) ch; 31 linebuf[idx++] = (char) ch;
@@ -35,14 +35,14 @@ char *bb_get_chunk_from_file(FILE * file, int *end)
35 if (end) 35 if (end)
36 *end = idx; 36 *end = idx;
37 if (linebuf) { 37 if (linebuf) {
38 // huh, is fgets discards prior data on error like this? 38 // huh, does fgets discard prior data on error like this?
39 // I don't think so.... 39 // I don't think so....
40 //if (ferror(file)) { 40 //if (ferror(file)) {
41 // free(linebuf); 41 // free(linebuf);
42 // return NULL; 42 // return NULL;
43 //} 43 //}
44 linebuf = xrealloc(linebuf, idx+1); 44 linebuf = xrealloc(linebuf, idx+1);
45 linebuf[idx] = 0; 45 linebuf[idx] = '\0';
46 } 46 }
47 return linebuf; 47 return linebuf;
48} 48}