patch 9.0.0826: if 'endofline' is set CTRL-Z may be written in a wrong place

Problem:    If 'endofline' is set the CTRL-Z may be written in the wrong
            place.
Solution:   Write CTRL-Z at the end of the file.  Update the help to explain
            the possibilities better. (Ken Takata, closes #11486)
diff --git a/src/bufwrite.c b/src/bufwrite.c
index 12c5c7a..f3adcc3 100644
--- a/src/bufwrite.c
+++ b/src/bufwrite.c
@@ -2050,10 +2050,6 @@
 		len = 0;
 		write_info.bw_start_lnum = lnum;
 	    }
-	    if (!buf->b_p_fixeol && buf->b_p_eof)
-		// write trailing CTRL-Z
-		(void)write_eintr(write_info.bw_fd, "\x1a", 1);
-
 	    // write failed or last line has no EOL: stop here
 	    if (end == 0
 		    || (lnum == end
@@ -2158,6 +2154,13 @@
 	    nchars += len;
 	}
 
+	if (!buf->b_p_fixeol && buf->b_p_eof)
+	{
+	    // write trailing CTRL-Z
+	    (void)write_eintr(write_info.bw_fd, "\x1a", 1);
+	    nchars++;
+	}
+
 	// Stop when writing done or an error was encountered.
 	if (!checking_conversion || end == 0)
 	    break;
diff --git a/src/fileio.c b/src/fileio.c
index bca8271..9916de8 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2271,27 +2271,32 @@
     if (error && read_count == 0)
 	error = FALSE;
 
-    /*
-     * If we get EOF in the middle of a line, note the fact and
-     * complete the line ourselves.
-     * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
-     */
+    // In Dos format ignore a trailing CTRL-Z, unless 'binary' is set.
+    // In old days the file length was in sector count and the CTRL-Z the
+    // marker where the file really ended.  Assuming we write it to a file
+    // system that keeps file length properly the CTRL-Z should be dropped.
+    // Set the 'endoffile' option so the user can decide what to write later.
+    // In Unix format the CTRL-Z is just another character.
+    if (linerest != 0
+	    && !curbuf->b_p_bin
+	    && fileformat == EOL_DOS
+	    && ptr[-1] == Ctrl_Z)
+    {
+	ptr--;
+	linerest--;
+	if (set_options)
+	    curbuf->b_p_eof = TRUE;
+    }
+
+    // If we get EOF in the middle of a line, note the fact by resetting
+    // 'endofline' and add the line normally.
     if (!error
 	    && !got_int
-	    && linerest != 0
-	    // TODO: should we handle CTRL-Z differently here for 'endoffile'?
-	    && !(!curbuf->b_p_bin
-		&& fileformat == EOL_DOS
-		&& *line_start == Ctrl_Z
-		&& ptr == line_start + 1))
+	    && linerest != 0)
     {
 	// remember for when writing
 	if (set_options)
-	{
 	    curbuf->b_p_eol = FALSE;
-	    if (*line_start == Ctrl_Z && ptr == line_start + 1)
-		curbuf->b_p_eof = TRUE;
-	}
 	*ptr = NUL;
 	len = (colnr_T)(ptr - line_start + 1);
 	if (ml_append(lnum, line_start, len, newfile) == FAIL)
diff --git a/src/testdir/test_fixeol.vim b/src/testdir/test_fixeol.vim
index 9d6c900..41d47d6 100644
--- a/src/testdir/test_fixeol.vim
+++ b/src/testdir/test_fixeol.vim
@@ -48,4 +48,71 @@
   enew!
 endfunc
 
+func Test_eof()
+  let data = 0z68656c6c6f.0d0a.776f726c64   " "hello\r\nworld"
+
+  " 1. Eol, Eof
+  " read
+  call writefile(data + 0z0d0a.1a, 'XXEolEof')
+  e! XXEolEof
+  call assert_equal(['hello', 'world'], getline(1, 2))
+  call assert_equal([1, 1], [&eol, &eof])
+  " write
+  set fixeol
+  w!
+  call assert_equal(data + 0z0d0a, readblob('XXEolEof'))
+  set nofixeol
+  w!
+  call assert_equal(data + 0z0d0a.1a, readblob('XXEolEof'))
+
+  " 2. NoEol, Eof
+  " read
+  call writefile(data + 0z1a, 'XXNoEolEof')
+  e! XXNoEolEof
+  call assert_equal(['hello', 'world'], getline(1, 2))
+  call assert_equal([0, 1], [&eol, &eof])
+  " write
+  set fixeol
+  w!
+  call assert_equal(data + 0z0d0a, readblob('XXNoEolEof'))
+  set nofixeol
+  w!
+  call assert_equal(data + 0z1a, readblob('XXNoEolEof'))
+
+  " 3. Eol, NoEof
+  " read
+  call writefile(data + 0z0d0a, 'XXEolNoEof')
+  e! XXEolNoEof
+  call assert_equal(['hello', 'world'], getline(1, 2))
+  call assert_equal([1, 0], [&eol, &eof])
+  " write
+  set fixeol
+  w!
+  call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+  set nofixeol
+  w!
+  call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+
+  " 4. NoEol, NoEof
+  " read
+  call writefile(data, 'XXNoEolNoEof')
+  e! XXNoEolNoEof
+  call assert_equal(['hello', 'world'], getline(1, 2))
+  call assert_equal([0, 0], [&eol, &eof])
+  " write
+  set fixeol
+  w!
+  call assert_equal(data + 0z0d0a, readblob('XXNoEolNoEof'))
+  set nofixeol
+  w!
+  call assert_equal(data, readblob('XXNoEolNoEof'))
+
+  call delete('XXEolEof')
+  call delete('XXNoEolEof')
+  call delete('XXEolNoEof')
+  call delete('XXNoEolNoEof')
+  set ff& fixeol& eof& eol&
+  enew!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index c1875ad..86cf25a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    826,
+/**/
     825,
 /**/
     824,