To: vim_dev@googlegroups.com Subject: Patch 7.4.1518 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1518 Problem: Channel with disconnected in/out/err is not supported. Solution: Implement it for Unix. Files: src/eval.c, src/os_unix.c, src/structs.h, src/testdir/test_channel.vim, src/testdir/test_channel_pipe.py *** ../vim-7.4.1517/src/eval.c 2016-03-08 17:08:38.558223138 +0100 --- src/eval.c 2016-03-08 18:18:34.206760505 +0100 *************** *** 10285,10291 **** * Returns NULL if the handle is invalid. */ static channel_T * ! get_channel_arg(typval_T *tv) { channel_T *channel = NULL; --- 10285,10291 ---- * Returns NULL if the handle is invalid. */ static channel_T * ! get_channel_arg(typval_T *tv, int check_open) { channel_T *channel = NULL; *************** *** 10304,10310 **** return NULL; } ! if (channel == NULL || !channel_is_open(channel)) { EMSG(_("E906: not an open channel")); return NULL; --- 10304,10310 ---- return NULL; } ! if (check_open && (channel == NULL || !channel_is_open(channel))) { EMSG(_("E906: not an open channel")); return NULL; *************** *** 10318,10324 **** static void f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) { ! channel_T *channel = get_channel_arg(&argvars[0]); if (channel != NULL) { --- 10318,10324 ---- static void f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) { ! channel_T *channel = get_channel_arg(&argvars[0], TRUE); if (channel != NULL) { *************** *** 10333,10339 **** static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv) { ! channel_T *channel = get_channel_arg(&argvars[0]); rettv->vval.v_number = -1; if (channel != NULL) --- 10333,10339 ---- static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv) { ! channel_T *channel = get_channel_arg(&argvars[0], TRUE); rettv->vval.v_number = -1; if (channel != NULL) *************** *** 10361,10367 **** static void f_ch_getjob(typval_T *argvars, typval_T *rettv) { ! channel_T *channel = get_channel_arg(&argvars[0]); if (channel != NULL) { --- 10361,10367 ---- static void f_ch_getjob(typval_T *argvars, typval_T *rettv) { ! channel_T *channel = get_channel_arg(&argvars[0], TRUE); if (channel != NULL) { *************** *** 10383,10389 **** channel_T *channel = NULL; if (argvars[1].v_type != VAR_UNKNOWN) ! channel = get_channel_arg(&argvars[1]); ch_log(channel, (char *)msg); } --- 10383,10389 ---- channel_T *channel = NULL; if (argvars[1].v_type != VAR_UNKNOWN) ! channel = get_channel_arg(&argvars[1], TRUE); ch_log(channel, (char *)msg); } *************** *** 10500,10506 **** == FAIL) return; ! channel = get_channel_arg(&argvars[0]); if (channel != NULL) { if (opt.jo_set & JO_PART) --- 10500,10506 ---- == FAIL) return; ! channel = get_channel_arg(&argvars[0], TRUE); if (channel != NULL) { if (opt.jo_set & JO_PART) *************** *** 10570,10576 **** channel_T *channel; int part_send; ! channel = get_channel_arg(&argvars[0]); if (channel == NULL) return NULL; part_send = channel_part_send(channel); --- 10570,10576 ---- channel_T *channel; int part_send; ! channel = get_channel_arg(&argvars[0], TRUE); if (channel == NULL) return NULL; part_send = channel_part_send(channel); *************** *** 10619,10625 **** rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; ! channel = get_channel_arg(&argvars[0]); if (channel == NULL) return; part_send = channel_part_send(channel); --- 10619,10625 ---- rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; ! channel = get_channel_arg(&argvars[0], TRUE); if (channel == NULL) return; part_send = channel_part_send(channel); *************** *** 10736,10742 **** channel_T *channel; jobopt_T opt; ! channel = get_channel_arg(&argvars[0]); if (channel == NULL) return; clear_job_options(&opt); --- 10736,10742 ---- channel_T *channel; jobopt_T opt; ! channel = get_channel_arg(&argvars[0], TRUE); if (channel == NULL) return; clear_job_options(&opt); *************** *** 10752,10768 **** static void f_ch_status(typval_T *argvars, typval_T *rettv) { /* return an empty string by default */ rettv->v_type = VAR_STRING; ! if (argvars[0].v_type != VAR_CHANNEL) ! { ! EMSG2(_(e_invarg2), get_tv_string(&argvars[0])); ! rettv->vval.v_string = NULL; ! } ! else ! rettv->vval.v_string = vim_strsave( ! (char_u *)channel_status(argvars[0].vval.v_channel)); } #endif --- 10752,10765 ---- static void f_ch_status(typval_T *argvars, typval_T *rettv) { + channel_T *channel; + /* return an empty string by default */ rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; ! channel = get_channel_arg(&argvars[0], FALSE); ! rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel)); } #endif *** ../vim-7.4.1517/src/os_unix.c 2016-03-08 15:37:36.734963213 +0100 --- src/os_unix.c 2016-03-08 18:00:02.826270515 +0100 *************** *** 5045,5055 **** --- 5045,5061 ---- int fd_out[2]; /* for stdout */ int fd_err[2]; /* for stderr */ channel_T *channel = NULL; + int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; + int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; + int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL; int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE; int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE; int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT; + if (use_out_for_err && use_null_for_out) + use_null_for_err = TRUE; + /* default is to fail */ job->jv_status = JOB_FAILED; fd_in[0] = -1; *************** *** 5072,5078 **** goto failed; } } ! else if (pipe(fd_in) < 0) goto failed; if (use_file_for_out) --- 5078,5084 ---- goto failed; } } ! else if (!use_null_for_in && pipe(fd_in) < 0) goto failed; if (use_file_for_out) *************** *** 5086,5092 **** goto failed; } } ! else if (pipe(fd_out) < 0) goto failed; if (use_file_for_err) --- 5092,5098 ---- goto failed; } } ! else if (!use_null_for_out && pipe(fd_out) < 0) goto failed; if (use_file_for_err) *************** *** 5100,5111 **** goto failed; } } ! else if (!use_out_for_err && pipe(fd_err) < 0) goto failed; ! channel = add_channel(); ! if (channel == NULL) ! goto failed; # endif pid = fork(); /* maybe we should use vfork() */ --- 5106,5120 ---- goto failed; } } ! else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0) goto failed; ! if (!use_null_for_in || !use_null_for_out || !use_null_for_err) ! { ! channel = add_channel(); ! if (channel == NULL) ! goto failed; ! } # endif pid = fork(); /* maybe we should use vfork() */ *************** *** 5117,5122 **** --- 5126,5135 ---- if (pid == 0) { + # ifdef FEAT_CHANNEL + int null_fd = -1; + # endif + /* child */ reset_signals(); /* handle signals normally */ *************** *** 5131,5145 **** /* TODO: re-enable this when pipes connect without a channel */ # ifdef FEAT_CHANNEL /* set up stdin for the child */ ! if (!use_file_for_in) ! close(fd_in[1]); ! close(0); ! ignored = dup(fd_in[0]); ! close(fd_in[0]); /* set up stderr for the child */ ! if (use_out_for_err) { close(2); ignored = dup(fd_out[1]); --- 5144,5174 ---- /* TODO: re-enable this when pipes connect without a channel */ # ifdef FEAT_CHANNEL + if (use_null_for_in || use_null_for_out || use_null_for_err) + null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0); + /* set up stdin for the child */ ! if (use_null_for_in) ! { ! close(0); ! ignored = dup(null_fd); ! } ! else ! { ! if (!use_file_for_in) ! close(fd_in[1]); ! close(0); ! ignored = dup(fd_in[0]); ! close(fd_in[0]); ! } /* set up stderr for the child */ ! if (use_null_for_err) ! { ! close(2); ! ignored = dup(null_fd); ! } ! else if (use_out_for_err) { close(2); ignored = dup(fd_out[1]); *************** *** 5154,5164 **** } /* set up stdout for the child */ ! if (!use_file_for_out) ! close(fd_out[0]); ! close(1); ! ignored = dup(fd_out[1]); ! close(fd_out[1]); # endif /* See above for type of argv. */ --- 5183,5203 ---- } /* set up stdout for the child */ ! if (use_null_for_out) ! { ! close(0); ! ignored = dup(null_fd); ! } ! else ! { ! if (!use_file_for_out) ! close(fd_out[0]); ! close(1); ! ignored = dup(fd_out[1]); ! close(fd_out[1]); ! } ! if (null_fd >= 0) ! close(null_fd); # endif /* See above for type of argv. */ *************** *** 5183,5199 **** close(fd_out[1]); if (!use_out_for_err && !use_file_for_err) close(fd_err[1]); ! channel_set_pipes(channel, ! use_file_for_in ? INVALID_FD : fd_in[1], ! use_file_for_out ? INVALID_FD : fd_out[0], ! use_out_for_err || use_file_for_err ? INVALID_FD : fd_err[0]); ! channel_set_job(channel, job, options); # ifdef FEAT_GUI ! channel_gui_register(channel); # endif # endif return; failed: ; --- 5222,5244 ---- close(fd_out[1]); if (!use_out_for_err && !use_file_for_err) close(fd_err[1]); ! if (channel != NULL) ! { ! channel_set_pipes(channel, ! use_file_for_in || use_null_for_in ! ? INVALID_FD : fd_in[1], ! use_file_for_out || use_null_for_out ! ? INVALID_FD : fd_out[0], ! use_out_for_err || use_file_for_err || use_null_for_err ? INVALID_FD : fd_err[0]); ! channel_set_job(channel, job, options); # ifdef FEAT_GUI ! channel_gui_register(channel); # endif + } # endif + /* success! */ return; failed: ; *** ../vim-7.4.1517/src/structs.h 2016-03-06 20:22:20.352165976 +0100 --- src/structs.h 2016-03-08 17:53:21.790418035 +0100 *************** *** 1417,1424 **** #define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT) typedef enum { JIO_NULL, - JIO_PIPE, JIO_FILE, JIO_BUFFER, JIO_OUT --- 1417,1424 ---- #define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT) typedef enum { + JIO_PIPE, /* default */ JIO_NULL, JIO_FILE, JIO_BUFFER, JIO_OUT *** ../vim-7.4.1517/src/testdir/test_channel.vim 2016-03-08 16:06:51.048733393 +0100 --- src/testdir/test_channel.vim 2016-03-08 18:19:39.738081447 +0100 *************** *** 784,789 **** --- 784,841 ---- endtry endfunc + func Test_pipe_null() + if !has('job') + return + endif + " TODO: implement this for MS-Windows + if !has('unix') + return + endif + call ch_log('Test_pipe_null()') + + " We cannot check that no I/O works, we only check that the job starts + " properly. + let job = job_start(s:python . " test_channel_pipe.py something", + \ {'in-io': 'null'}) + call assert_equal("run", job_status(job)) + try + call assert_equal('something', ch_read(job)) + finally + call job_stop(job) + endtry + + let job = job_start(s:python . " test_channel_pipe.py err-out", + \ {'out-io': 'null'}) + call assert_equal("run", job_status(job)) + try + call assert_equal('err-out', ch_read(job, {"part": "err"})) + finally + call job_stop(job) + endtry + + let job = job_start(s:python . " test_channel_pipe.py something", + \ {'err-io': 'null'}) + call assert_equal("run", job_status(job)) + try + call assert_equal('something', ch_read(job)) + finally + call job_stop(job) + endtry + + let job = job_start(s:python . " test_channel_pipe.py something", + \ {'out-io': 'null', 'err-io': 'out'}) + call assert_equal("run", job_status(job)) + call job_stop(job) + + let job = job_start(s:python . " test_channel_pipe.py something", + \ {'in-io': 'null', 'out-io': 'null', 'err-io': 'null'}) + call assert_equal("run", job_status(job)) + call assert_equal('channel fail', string(job_getchannel(job))) + call assert_equal('fail', ch_status(job)) + call job_stop(job) + endfunc + """""""""" let s:unletResponse = '' *** ../vim-7.4.1517/src/testdir/test_channel_pipe.py 2016-03-08 15:37:36.734963213 +0100 --- src/testdir/test_channel_pipe.py 2016-03-08 17:31:19.792095528 +0100 *************** *** 10,16 **** if __name__ == "__main__": if len(sys.argv) > 1: ! print(sys.argv[1]) while True: typed = sys.stdin.readline() --- 10,21 ---- if __name__ == "__main__": if len(sys.argv) > 1: ! if sys.argv[1].startswith("err"): ! print(sys.argv[1], file=sys.stderr) ! sys.stderr.flush() ! else: ! print(sys.argv[1]) ! sys.stdout.flush() while True: typed = sys.stdin.readline() *** ../vim-7.4.1517/src/version.c 2016-03-08 17:13:02.063486804 +0100 --- src/version.c 2016-03-08 17:26:56.018826202 +0100 *************** *** 745,746 **** --- 745,748 ---- { /* Add new patch number below this line */ + /**/ + 1518, /**/ -- hundred-and-one symptoms of being an internet addict: 12. You turn off your modem and get this awful empty feeling, like you just pulled the plug on a loved one. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///