Module Name:    src
Committed By:   christos
Date:           Fri May 15 22:39:54 UTC 2020

Modified Files:
        src/usr.bin/sed: defs.h main.c process.c

Log Message:
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.

>From FreeBSD (9dd857db3dc558dc61dc8674d204ebc83cac0739), requested by mrg@


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/usr.bin/sed/defs.h
cvs rdiff -u -r1.35 -r1.36 src/usr.bin/sed/main.c
cvs rdiff -u -r1.52 -r1.53 src/usr.bin/sed/process.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/sed/defs.h
diff -u src/usr.bin/sed/defs.h:1.12 src/usr.bin/sed/defs.h:1.13
--- src/usr.bin/sed/defs.h:1.12	Fri Jun  6 17:56:39 2014
+++ src/usr.bin/sed/defs.h	Fri May 15 18:39:54 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: defs.h,v 1.12 2014/06/06 21:56:39 wiz Exp $	*/
+/*	$NetBSD: defs.h,v 1.13 2020/05/15 22:39:54 christos Exp $	*/
 
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
@@ -145,6 +145,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;

Index: src/usr.bin/sed/main.c
diff -u src/usr.bin/sed/main.c:1.35 src/usr.bin/sed/main.c:1.36
--- src/usr.bin/sed/main.c:1.35	Sat Oct  5 16:22:36 2019
+++ src/usr.bin/sed/main.c	Fri May 15 18:39:54 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.35 2019/10/05 20:22:36 christos Exp $	*/
+/*	$NetBSD: main.c,v 1.36 2020/05/15 22:39:54 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson.
@@ -39,7 +39,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: main.c,v 1.35 2019/10/05 20:22:36 christos Exp $");
+__RCSID("$NetBSD: main.c,v 1.36 2020/05/15 22:39:54 christos Exp $");
 #ifdef __FBSDID
 __FBSDID("$FreeBSD: head/usr.bin/sed/main.c 252231 2013-06-26 04:14:19Z pfg $");
 #endif
@@ -465,8 +465,14 @@ mf_fgets(SPACE *sp, enum e_spflag spflag
 	ssize_t slen = getline(&p, &plen, infile);
 	if (slen == -1)
 		err(1, "%s", fname);
-	if (slen != 0 && p[slen - 1] == '\n')
+	if (slen != 0 && p[slen - 1] == '\n') {
+		sp->append_newline = 1;
 		slen--;
+	} else if (!lastline()) {
+		sp->append_newline = 1;
+	} else {
+		sp->append_newline = 0;
+	}
 	cspace(sp, p, (size_t)slen, spflag);
 
 	linenum++;
@@ -505,15 +511,49 @@ add_file(char *s)
 	fl_nextp = &fp->next;
 }
 
+static int
+next_files_have_lines(void)
+{
+	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);
 }

Index: src/usr.bin/sed/process.c
diff -u src/usr.bin/sed/process.c:1.52 src/usr.bin/sed/process.c:1.53
--- src/usr.bin/sed/process.c:1.52	Thu Mar 12 08:40:41 2015
+++ src/usr.bin/sed/process.c	Fri May 15 18:39:54 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: process.c,v 1.52 2015/03/12 12:40:41 christos Exp $	*/
+/*	$NetBSD: process.c,v 1.53 2020/05/15 22:39:54 christos Exp $	*/
 
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
@@ -38,7 +38,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: process.c,v 1.52 2015/03/12 12:40:41 christos Exp $");
+__RCSID("$NetBSD: process.c,v 1.53 2020/05/15 22:39:54 christos Exp $");
 #ifdef __FBSDID
 __FBSDID("$FreeBSD: head/usr.bin/sed/process.c 192732 2009-05-25 06:45:33Z brian $");
 #endif
@@ -72,6 +72,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
 
@@ -94,7 +95,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)
@@ -103,6 +107,7 @@ process(void)
 	SPACE tspace;
 	size_t oldpsl = 0;
 	char *p;
+	int oldpsanl;
 
 	p = NULL;
 
@@ -198,11 +203,15 @@ redirect:
 					break;
 				if ((p = memchr(ps, '\n', psl - 1)) != NULL) {
 					oldpsl = psl;
+					oldpsanl = psanl;
 					psl = (size_t)(p - ps);
+					psanl = 1;
 				}
 				OUT();
-				if (p != NULL)
+				if (p != NULL) {
 					psl = oldpsl;
+					psanl = oldpsanl;
+				}
 				break;
 			case 'q':
 				if (!nflag && !pd)
@@ -251,6 +260,7 @@ redirect:
 					cspace(&HS, "", 0, REPLACE);
 				tspace = PS;
 				PS = HS;
+				psanl = tspace.append_newline;
 				HS = tspace;
 				break;
 			case 'y':
@@ -459,6 +469,7 @@ substitute(struct s_command *cp)
 	 */
 	tspace = PS;
 	PS = SS;
+	psanl = tspace.append_newline;
 	SS = tspace;
 	SS.space = SS.back;
 
@@ -528,6 +539,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;
 	}

Reply via email to