# HG changeset patch # User Christian Brabandt # Date 1470773706 -7200 # Node ID e84e457866914d76e84a3096ff417d9d0ed33d23 # Parent bc358576ace1c5f5639e2b0ef8680f152e29eecd commit https://github.com/vim/vim/commit/f71d7b9ee5ceba75f70c30845332ddd728fd16c6 Author: Bram Moolenaar Date: Tue Aug 9 22:14:05 2016 +0200 patch 7.4.2189 Problem: Cannot detect encoding in a fifo. Solution: Extend the stdin way of detecting encoding to fifo. Add a test for detecting encoding on stdin and fifo. (Ken Takata) diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -2114,6 +2114,7 @@ test_arglist \ test_signs \ test_sort \ test_startup \ + test_startup_utf8 \ test_stat \ test_statusline \ test_syn_attr \ diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -70,6 +70,64 @@ static char *e_auabort = N_("E855: Autoc /* Number of times free_buffer() was called. */ static int buf_free_count = 0; +/* Read data from buffer for retrying. */ + static int +read_buffer( + int read_stdin, /* read file from stdin, otherwise fifo */ + exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */ + int flags) /* extra flags for readfile() */ +{ + int retval = OK; + linenr_T line_count; + + /* + * Read from the buffer which the text is already filled in and append at + * the end. This makes it possible to retry when 'fileformat' or + * 'fileencoding' was guessed wrong. + */ + line_count = curbuf->b_ml.ml_line_count; + retval = readfile( + read_stdin ? NULL : curbuf->b_ffname, + read_stdin ? NULL : curbuf->b_fname, + (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, + flags | READ_BUFFER); + if (retval == OK) + { + /* Delete the binary lines. */ + while (--line_count >= 0) + ml_delete((linenr_T)1, FALSE); + } + else + { + /* Delete the converted lines. */ + while (curbuf->b_ml.ml_line_count > line_count) + ml_delete(line_count, FALSE); + } + /* Put the cursor on the first line. */ + curwin->w_cursor.lnum = 1; + curwin->w_cursor.col = 0; + + if (read_stdin) + { + /* Set or reset 'modified' before executing autocommands, so that + * it can be changed there. */ + if (!readonlymode && !bufempty()) + changed(); + else if (retval != FAIL) + unchanged(curbuf, FALSE); + +#ifdef FEAT_AUTOCMD +# ifdef FEAT_EVAL + apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, + curbuf, &retval); +# else + apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf); +# endif +#endif + } + return retval; +} + /* * Open current buffer, that is: open the memfile and read the file into * memory. @@ -88,6 +146,7 @@ open_buffer( #ifdef FEAT_SYN_HL long old_tw = curbuf->b_p_tw; #endif + int read_fifo = FALSE; /* * The 'readonly' flag is only set when BF_NEVERLOADED is being reset. @@ -143,17 +202,42 @@ open_buffer( ) { int old_msg_silent = msg_silent; - +#ifdef UNIX + int save_bin = curbuf->b_p_bin; + int perm; +#endif #ifdef FEAT_NETBEANS_INTG int oldFire = netbeansFireChanges; netbeansFireChanges = 0; #endif +#ifdef UNIX + perm = mch_getperm(curbuf->b_ffname); + if (perm >= 0 && (0 +# ifdef S_ISFIFO + || S_ISFIFO(perm) +# endif +# ifdef S_ISSOCK + || S_ISSOCK(perm) +# endif + )) + read_fifo = TRUE; + if (read_fifo) + curbuf->b_p_bin = TRUE; +#endif if (shortmess(SHM_FILEINFO)) msg_silent = 1; retval = readfile(curbuf->b_ffname, curbuf->b_fname, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, - flags | READ_NEW); + flags | READ_NEW | (read_fifo ? READ_FIFO : 0)); +#ifdef UNIX + if (read_fifo) + { + curbuf->b_p_bin = save_bin; + if (retval == OK) + retval = read_buffer(FALSE, eap, flags); + } +#endif msg_silent = old_msg_silent; #ifdef FEAT_NETBEANS_INTG netbeansFireChanges = oldFire; @@ -164,8 +248,7 @@ open_buffer( } else if (read_stdin) { - int save_bin = curbuf->b_p_bin; - linenr_T line_count; + int save_bin = curbuf->b_p_bin; /* * First read the text in binary mode into the buffer. @@ -179,42 +262,7 @@ open_buffer( flags | (READ_NEW + READ_STDIN)); curbuf->b_p_bin = save_bin; if (retval == OK) - { - line_count = curbuf->b_ml.ml_line_count; - retval = readfile(NULL, NULL, (linenr_T)line_count, - (linenr_T)0, (linenr_T)MAXLNUM, eap, - flags | READ_BUFFER); - if (retval == OK) - { - /* Delete the binary lines. */ - while (--line_count >= 0) - ml_delete((linenr_T)1, FALSE); - } - else - { - /* Delete the converted lines. */ - while (curbuf->b_ml.ml_line_count > line_count) - ml_delete(line_count, FALSE); - } - /* Put the cursor on the first line. */ - curwin->w_cursor.lnum = 1; - curwin->w_cursor.col = 0; - - /* Set or reset 'modified' before executing autocommands, so that - * it can be changed there. */ - if (!readonlymode && !bufempty()) - changed(); - else if (retval != FAIL) - unchanged(curbuf, FALSE); -#ifdef FEAT_AUTOCMD -# ifdef FEAT_EVAL - apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, - curbuf, &retval); -# else - apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf); -# endif -#endif - } + retval = read_buffer(TRUE, eap, flags); } /* if first time loading this buffer, init b_chartab[] */ @@ -243,7 +291,7 @@ open_buffer( #endif ) changed(); - else if (retval != FAIL && !read_stdin) + else if (retval != FAIL && !read_stdin && !read_fifo) unchanged(curbuf, FALSE); save_file_ff(curbuf); /* keep this fileformat */ diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -212,6 +212,7 @@ filemess( * stdin) * READ_DUMMY read into a dummy buffer (to check if file contents changed) * READ_KEEP_UNDO don't clear undo info or read it from a file + * READ_FIFO read from fifo/socket instead of a file * * return FAIL for failure, OK otherwise */ @@ -231,6 +232,7 @@ readfile( int filtering = (flags & READ_FILTER); int read_stdin = (flags & READ_STDIN); int read_buffer = (flags & READ_BUFFER); + int read_fifo = (flags & READ_FIFO); int set_options = newfile || read_buffer || (eap != NULL && eap->read_edit); linenr_T read_buf_lnum = 1; /* next line to read from curbuf */ @@ -431,7 +433,7 @@ readfile( } } - if (!read_stdin && !read_buffer) + if (!read_stdin && !read_buffer && !read_fifo) { #ifdef UNIX /* @@ -489,7 +491,7 @@ readfile( if (check_readonly && !readonlymode) curbuf->b_p_ro = FALSE; - if (newfile && !read_stdin && !read_buffer) + if (newfile && !read_stdin && !read_buffer && !read_fifo) { /* Remember time of file. */ if (mch_stat((char *)fname, &st) >= 0) @@ -1101,6 +1103,7 @@ retry: * and we can't do it internally or with iconv(). */ if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL + && !read_fifo # ifdef USE_ICONV && iconv_fd == (iconv_t)-1 # endif @@ -1149,7 +1152,7 @@ retry: /* Set "can_retry" when it's possible to rewind the file and try with * another "fenc" value. It's FALSE when no other "fenc" to try, reading * stdin or fixed at a specific encoding. */ - can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc); + can_retry = (*fenc != NUL && !read_stdin && !read_fifo && !keep_dest_enc); #endif if (!skip_read) @@ -1166,6 +1169,7 @@ retry: && curbuf->b_ffname != NULL && curbuf->b_p_udf && !filtering + && !read_fifo && !read_stdin && !read_buffer); if (read_undo_file) @@ -2666,7 +2670,7 @@ failed: #endif #ifdef FEAT_AUTOCMD - if (!read_stdin && !read_buffer) + if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) { int m = msg_scroll; int n = msg_scrolled; @@ -2685,7 +2689,7 @@ failed: if (filtering) apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname, FALSE, curbuf, eap); - else if (newfile) + else if (newfile || (read_buffer && sfname != NULL)) { apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname, FALSE, curbuf, eap); diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -185,6 +185,7 @@ NEW_TESTS = test_arglist.res \ test_ruby.res \ test_signs.res \ test_startup.res \ + test_startup_utf8.res \ test_stat.res \ test_syntax.res \ test_textobjects.res \ diff --git a/src/testdir/test_startup_utf8.vim b/src/testdir/test_startup_utf8.vim new file mode 100644 --- /dev/null +++ b/src/testdir/test_startup_utf8.vim @@ -0,0 +1,64 @@ +" Tests for startup using utf-8. +if !has('multi_byte') + finish +endif + +source shared.vim + +func Test_read_stdin_utf8() + let linesin = ['テスト', '€ÀÈÌÒÙ'] + call writefile(linesin, 'Xtestin') + let before = [ + \ 'set enc=utf-8', + \ 'set fencs=cp932,utf-8', + \ ] + let after = [ + \ 'write ++enc=utf-8 Xtestout', + \ 'quit!', + \ ] + if has('win32') + let pipecmd = 'type Xtestin | ' + else + let pipecmd = 'cat Xtestin | ' + endif + if RunVimPiped(before, after, '-', pipecmd) + let lines = readfile('Xtestout') + call assert_equal(linesin, lines) + else + call assert_equal('', 'RunVimPiped failed.') + endif + call delete('Xtestout') + call delete('Xtestin') +endfunc + +func Test_read_fifo_utf8() + if !has('unix') + return + endif + " Using bash/zsh's process substitution. + if executable('bash') + set shell=bash + elseif executable('zsh') + set shell=zsh + else + return + endif + let linesin = ['テスト', '€ÀÈÌÒÙ'] + call writefile(linesin, 'Xtestin') + let before = [ + \ 'set enc=utf-8', + \ 'set fencs=cp932,utf-8', + \ ] + let after = [ + \ 'write ++enc=utf-8 Xtestout', + \ 'quit!', + \ ] + if RunVim(before, after, '<(cat Xtestin)') + let lines = readfile('Xtestout') + call assert_equal(linesin, lines) + else + call assert_equal('', 'RunVim failed.') + endif + call delete('Xtestout') + call delete('Xtestin') +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2189, +/**/ 2188, /**/ 2187, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -980,7 +980,8 @@ extern char *(*dyn_libintl_textdomain)(c #define READ_STDIN 0x04 /* read from stdin */ #define READ_BUFFER 0x08 /* read from curbuf (converting stdin) */ #define READ_DUMMY 0x10 /* reading into a dummy buffer */ -#define READ_KEEP_UNDO 0x20 /* keep undo info*/ +#define READ_KEEP_UNDO 0x20 /* keep undo info */ +#define READ_FIFO 0x40 /* read from fifo or socket */ /* Values for change_indent() */ #define INDENT_SET 1 /* set indent */