changeset 8430:800423dbc260 v7.4.1506

commit https://github.com/vim/vim/commit/b69fccf377f43544b86817b0de6cc1498a4ff9ec Author: Bram Moolenaar <Bram@vim.org> Date: Sun Mar 6 23:06:25 2016 +0100 patch 7.4.1506 Problem: Job cannot read from a file. Solution: Implement reading from a file for Unix.
author Christian Brabandt <cb@256bit.org>
date Sun, 06 Mar 2016 23:15:05 +0100
parents eac8a407df71
children d036b4be99b0
files src/eval.c src/os_unix.c src/os_win32.c src/testdir/test_channel.vim src/version.c
diffstat 5 files changed, 85 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -15118,6 +15118,7 @@ f_job_start(typval_T *argvars UNUSED, ty
     garray_T	ga;
 #endif
     jobopt_T	opt;
+    int		part;
 
     rettv->v_type = VAR_JOB;
     job = job_alloc();
@@ -15135,6 +15136,17 @@ f_job_start(typval_T *argvars UNUSED, ty
 			    + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO) == FAIL)
 	return;
 
+    /* Check that when io is "file" that there is a file name. */
+    for (part = PART_OUT; part <= PART_IN; ++part)
+	if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
+		&& opt.jo_io[part] == JIO_FILE
+		&& (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
+		    || *opt.jo_io_name[part] == NUL))
+	{
+	    EMSG(_("E920: -io file requires -name to be set"));
+	    return;
+	}
+
     if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
     {
 	buf_T *buf;
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5045,6 +5045,7 @@ mch_start_job(char **argv, job_T *job, j
     int		fd_out[2];	/* for stdout */
     int		fd_err[2];	/* for stderr */
     channel_T	*channel = NULL;
+    int		use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
     int		use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
 
     /* default is to fail */
@@ -5055,8 +5056,22 @@ mch_start_job(char **argv, job_T *job, j
 
     /* TODO: without the channel feature connect the child to /dev/null? */
     /* Open pipes for stdin, stdout, stderr. */
-    if (pipe(fd_in) < 0 || pipe(fd_out) < 0
-				    || (!use_out_for_err && pipe(fd_err) < 0))
+    if (use_file_for_in)
+    {
+	char_u *fname = options->jo_io_name[PART_IN];
+
+	fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
+	if (fd_in[0] < 0)
+	{
+	    EMSG2(_(e_notopen), fname);
+	    goto failed;
+	}
+    }
+    else if (pipe(fd_in) < 0)
+	goto failed;
+    if (pipe(fd_out) < 0)
+	goto failed;
+    if (!use_out_for_err && pipe(fd_err) < 0)
 	goto failed;
 
     channel = add_channel();
@@ -5088,7 +5103,8 @@ mch_start_job(char **argv, job_T *job, j
 	/* TODO: re-enable this when pipes connect without a channel */
 # ifdef FEAT_CHANNEL
 	/* set up stdin for the child */
-	close(fd_in[1]);
+	if (!use_file_for_in)
+	    close(fd_in[1]);
 	close(0);
 	ignored = dup(fd_in[0]);
 	close(fd_in[0]);
@@ -5130,12 +5146,15 @@ mch_start_job(char **argv, job_T *job, j
 
 # ifdef FEAT_CHANNEL
     /* child stdin, stdout and stderr */
-    close(fd_in[0]);
+    if (!use_file_for_in)
+	close(fd_in[0]);
     close(fd_out[1]);
     if (!use_out_for_err)
 	close(fd_err[1]);
-    channel_set_pipes(channel, fd_in[1], fd_out[0],
-				    use_out_for_err ? INVALID_FD : fd_err[0]);
+    channel_set_pipes(channel,
+		      use_file_for_in ? INVALID_FD : fd_in[1],
+		      fd_out[0],
+		      use_out_for_err ? INVALID_FD : fd_err[0]);
     channel_set_job(channel, job, options);
 #  ifdef FEAT_GUI
     channel_gui_register(channel);
@@ -5151,7 +5170,8 @@ failed: ;
     if (fd_in[0] >= 0)
     {
 	close(fd_in[0]);
-	close(fd_in[1]);
+	if (!use_file_for_in)
+	    close(fd_in[1]);
     }
     if (fd_out[0] >= 0)
     {
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5000,6 +5000,7 @@ mch_start_job(char *cmd, job_T *job, job
     HANDLE		jo;
 # ifdef FEAT_CHANNEL
     channel_T		*channel;
+    int			use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
     int			use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
     HANDLE		ifd[2];
     HANDLE		ofd[2];
@@ -5035,13 +5036,25 @@ mch_start_job(char *cmd, job_T *job, job
     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
     saAttr.bInheritHandle = TRUE;
     saAttr.lpSecurityDescriptor = NULL;
-    if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
-       || !pSetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)
-       || !CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
-       || !pSetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)
-       || (!use_out_for_err
+    if (use_file_for_in)
+    {
+	char_u *fname = options->jo_io_name[PART_IN];
+
+	// TODO
+	EMSG2(_(e_notopen), fname);
+	goto failed;
+    }
+    else if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
+	    || !pSetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0))
+	goto failed;
+
+    if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
+	    || !pSetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0))
+	goto failed;
+
+    if (!use_out_for_err
 	   && (!CreatePipe(&efd[0], &efd[1], &saAttr, 0)
-	    || !pSetHandleInformation(efd[0], HANDLE_FLAG_INHERIT, 0))))
+	    || !pSetHandleInformation(efd[0], HANDLE_FLAG_INHERIT, 0)))
 	goto failed;
     si.dwFlags |= STARTF_USESTDHANDLES;
     si.hStdInput = ifd[0];
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -524,6 +524,31 @@ func Test_nl_err_to_out_pipe()
   endtry
 endfunc
 
+func Test_nl_read_file()
+  if !has('job')
+    return
+  endif
+  " TODO: make this work for MS-Windows.
+  if !has('unix')
+    return
+  endif
+  call ch_log('Test_nl_read_file()')
+  call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput')
+  let job = job_start(s:python . " test_channel_pipe.py",
+	\ {'in-io': 'file', 'in-name': 'Xinput'})
+  call assert_equal("run", job_status(job))
+  try
+    let handle = job_getchannel(job)
+    call assert_equal("something", ch_readraw(handle))
+    call assert_equal("wrong", ch_readraw(handle, {'part': 'err'}))
+    call assert_equal("this", ch_readraw(handle))
+    call assert_equal("AND this", ch_readraw(handle))
+  finally
+    call job_stop(job)
+    call delete('Xinput')
+  endtry
+endfunc
+
 func Test_pipe_to_buffer()
   if !has('job')
     return
@@ -556,7 +581,6 @@ func Test_pipe_from_buffer()
   if !has('job')
     return
   endif
-call ch_logfile('channellog', 'w')
   call ch_log('Test_pipe_from_buffer()')
 
   sp pipe-input
@@ -574,7 +598,6 @@ call ch_logfile('channellog', 'w')
   finally
     call job_stop(job)
   endtry
-call ch_logfile('')
 endfunc
 
 func Test_pipe_to_nameless_buffer()
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1506,
+/**/
     1505,
 /**/
     1504,