From owner-svn-src-head@FreeBSD.ORG  Fri Aug  8 17:29:02 2014
Return-Path: <owner-svn-src-head@FreeBSD.ORG>
Delivered-To: svn-src-head@freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org
 [IPv6:2001:1900:2254:206a::19:1])
 (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
 (No client certificate requested)
 by hub.freebsd.org (Postfix) with ESMTPS id 63270C18
 for <svn-src-head@freebsd.org>; Fri,  8 Aug 2014 17:29:02 +0000 (UTC)
Received: from svn.freebsd.org (svn.freebsd.org
 [IPv6:2001:1900:2254:2068::e6a:0])
 (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
 (Client did not present a certificate)
 by mx1.freebsd.org (Postfix) with ESMTPS id 44F53209A
 for <svn-src-head@freebsd.org>; Fri,  8 Aug 2014 17:29:02 +0000 (UTC)
Received: from dumbbell (uid 1042) (envelope-from dumbbell@FreeBSD.org) id 23d7
 by svn.freebsd.org (DragonFly Mail Agent v0.9+);
 Fri, 08 Aug 2014 17:29:01 +0000
From: Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
Date: Fri, 8 Aug 2014 17:29:01 +0000 (UTC)
To: src-committers@freebsd.org, svn-src-all@freebsd.org,
 svn-src-head@freebsd.org
Subject: svn commit: r269729 - in head/usr.bin/sed: . tests
X-SVN-Group: head
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Message-Id: <53e508dd.23d7.7477a7f9@svn.freebsd.org>
X-BeenThere: svn-src-head@freebsd.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: SVN commit messages for the src tree for head/-current
 <svn-src-head.freebsd.org>
List-Unsubscribe: <http://lists.freebsd.org/mailman/options/svn-src-head>,
 <mailto:svn-src-head-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/svn-src-head/>
List-Post: <mailto:svn-src-head@freebsd.org>
List-Help: <mailto:svn-src-head-request@freebsd.org?subject=help>
List-Subscribe: <http://lists.freebsd.org/mailman/listinfo/svn-src-head>,
 <mailto:svn-src-head-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Fri, 08 Aug 2014 17:29:02 -0000

Author: dumbbell
Date: Fri Aug  8 17:29:01 2014
New Revision: 269729
URL: http://svnweb.freebsd.org/changeset/base/269729

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

Modified:
  head/usr.bin/sed/defs.h
  head/usr.bin/sed/main.c
  head/usr.bin/sed/process.c
  head/usr.bin/sed/tests/regress.y.out

Modified: head/usr.bin/sed/defs.h
==============================================================================
--- head/usr.bin/sed/defs.h	Fri Aug  8 17:12:03 2014	(r269728)
+++ head/usr.bin/sed/defs.h	Fri Aug  8 17:29:01 2014	(r269729)
@@ -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;

Modified: head/usr.bin/sed/main.c
==============================================================================
--- head/usr.bin/sed/main.c	Fri Aug  8 17:12:03 2014	(r269728)
+++ head/usr.bin/sed/main.c	Fri Aug  8 17:29:01 2014	(r269729)
@@ -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);
 }

Modified: head/usr.bin/sed/process.c
==============================================================================
--- head/usr.bin/sed/process.c	Fri Aug  8 17:12:03 2014	(r269728)
+++ head/usr.bin/sed/process.c	Fri Aug  8 17:29:01 2014	(r269729)
@@ -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;
 	}

Modified: head/usr.bin/sed/tests/regress.y.out
==============================================================================
--- head/usr.bin/sed/tests/regress.y.out	Fri Aug  8 17:12:03 2014	(r269728)
+++ head/usr.bin/sed/tests/regress.y.out	Fri Aug  8 17:29:01 2014	(r269729)
@@ -1 +1 @@
-fOO
+fOO
\ No newline at end of file