aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-28 23:26:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-28 23:26:15 +0000
commit826c85f3828c30b772d307c6b60ff3be744cecc2 (patch)
treeaf1d14dc4df46508bdccc3f99d3aac622933b0f1
parentdccb1a53432aad9ef304f891817f658e58c67651 (diff)
downloadbusybox-w32-826c85f3828c30b772d307c6b60ff3be744cecc2.tar.gz
busybox-w32-826c85f3828c30b772d307c6b60ff3be744cecc2.tar.bz2
busybox-w32-826c85f3828c30b772d307c6b60ff3be744cecc2.zip
fix all known regressions with sed and also make it simpler
-rw-r--r--editors/sed.c70
-rwxr-xr-xtestsuite/sed.tests5
2 files changed, 47 insertions, 28 deletions
diff --git a/editors/sed.c b/editors/sed.c
index 720d29aed..28ee698e4 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -82,7 +82,7 @@ typedef struct sed_cmd_s {
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
85 int last_char; /* Last line written by (sw) had no '\n' */ 85// int sw_last_char; /* Last line written by (sw) had no '\n' */
86 86
87 /* GENERAL FIELDS */ 87 /* GENERAL FIELDS */
88 char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */ 88 char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
@@ -717,6 +717,11 @@ static void add_input_file(FILE *file)
717 bbg.input_file_list[bbg.input_file_count++] = file; 717 bbg.input_file_list[bbg.input_file_count++] = file;
718} 718}
719 719
720enum {
721 MASK_NO_EOL_CHAR = 0x100,
722 //MASK_FIRST_LINE = 0x200,
723};
724
720/* Get next line of input from bbg.input_file_list, flushing append buffer and 725/* Get next line of input from bbg.input_file_list, flushing append buffer and
721 * noting if we ran out of files without a newline on the last line we read. 726 * noting if we ran out of files without a newline on the last line we read.
722 */ 727 */
@@ -743,13 +748,13 @@ static char *get_next_line(int *last_char)
743 } 748 }
744 /* will be returned if last line in the file 749 /* will be returned if last line in the file
745 * doesn't end with either '\n' or '\0' */ 750 * doesn't end with either '\n' or '\0' */
746 lc |= 0x100; 751 lc |= MASK_NO_EOL_CHAR;
747 break; 752 break;
748 } 753 }
749 /* Close this file and advance to next one */ 754 /* Close this file and advance to next one */
750 fclose(bbg.input_file_list[bbg.current_input_file++]); 755 fclose(bbg.input_file_list[bbg.current_input_file++]);
751 /* "this is the first line from new input file" */ 756 /* "this is the first line from new input file" */
752 lc |= 0x200; 757 //lc |= MASK_FIRST_LINE;
753 } 758 }
754 *last_char = lc; 759 *last_char = lc;
755 return temp; 760 return temp;
@@ -757,7 +762,7 @@ static char *get_next_line(int *last_char)
757 762
758/* Output line of text. */ 763/* Output line of text. */
759/* Note: 764/* Note:
760 * The tricks with 0x200 and last_puts_char are there to emulate gnu sed. 765 * The tricks with MASK_FIRST_LINE and last_puts_char are there to emulate gnu sed.
761 * Without them, we had this: 766 * Without them, we had this:
762 * echo -n thingy >z1 767 * echo -n thingy >z1
763 * echo -n again >z2 768 * echo -n again >z2
@@ -769,14 +774,14 @@ static char *get_next_line(int *last_char)
769 * bbox: 774 * bbox:
770 * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| 775 * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
771 */ 776 */
772 777static void puts_maybe_newline(char *s, FILE *file, int last_char)
773static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char)
774{ 778{
775 static char last_puts_char; 779 static char last_puts_char = '\n';
776 780
777 /* Is this a first line from new file 781 /* Is this a first line from new file
778 * and old file didn't end with '\n'? */ 782 * and old file didn't end with '\n' or '\0'? */
779 if ((last_char & 0x200) && last_puts_char != '\n') { 783// if ((last_char & MASK_FIRST_LINE) && last_puts_char != '\n') {
784 if (last_puts_char != '\n' && last_puts_char != '\0') {
780 fputc('\n', file); 785 fputc('\n', file);
781 last_puts_char = '\n'; 786 last_puts_char = '\n';
782 } 787 }
@@ -784,7 +789,7 @@ static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_
784 /* why 'x'? - just something which is not '\n' */ 789 /* why 'x'? - just something which is not '\n' */
785 if (s[0]) 790 if (s[0])
786 last_puts_char = 'x'; 791 last_puts_char = 'x';
787 if (!(last_char & 0x100)) { /* had trailing '\n' or '\0'? */ 792 if (!(last_char & MASK_NO_EOL_CHAR)) { /* had trailing '\n' or '\0'? */
788 last_char &= 0xff; 793 last_char &= 0xff;
789 fputc(last_char, file); 794 fputc(last_char, file);
790 last_puts_char = last_char; 795 last_puts_char = last_char;
@@ -795,18 +800,18 @@ static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_
795 bb_error_msg_and_die(bb_msg_write_error); 800 bb_error_msg_and_die(bb_msg_write_error);
796 } 801 }
797 802
798 return last_char; 803 /* Seems to be unused */
804 /*return last_char;*/
799} 805}
800 806
801#define sed_puts(s, n) \ 807#define sed_puts(s, n) (puts_maybe_newline(s, bbg.nonstdout, n))
802 (prev_last_char = puts_maybe_newline(s, bbg.nonstdout, prev_last_char, n))
803 808
804/* Process all the lines in all the files */ 809/* Process all the lines in all the files */
805 810
806static void process_files(void) 811static void process_files(void)
807{ 812{
808 char *pattern_space, *next_line; 813 char *pattern_space, *next_line;
809 int linenum = 0, prev_last_char = 0; 814 int linenum = 0;
810 int last_char, next_last_char = 0; 815 int last_char, next_last_char = 0;
811 sed_cmd_t *sed_cmd; 816 sed_cmd_t *sed_cmd;
812 int substituted; 817 int substituted;
@@ -873,10 +878,13 @@ restart:
873 878
874 /* Skip blocks of commands we didn't match. */ 879 /* Skip blocks of commands we didn't match. */
875 if (sed_cmd->cmd == '{') { 880 if (sed_cmd->cmd == '{') {
876 if (sed_cmd->invert ? matched : !matched) 881 if (sed_cmd->invert ? matched : !matched) {
877 while (sed_cmd && sed_cmd->cmd != '}') 882 while (sed_cmd->cmd != '}') {
878 sed_cmd = sed_cmd->next; 883 sed_cmd = sed_cmd->next;
879 if (!sed_cmd) bb_error_msg_and_die("unterminated {"); 884 if (!sed_cmd)
885 bb_error_msg_and_die("unterminated {");
886 }
887 }
880 continue; 888 continue;
881 } 889 }
882 890
@@ -902,7 +910,8 @@ restart:
902 910
903 if (tmp) { 911 if (tmp) {
904 *tmp = '\0'; 912 *tmp = '\0';
905 sed_puts(pattern_space, 1); 913 /* TODO: explain why '\n' below */
914 sed_puts(pattern_space, '\n');
906 *tmp = '\n'; 915 *tmp = '\n';
907 break; 916 break;
908 } 917 }
@@ -911,7 +920,11 @@ restart:
911 920
912 /* Write the current pattern space to output */ 921 /* Write the current pattern space to output */
913 case 'p': 922 case 'p':
914 sed_puts(pattern_space, last_char); 923 /* NB: we print this _before_ the last line
924 * (of current file) is printed. Even if
925 * that line is nonterminated, we print
926 * '\n' here (gnu sed does the same) */
927 sed_puts(pattern_space, (last_char & 0x200) | '\n');
915 break; 928 break;
916 /* Delete up through first newline */ 929 /* Delete up through first newline */
917 case 'D': 930 case 'D':
@@ -940,9 +953,9 @@ restart:
940 sed_puts(pattern_space, last_char); 953 sed_puts(pattern_space, last_char);
941 /* handle w option */ 954 /* handle w option */
942 if (sed_cmd->file) 955 if (sed_cmd->file)
943 sed_cmd->last_char = puts_maybe_newline( 956 /*sed_cmd->sw_last_char =*/ puts_maybe_newline(
944 pattern_space, sed_cmd->file, 957 pattern_space, sed_cmd->file,
945 sed_cmd->last_char, last_char); 958 last_char);
946 break; 959 break;
947 960
948 /* Append line to linked list to be printed later */ 961 /* Append line to linked list to be printed later */
@@ -952,14 +965,14 @@ restart:
952 965
953 /* Insert text before this line */ 966 /* Insert text before this line */
954 case 'i': 967 case 'i':
955 sed_puts(sed_cmd->string, 1); 968 sed_puts(sed_cmd->string, '\n');
956 break; 969 break;
957 970
958 /* Cut and paste text (replace) */ 971 /* Cut and paste text (replace) */
959 case 'c': 972 case 'c':
960 /* Only triggers on last line of a matching range. */ 973 /* Only triggers on last line of a matching range. */
961 if (!sed_cmd->in_match) 974 if (!sed_cmd->in_match)
962 sed_puts(sed_cmd->string, 0); 975 sed_puts(sed_cmd->string, MASK_NO_EOL_CHAR);
963 goto discard_line; 976 goto discard_line;
964 977
965 /* Read file, append contents to output */ 978 /* Read file, append contents to output */
@@ -982,9 +995,9 @@ restart:
982 995
983 /* Write pattern space to file. */ 996 /* Write pattern space to file. */
984 case 'w': 997 case 'w':
985 sed_cmd->last_char = puts_maybe_newline( 998 /*sed_cmd->sw_last_char =*/ puts_maybe_newline(
986 pattern_space, sed_cmd->file, 999 pattern_space, sed_cmd->file,
987 sed_cmd->last_char, last_char); 1000 last_char);
988 break; 1001 break;
989 1002
990 /* Read next line from input */ 1003 /* Read next line from input */
@@ -1123,13 +1136,14 @@ restart:
1123 /* 1136 /*
1124 * exit point from sedding... 1137 * exit point from sedding...
1125 */ 1138 */
1126discard_commands: 1139 discard_commands:
1127 /* we will print the line unless we were told to be quiet ('-n') 1140 /* we will print the line unless we were told to be quiet ('-n')
1128 or if the line was suppressed (ala 'd'elete) */ 1141 or if the line was suppressed (ala 'd'elete) */
1129 if (!bbg.be_quiet) sed_puts(pattern_space, last_char); 1142 if (!bbg.be_quiet)
1143 sed_puts(pattern_space, last_char);
1130 1144
1131 /* Delete and such jump here. */ 1145 /* Delete and such jump here. */
1132discard_line: 1146 discard_line:
1133 flush_append(); 1147 flush_append();
1134 free(pattern_space); 1148 free(pattern_space);
1135 1149
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 2a0d4eacf..a386f1723 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -146,6 +146,11 @@ testing "sed match EOF" "sed -e '"'$p'"'" "hello\nthere\nthere" "" \
146 "hello\nthere" 146 "hello\nthere"
147testing "sed match EOF two files" "sed -e '"'$p'"' input -" \ 147testing "sed match EOF two files" "sed -e '"'$p'"' input -" \
148 "one\ntwo\nthree\nfour\nfour" "one\ntwo" "three\nfour" 148 "one\ntwo\nthree\nfour\nfour" "one\ntwo" "three\nfour"
149# sed match EOF inline: gnu sed 4.1.5 outputs this:
150#00000000 6f 6e 65 0a 6f 6f 6b 0a 6f 6f 6b 0a 74 77 6f 0a |one.ook.ook.two.|
151#00000010 0a 74 68 72 65 65 0a 6f 6f 6b 0a 6f 6f 6b 0a 66 |.three.ook.ook.f|
152#00000020 6f 75 72 |our|
153# which looks buggy to me.
149echo -ne "three\nfour" > input2 154echo -ne "three\nfour" > input2
150testing "sed match EOF inline" \ 155testing "sed match EOF inline" \
151 "sed -e '"'$i ook'"' -i input input2 && cat input input2" \ 156 "sed -e '"'$i ook'"' -i input input2 && cat input input2" \