summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko2006-12-02 20:12:12 +0000
committerDenis Vlasenko2006-12-02 20:12:12 +0000
commit1375bc7b678d143798823c719ebba55dce596585 (patch)
tree35ff0fbbe02e87bd8a638148172d972cb072555a
parent8b22b07bc599ca39d1b42cabef98189894b2162f (diff)
downloadbusybox-1375bc7b678d143798823c719ebba55dce596585.zip
busybox-1375bc7b678d143798823c719ebba55dce596585.tar.gz
sed: fix handling of files not ending in '\n'
-rw-r--r--editors/sed.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/editors/sed.c b/editors/sed.c
index 630d6d7..94368aa 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;
}