Skip to content

Commit c44539f

Browse files
author
Denys Vlasenko
committed
sed: fix "sed clusternewline" testcase
function old new delta process_files 2197 2226 +29 flush_append 47 54 +7 get_next_line 184 189 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 41/0) Total: 41 bytes Signed-off-by: Denys Vlasenko <[email protected]>
1 parent a82e32d commit c44539f

File tree

2 files changed

+67
-69
lines changed

2 files changed

+67
-69
lines changed

editors/sed.c

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -851,37 +851,79 @@ static void append(char *s)
851851
llist_add_to_end(&G.append_head, s);
852852
}
853853

854-
static void flush_append(void)
854+
/* Output line of text. */
855+
/* Note:
856+
* The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
857+
* Without them, we had this:
858+
* echo -n thingy >z1
859+
* echo -n again >z2
860+
* >znull
861+
* sed "s/i/z/" z1 z2 znull | hexdump -vC
862+
* output:
863+
* gnu sed 4.1.5:
864+
* 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
865+
* bbox:
866+
* 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
867+
*/
868+
enum {
869+
NO_EOL_CHAR = 1,
870+
LAST_IS_NUL = 2,
871+
};
872+
static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
873+
{
874+
char lpc = *last_puts_char;
875+
876+
/* Need to insert a '\n' between two files because first file's
877+
* last line wasn't terminated? */
878+
if (lpc != '\n' && lpc != '\0') {
879+
fputc('\n', file);
880+
lpc = '\n';
881+
}
882+
fputs(s, file);
883+
884+
/* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
885+
if (s[0])
886+
lpc = 'x';
887+
888+
/* had trailing '\0' and it was last char of file? */
889+
if (last_gets_char == LAST_IS_NUL) {
890+
fputc('\0', file);
891+
lpc = 'x'; /* */
892+
} else
893+
/* had trailing '\n' or '\0'? */
894+
if (last_gets_char != NO_EOL_CHAR) {
895+
fputc(last_gets_char, file);
896+
lpc = last_gets_char;
897+
}
898+
899+
if (ferror(file)) {
900+
xfunc_error_retval = 4; /* It's what gnu sed exits with... */
901+
bb_error_msg_and_die(bb_msg_write_error);
902+
}
903+
*last_puts_char = lpc;
904+
}
905+
906+
static void flush_append(char *last_puts_char, char last_gets_char)
855907
{
856908
char *data;
857909

858910
/* Output appended lines. */
859911
while ((data = (char *)llist_pop(&G.append_head))) {
860-
fprintf(G.nonstdout, "%s\n", data);
912+
puts_maybe_newline(data, G.nonstdout, last_puts_char, last_gets_char);
861913
free(data);
862914
}
863915
}
864916

865-
static void add_input_file(FILE *file)
866-
{
867-
G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count);
868-
G.input_file_list[G.input_file_count++] = file;
869-
}
870-
871917
/* Get next line of input from G.input_file_list, flushing append buffer and
872918
* noting if we ran out of files without a newline on the last line we read.
873919
*/
874-
enum {
875-
NO_EOL_CHAR = 1,
876-
LAST_IS_NUL = 2,
877-
};
878-
static char *get_next_line(char *gets_char)
920+
static char *get_next_line(char *gets_char, char *last_puts_char, char last_gets_char)
879921
{
880922
char *temp = NULL;
881923
int len;
882924
char gc;
883925

884-
flush_append();
926+
flush_append(last_puts_char, last_gets_char);
885927

886928
/* will be returned if last line in the file
887929
* doesn't end with either '\n' or '\0' */
@@ -925,54 +967,6 @@ static char *get_next_line(char *gets_char)
925967
return temp;
926968
}
927969

