diff options
author | dumbbell <dumbbell@FreeBSD.org> | 2014-08-08 17:29:01 +0000 |
---|---|---|
committer | dumbbell <dumbbell@FreeBSD.org> | 2014-08-08 17:29:01 +0000 |
commit | 9dd857db3dc558dc61dc8674d204ebc83cac0739 (patch) | |
tree | 56fad7945f924294efc11e0543b0c26cd444943a | |
parent | 094158b3f2a6f1f1c94fd8c1357192c5d7486a79 (diff) | |
download | FreeBSD-src-9dd857db3dc558dc61dc8674d204ebc83cac0739.zip FreeBSD-src-9dd857db3dc558dc61dc8674d204ebc83cac0739.tar.gz |
sed(1): Don't force a newline on last line, if input stream doesn't have one
While here, change how we check if the current line is the last one.
Before, we just checked if there were more files after the current one.
Now, we check the actual content of those files: they files may not have
a line at all. This matches the definition of the "last line" by the
Open Group.
The new behavior is closer to GNU sed.
PR: 160745
Phabric: https://phabric.freebsd.org/D431
Reviewed by: jilles
Approved by: jilles
Exp-run by: antoine
-rw-r--r-- | usr.bin/sed/defs.h | 1 | ||||
-rw-r--r-- | usr.bin/sed/main.c | 50 | ||||
-rw-r--r-- | usr.bin/sed/process.c | 16 | ||||
-rw-r--r-- | usr.bin/sed/tests/regress.y.out | 2 |
4 files changed, 61 insertions, 8 deletions
diff --git a/usr.bin/sed/defs.h b/usr.bin/sed/defs.h index d4f434e..fb33676 100644 --- a/usr.bin/sed/defs.h +++ b/usr.bin/sed/defs.h @@ -143,6 +143,7 @@ typedef struct { char *space; /* Current space pointer. */ size_t len; /* Current length. */ int deleted; /* If deleted. */ + int append_newline; /* If originally terminated by \n. */ char *back; /* Backing memory. */ size_t blen; /* Backing memory length. */ } SPACE; diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c index 6cdfcda..76e186f 100644 --- a/usr.bin/sed/main.c +++ b/usr.bin/sed/main.c @@ -439,8 +439,14 @@ mf_fgets(SPACE *sp, enum e_spflag spflag) len = getline(&p, &plen, infile); if (len == -1) err(1, "%s", fname); - if (len != 0 && p[len - 1] == '\n') + if (len != 0 && p[len - 1] == '\n') { + sp->append_newline = 1; len--; + } else if (!lastline()) { + sp->append_newline = 1; + } else { + sp->append_newline = 0; + } cspace(sp, p, len, spflag); linenum++; @@ -481,15 +487,49 @@ add_file(char *s) fl_nextp = &fp->next; } +static int +next_files_have_lines() +{ + struct s_flist *file; + FILE *file_fd; + int ch; + + file = files; + while ((file = file->next) != NULL) { + if ((file_fd = fopen(file->fname, "r")) == NULL) + continue; + + if ((ch = getc(file_fd)) != EOF) { + /* + * This next file has content, therefore current + * file doesn't contains the last line. + */ + ungetc(ch, file_fd); + fclose(file_fd); + return (1); + } + + fclose(file_fd); + } + + return (0); +} + int lastline(void) { int ch; - if (files->next != NULL && (inplace == NULL || ispan)) - return (0); - if ((ch = getc(infile)) == EOF) - return (1); + if (feof(infile)) { + return !( + (inplace == NULL || ispan) && + next_files_have_lines()); + } + if ((ch = getc(infile)) == EOF) { + return !( + (inplace == NULL || ispan) && + next_files_have_lines()); + } ungetc(ch, infile); return (0); } diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c index a500200..9cd2c2e 100644 --- a/usr.bin/sed/process.c +++ b/usr.bin/sed/process.c @@ -63,6 +63,7 @@ static SPACE HS, PS, SS, YS; #define pd PS.deleted #define ps PS.space #define psl PS.len +#define psanl PS.append_newline #define hs HS.space #define hsl HS.len @@ -85,7 +86,10 @@ static regex_t *defpreg; size_t maxnsub; regmatch_t *match; -#define OUT() do {fwrite(ps, 1, psl, outfile); fputc('\n', outfile);} while (0) +#define OUT() do { \ + fwrite(ps, 1, psl, outfile); \ + if (psanl) fputc('\n', outfile); \ +} while (0) void process(void) @@ -94,6 +98,7 @@ process(void) SPACE tspace; size_t oldpsl = 0; char *p; + int oldpsanl; p = NULL; @@ -190,11 +195,15 @@ redirect: break; if ((p = memchr(ps, '\n', psl)) != NULL) { oldpsl = psl; + oldpsanl = psanl; psl = p - ps; + psanl = 1; } OUT(); - if (p != NULL) + if (p != NULL) { psl = oldpsl; + psanl = oldpsanl; + } break; case 'q': if (!nflag && !pd) @@ -244,6 +253,7 @@ redirect: cspace(&HS, "", 0, REPLACE); tspace = PS; PS = HS; + psanl = tspace.append_newline; HS = tspace; break; case 'y': @@ -452,6 +462,7 @@ substitute(struct s_command *cp) */ tspace = PS; PS = SS; + psanl = tspace.append_newline; SS = tspace; SS.space = SS.back; @@ -521,6 +532,7 @@ do_tr(struct s_tr *y) /* Swap the translation space and the pattern space. */ tmp = PS; PS = YS; + psanl = tmp.append_newline; YS = tmp; YS.space = YS.back; } diff --git a/usr.bin/sed/tests/regress.y.out b/usr.bin/sed/tests/regress.y.out index 829a681..22f4f05 100644 --- a/usr.bin/sed/tests/regress.y.out +++ b/usr.bin/sed/tests/regress.y.out @@ -1 +1 @@ -fOO +fOO
\ No newline at end of file |