# HG changeset patch # User Christian Brabandt # Date 1457302505 -3600 # Node ID 800423dbc2603769754082c3a44adc5dcccbb9e8 # Parent eac8a407df718a69dfa28b4ac4d93793435af106 commit https://github.com/vim/vim/commit/b69fccf377f43544b86817b0de6cc1498a4ff9ec Author: Bram Moolenaar 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. diff --git a/src/eval.c b/src/eval.c --- 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; diff --git a/src/os_unix.c b/src/os_unix.c --- 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) { diff --git a/src/os_win32.c b/src/os_win32.c --- 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]; diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim --- 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() diff --git a/src/version.c b/src/version.c --- 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,