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
This commit is contained in:
Jean-Sébastien Pédron 2014-08-08 17:29:01 +00:00
parent 39ffa8c138
commit 96d68291af
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=269729
4 changed files with 61 additions and 8 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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 @@ process(void)
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 @@ process(void)
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;
}

View File

@ -1 +1 @@
fOO
fOO