diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 23:12:12 +0300 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-02 23:12:12 +0300 |
commit | 1375bc7b678d143798823c719ebba55dce596585 (patch) | |
tree | 35ff0fbbe02e87bd8a638148172d972cb072555a | |
parent | 8b22b07bc599ca39d1b42cabef98189894b2162f (diff) |
sed: fix handling of files not ending in '\n'
-rw-r--r-- | editors/sed.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/editors/sed.c b/editors/sed.c index 630d6d792..94368aa68 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -81,6 +81,7 @@ typedef struct sed_cmd_s { unsigned int invert:1; /* the '!' after the address */ 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' */ /* GENERAL FIELDS */ @@ -715,12 +716,9 @@ static void add_input_file(FILE *file) static char *get_next_line(int *last_char) { char *temp = NULL; - int len; - - /* will be returned if last line in the file - * doesn't end with either '\n' or '\0' */ - *last_char = 0x100; + int len, lc; + lc = 0; flush_append(); while (bbg.current_input_file < bbg.input_file_count) { temp = bb_get_chunk_from_file( @@ -730,18 +728,27 @@ static char *get_next_line(int *last_char) char c = temp[len-1]; if (c == '\n' || c == '\0') { temp[len-1] = '\0'; - *last_char = (unsigned char)c; + lc |= (unsigned char)c; + break; } + /* will be returned if last line in the file + * doesn't end with either '\n' or '\0' */ + lc |= 0x100; 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; } + *last_char = lc; return temp; } /* Output line of text. */ /* Note: + * The tricks with 0x200 and last_puts_char are there to emulate gnu sed. + * Without them, we had this: * echo -n thingy >z1 * echo -n again >z2 * >znull @@ -750,13 +757,26 @@ static char *get_next_line(int *last_char) * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| * bbox: * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| - * I am not sure that bbox is wrong here... */ static int puts_maybe_newline(char *s, FILE *file, int prev_last_char, int last_char) { + static char last_puts_char; + + /* Is this a first line from new file + * and old file didn't end with '\n'? */ + if ((last_char & 0x200) && last_puts_char != '\n') { + fputc('\n', file); + last_puts_char = '\n'; + } fputs(s, file); - if (last_char < 0x100) fputc(last_char, file); + /* 'x': we don't care what is it, but we know it isn't '\n' */ + if (s[0]) last_puts_char = 'x'; + if (!(last_char & 0x100)) { /* had trailing '\n' or '\0'? */ + last_char &= 0xff; + fputc(last_char, file); + last_puts_char = last_char; + } if (ferror(file)) { xfunc_error_retval = 4; /* It's what gnu sed exits with... */ @@ -1047,7 +1067,7 @@ restart: strcat(pattern_space, "\n"); if (bbg.hold_space) strcat(pattern_space, bbg.hold_space); - last_char = 0x100; + last_char = '\n'; break; } @@ -1079,7 +1099,7 @@ restart: { char *tmp = pattern_space; pattern_space = bbg.hold_space ? : xzalloc(1); - last_char = 0x100; + last_char = '\n'; bbg.hold_space = tmp; break; } |