diff options
author | Denis Vlasenko | 2007-01-28 23:26:15 +0000 |
---|---|---|
committer | Denis Vlasenko | 2007-01-28 23:26:15 +0000 |
commit | 826c85f3828c30b772d307c6b60ff3be744cecc2 (patch) | |
tree | af1d14dc4df46508bdccc3f99d3aac622933b0f1 /editors | |
parent | dccb1a53432aad9ef304f891817f658e58c67651 (diff) | |
download | busybox-826c85f3828c30b772d307c6b60ff3be744cecc2.zip busybox-826c85f3828c30b772d307c6b60ff3be744cecc2.tar.gz |
fix all known regressions with sed and also make it simpler
Diffstat (limited to 'editors')
-rw-r--r-- | editors/sed.c | 70 |
1 files changed, 42 insertions, 28 deletions
diff --git a/editors/sed.c b/editors/sed.c index 720d29a..28ee698 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -82,7 +82,7 @@ typedef struct sed_cmd_s { unsigned int in_match:1; /* Next line also included in match? */ unsigned int sub_p:1; /* (s) print option */ - int last_char; /* Last line written by (sw) had no '\n' */ +// int sw_last_char; /* Last line written by (sw) had no '\n' */ /* GENERAL FIELDS */ char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */ @@ -717,6 +717,11 @@ static void add_input_file(FILE *file) bbg.input_file_list[bbg.input_file_count++] = file; } +enum { + MASK_NO_EOL_CHAR = 0x100, + //MASK_FIRST_LINE = 0x200, +}; + /* Get next line of input from bbg.input_file_list, flushing append buffer and * noting if we ran out of files without a newline on the last line we read. */ @@ -743,13 +748,13 @@ static char *get_next_line(int *last_char) } /* will be returned if last line in the file * doesn't end with either '\n' or '\0' */ - lc |= 0x100; + lc |= MASK_NO_EOL_CHAR; break; } /* Close this file and advance to next one */ fclose(bbg.input_file_list[bbg.current_input_file++]); /* "this is the first line from new input file" */ - lc |= 0x200; + //lc |= MASK_FIRST_LINE; } *last_char = lc; return temp; @@ -757,7 +762,7 @@ static char *get_next_line(int *last_char) /* Output line of text. */ /* Note: - * The tricks with 0x200 and last_puts_char are there to emulate gnu sed. + * The tricks with MASK_FIRST_LINE and last_puts_char are there to emulate gnu sed. * Without them, we had this: * echo -n thingy >z1 * echo -n again >z2 @@ -769,14 +774,14 @@ static char *get_next_line(int *last_char) * bbox: * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| */ - -static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char) +static void puts_maybe_newline(char *s, FILE *file, int last_char) { - static char last_puts_char; + static char last_puts_char = '\n'; /* Is this a first line from new file - * and old file didn't end with '\n'? */ - if ((last_char & 0x200) && last_puts_char != '\n') { + * and old file didn't end with '\n' or '\0'? */ +// if ((last_char & MASK_FIRST_LINE) && last_puts_char != '\n') { + if (last_puts_char != '\n' && last_puts_char != '\0') { fputc('\n', file); last_puts_char = '\n'; } @@ -784,7 +789,7 @@ static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_ /* why 'x'? - just something which is not '\n' */ if (s[0]) last_puts_char = 'x'; - if (!(last_char & 0x100)) { /* had trailing '\n' or '\0'? */ + if (!(last_char & MASK_NO_EOL_CHAR)) { /* had trailing '\n' or '\0'? */ last_char &= 0xff; fputc(last_char, file); last_puts_char = last_char; @@ -795,18 +800,18 @@ static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_ bb_error_msg_and_die(bb_msg_write_error); } - return last_char; + /* Seems to be unused */ + /*return last_char;*/ } -#define sed_puts(s, n) \ - (prev_last_char = puts_maybe_newline(s, bbg.nonstdout, prev_last_char, n)) +#define sed_puts(s, n) (puts_maybe_newline(s, bbg.nonstdout, n)) /* Process all the lines in all the files */ static void process_files(void) { char *pattern_space, *next_line; - int linenum = 0, prev_last_char = 0; + int linenum = 0; int last_char, next_last_char = 0; sed_cmd_t *sed_cmd; int substituted; @@ -873,10 +878,13 @@ restart: /* Skip blocks of commands we didn't match. */ if (sed_cmd->cmd == '{') { - if (sed_cmd->invert ? matched : !matched) - while (sed_cmd && sed_cmd->cmd != '}') + if (sed_cmd->invert ? matched : !matched) { + while (sed_cmd->cmd != '}') { sed_cmd = sed_cmd->next; - if (!sed_cmd) bb_error_msg_and_die("unterminated {"); + if (!sed_cmd) + bb_error_msg_and_die("unterminated {"); + } + } continue; } @@ -902,7 +910,8 @@ restart: if (tmp) { *tmp = '\0'; - sed_puts(pattern_space, 1); + /* TODO: explain why '\n' below */ + sed_puts(pattern_space, '\n'); *tmp = '\n'; break; } @@ -911,7 +920,11 @@ restart: /* Write the current pattern space to output */ case 'p': - sed_puts(pattern_space, last_char); + /* NB: we print this _before_ the last line + * (of current file) is printed. Even if + * that line is nonterminated, we print + * '\n' here (gnu sed does the same) */ + sed_puts(pattern_space, (last_char & 0x200) | '\n'); break; /* Delete up through first newline */ case 'D': @@ -940,9 +953,9 @@ restart: sed_puts(pattern_space, last_char); /* handle w option */ if (sed_cmd->file) - sed_cmd->last_char = puts_maybe_newline( + /*sed_cmd->sw_last_char =*/ puts_maybe_newline( pattern_space, sed_cmd->file, - sed_cmd->last_char, last_char); + last_char); break; /* Append line to linked list to be printed later */ @@ -952,14 +965,14 @@ restart: /* Insert text before this line */ case 'i': - sed_puts(sed_cmd->string, 1); + sed_puts(sed_cmd->string, '\n'); break; /* Cut and paste text (replace) */ case 'c': /* Only triggers on last line of a matching range. */ if (!sed_cmd->in_match) - sed_puts(sed_cmd->string, 0); + sed_puts(sed_cmd->string, MASK_NO_EOL_CHAR); goto discard_line; /* Read file, append contents to output */ @@ -982,9 +995,9 @@ restart: /* Write pattern space to file. */ case 'w': - sed_cmd->last_char = puts_maybe_newline( + /*sed_cmd->sw_last_char =*/ puts_maybe_newline( pattern_space, sed_cmd->file, - sed_cmd->last_char, last_char); + last_char); break; /* Read next line from input */ @@ -1123,13 +1136,14 @@ restart: /* * exit point from sedding... */ -discard_commands: + discard_commands: /* we will print the line unless we were told to be quiet ('-n') or if the line was suppressed (ala 'd'elete) */ - if (!bbg.be_quiet) sed_puts(pattern_space, last_char); + if (!bbg.be_quiet) + sed_puts(pattern_space, last_char); /* Delete and such jump here. */ -discard_line: + discard_line: flush_append(); free(pattern_space); |