]> granicus.if.org Git - vim/commitdiff
patch 9.0.0826: if 'endofline' is set CTRL-Z may be written in a wrong place v9.0.0826
authorK.Takata <kentkt@csc.jp>
Tue, 1 Nov 2022 20:36:19 +0000 (20:36 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 1 Nov 2022 20:36:19 +0000 (20:36 +0000)
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)

runtime/doc/editing.txt
runtime/doc/options.txt
src/bufwrite.c
src/fileio.c
src/testdir/test_fixeol.vim
src/version.c

index 522831f992454c26ef2bb78d12bd4a2d7eb0f40e..e5661b1bb57be117259115911cd5d7c722bab402 100644 (file)
@@ -578,6 +578,43 @@ single <NL> characters are unexpectedly replaced with <CR><NL>.
 You can encrypt files that are written by setting the 'key' option.  This
 provides some security against others reading your files. |encryption|
 
+END OF LINE AND END OF FILE                            *eol-and-eof*
+
+Vim has several options to control the file format:
+       'fileformat'    the <EOL> style: Unix, DOS, Mac
+       'endofline'     whether the last line ends with a <EOL>
+       'endooffile'    whether the file ends with a CTRL-Z
+       'fixendofline'  whether to fix eol and eof
+
+The first three values are normally detected automatically when reading the
+file and are used when writing the text to a file.  While editing the buffer
+it looks like every line has a line ending and the CTRL-Z isn't there (an
+exception is when 'binary' is set, it works differently then).
+
+The 'fixendofline' option can be used to choose what to write.  You can also
+change the option values to write the file differently than how it was read.
+
+Here are some examples how to use them.
+
+If you want files in Unix format (every line NL terminated): >
+       setl ff=unix fixeol
+You should probably do this on any Unix-like system.  Also modern MS-Windows
+systems tend to work well with this.  It is recommended to always use this
+format for Vim scripts.
+
+If you want to use an old MS-DOS file in a modern environment, fixing line
+endings and dropping CTRL-Z, but keeping the <CR><NL> style <EOL>: >
+       setl ff=dos fixeol
+This is useful for many MS-Windows programs, they regularly expect the
+<CR><NL> line endings.
+
+If you want to drop the final <EOL> and add a final CTRL-Z (e.g. for an old
+system like CP/M): >
+       setl ff=dos nofixeol noeol eof
+
+If you want to preserve the fileformat exactly as-is, including any final
+<EOL> and final CTRL-Z: >
+       setl nofixeol
 
 ==============================================================================
 3. The argument list                           *argument-list* *arglist*
index 0a4df61dfa7d8db1809f68bb016ecd9905fc7bbd..bdc473df3e9a0aee56e04cc7cf90f4fb3d3c486a 100644 (file)
@@ -3056,6 +3056,7 @@ A jump table for the options with a short description can be found at |Q_op|.
        When writing a file and this option is off and the 'binary' option
        is on, or 'fixeol' option is off, no CTRL-Z will be written at the
        end of the file.
+       See |eol-and-eof| for example settings.
 
                        *'endofline'* *'eol'* *'noendofline'* *'noeol'*
 'endofline' 'eol'      boolean (default on)
@@ -3071,6 +3072,7 @@ A jump table for the options with a short description can be found at |Q_op|.
        to remember the presence of a <EOL> for the last line in the file, so
        that when you write the file the situation from the original file can
        be kept.  But you can change it if you want to.
+       See |eol-and-eof| for example settings.
 
                             *'equalalways'* *'ea'* *'noequalalways'* *'noea'*
 'equalalways' 'ea'     boolean (default on)
@@ -3466,6 +3468,7 @@ A jump table for the options with a short description can be found at |Q_op|.
        When the 'binary' option is set the value of this option doesn't
        matter.
        See the 'endofline' option.
+       See |eol-and-eof| for example settings.
 
                                        *'fkmap'* *'fk'* *'nofkmap'* *'nofk'*
 'fkmap' 'fk'           boolean (default off)
index 12c5c7a474226f892cbcd08aab6f134ebafb85f3..f3adcc3e8e08f90b85dcd84454e03217474ddb97 100644 (file)
@@ -2050,10 +2050,6 @@ restore_backup:
                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 @@ restore_backup:
            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;
index bca827152a1b3b39691fa6fd2fad5dc782d3850e..9916de8a63e714e9fe2cf9928f456da0868b981c 100644 (file)
@@ -2271,27 +2271,32 @@ failed:
     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)
index 9d6c900bdb3bdeeeb9475b581c1140a68ac472e8..41d47d6a06974edeb024382d9a349384541b9540 100644 (file)
@@ -48,4 +48,71 @@ func Test_fixeol()
   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
index c1875adc7b3b75df2319f4fa2536b47cef6503cb..86cf25ad0cf6bbdf80ae26481afa5cb82deadfe1 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    826,
 /**/
     825,
 /**/