928-
/* Output line of text. */
929-
/* Note:
930-
* The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
931-
* Without them, we had this:
932-
* echo -n thingy >z1
933-
* echo -n again >z2
934-
* >znull
935-
* sed "s/i/z/" z1 z2 znull | hexdump -vC
936-
* output:
937-
* gnu sed 4.1.5:
938-
* 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
939-
* bbox:
940-
* 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
941-
*/
942-
static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
943-
{
944-
char lpc = *last_puts_char;
945-
946-
/* Need to insert a '\n' between two files because first file's
947-
* last line wasn't terminated? */
948-
if (lpc != '\n' && lpc != '\0') {
949-
fputc('\n', file);
950-
lpc = '\n';
951-
}
952-
fputs(s, file);
953-
954-
/* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
955-
if (s[0])
956-
lpc = 'x';
957-
958-
/* had trailing '\0' and it was last char of file? */
959-
if (last_gets_char == LAST_IS_NUL) {
960-
fputc('\0', file);
961-
lpc = 'x'; /* */
962-
} else
963-
/* had trailing '\n' or '\0'? */
964-
if (last_gets_char != NO_EOL_CHAR) {
965-
fputc(last_gets_char, file);
966-
lpc = last_gets_char;
967-
}
968-
969-
if (ferror(file)) {
970-
xfunc_error_retval = 4; /* It's what gnu sed exits with... */
971-
bb_error_msg_and_die(bb_msg_write_error);
972-
}
973-
*last_puts_char = lpc;
974-
}
975-
976970
#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
977971

978972
static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
@@ -995,7 +989,7 @@ static void process_files(void)
995989
int substituted;
996990

997991
/* Prime the pump */
998-
next_line = get_next_line(&next_gets_char);
992+
next_line = get_next_line(&next_gets_char, &last_puts_char, '\n' /*last_gets_char*/);
999993

1000994
/* Go through every line in each file */
1001995
again:
@@ -1009,7 +1003,7 @@ static void process_files(void)
10091003

10101004
/* Read one line in advance so we can act on the last line,
10111005
* the '$' address */
1012-
next_line = get_next_line(&next_gets_char);
1006+
next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
10131007
linenum++;
10141008

10151009
/* For every line, go through all the commands */
@@ -1227,7 +1221,7 @@ static void process_files(void)
12271221
free(pattern_space);
12281222
pattern_space = next_line;
12291223
last_gets_char = next_gets_char;
1230-
next_line = get_next_line(&next_gets_char);
1224+
next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
12311225
substituted = 0;
12321226
linenum++;
12331227
break;
@@ -1263,7 +1257,7 @@ static void process_files(void)
12631257
pattern_space[len] = '\n';
12641258
strcpy(pattern_space + len+1, next_line);
12651259
last_gets_char = next_gets_char;
1266-
next_line = get_next_line(&next_gets_char);
1260+
next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
12671261
linenum++;
12681262
break;
12691263
}
@@ -1367,7 +1361,7 @@ static void process_files(void)
13671361

13681362
/* Delete and such jump here. */
13691363
discard_line:
1370-
flush_append();
1364+
flush_append(&last_puts_char, last_gets_char);
13711365
free(pattern_space);
13721366

13731367
goto again;
@@ -1394,6 +1388,12 @@ static void add_cmd_block(char *cmdstr)
13941388
free(sv);
13951389
}
13961390

1391+
static void add_input_file(FILE *file)
1392+
{
1393+
G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count);
1394+
G.input_file_list[G.input_file_count++] = file;
1395+
}
1396+
13971397
int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13981398
int sed_main(int argc UNUSED_PARAM, char **argv)
13991399
{

testsuite/sed.tests

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,9 @@ testing "sed selective matches insert newline" \
154154
testing "sed selective matches noinsert newline" \
155155
"sed -ne 's/woo/bang/p' input -" "a bang\nb bang" "a woo\nb woo" \
156156
"c no\nd no"
157-
test x"$SKIP_KNOWN_BUGS" = x"" && {
158157
testing "sed clusternewline" \
159158
"sed -e '/one/a 111' -e '/two/i 222' -e p input -" \
160159
"one\none\n111\n222\ntwo\ntwo" "one" "two"
161-
}
162160
testing "sed subst+write" \
163161
"sed -e 's/i/z/' -e 'woutputw' input -; $ECHO -n X; cat outputw" \
164162
"thzngy\nagaznXthzngy\nagazn" "thingy" "again"

0 commit comments

Comments
 (0)