]> granicus.if.org Git - vim/commitdiff
patch 7.4.1518 v7.4.1518
authorBram Moolenaar <Bram@vim.org>
Tue, 8 Mar 2016 17:27:21 +0000 (18:27 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 8 Mar 2016 17:27:21 +0000 (18:27 +0100)
Problem:    Channel with disconnected in/out/err is not supported.
Solution:   Implement it for Unix.

src/eval.c
src/os_unix.c
src/structs.h
src/testdir/test_channel.vim
src/testdir/test_channel_pipe.py
src/version.c

index 1422dc225d32b1fe4c444644c182567d73afddba..31c5ea2da9120ba92221581789a74cbba6a8ac35 100644 (file)
@@ -10285,7 +10285,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
  * Returns NULL if the handle is invalid.
  */
     static channel_T *
-get_channel_arg(typval_T *tv)
+get_channel_arg(typval_T *tv, int check_open)
 {
     channel_T *channel = NULL;
 
@@ -10304,7 +10304,7 @@ get_channel_arg(typval_T *tv)
        return NULL;
     }
 
-    if (channel == NULL || !channel_is_open(channel))
+    if (check_open && (channel == NULL || !channel_is_open(channel)))
     {
        EMSG(_("E906: not an open channel"));
        return NULL;
@@ -10318,7 +10318,7 @@ get_channel_arg(typval_T *tv)
     static void
 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    channel_T *channel = get_channel_arg(&argvars[0]);
+    channel_T *channel = get_channel_arg(&argvars[0], TRUE);
 
     if (channel != NULL)
     {
@@ -10333,7 +10333,7 @@ f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
     static void
 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
 {
-    channel_T *channel = get_channel_arg(&argvars[0]);
+    channel_T *channel = get_channel_arg(&argvars[0], TRUE);
 
     rettv->vval.v_number = -1;
     if (channel != NULL)
@@ -10361,7 +10361,7 @@ f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
     static void
 f_ch_getjob(typval_T *argvars, typval_T *rettv)
 {
-    channel_T *channel = get_channel_arg(&argvars[0]);
+    channel_T *channel = get_channel_arg(&argvars[0], TRUE);
 
     if (channel != NULL)
     {
@@ -10383,7 +10383,7 @@ f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
     channel_T  *channel = NULL;
 
     if (argvars[1].v_type != VAR_UNKNOWN)
-       channel = get_channel_arg(&argvars[1]);
+       channel = get_channel_arg(&argvars[1], TRUE);
 
     ch_log(channel, (char *)msg);
 }
@@ -10500,7 +10500,7 @@ common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
                                                                      == FAIL)
        return;
 
-    channel = get_channel_arg(&argvars[0]);
+    channel = get_channel_arg(&argvars[0], TRUE);
     if (channel != NULL)
     {
        if (opt.jo_set & JO_PART)
@@ -10570,7 +10570,7 @@ send_common(
     channel_T  *channel;
     int                part_send;
 
-    channel = get_channel_arg(&argvars[0]);
+    channel = get_channel_arg(&argvars[0], TRUE);
     if (channel == NULL)
        return NULL;
     part_send = channel_part_send(channel);
@@ -10619,7 +10619,7 @@ ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
 
-    channel = get_channel_arg(&argvars[0]);
+    channel = get_channel_arg(&argvars[0], TRUE);
     if (channel == NULL)
        return;
     part_send = channel_part_send(channel);
@@ -10736,7 +10736,7 @@ f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     channel_T  *channel;
     jobopt_T   opt;
 
-    channel = get_channel_arg(&argvars[0]);
+    channel = get_channel_arg(&argvars[0], TRUE);
     if (channel == NULL)
        return;
     clear_job_options(&opt);
@@ -10752,17 +10752,14 @@ f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     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;
 
-    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));
+    channel = get_channel_arg(&argvars[0], FALSE);
+    rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel));
 }
 #endif
 
index b4921e3f38f55874758e71949f94d12253b7291c..7eb4e710c9aa1dcfb16b502e0a3bc2b1e3820976 100644 (file)
@@ -5045,11 +5045,17 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
     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,7 +5078,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
            goto failed;
        }
     }
-    else if (pipe(fd_in) < 0)
+    else if (!use_null_for_in && pipe(fd_in) < 0)
        goto failed;
 
     if (use_file_for_out)
@@ -5086,7 +5092,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
            goto failed;
        }
     }
-    else if (pipe(fd_out) < 0)
+    else if (!use_null_for_out && pipe(fd_out) < 0)
        goto failed;
 
     if (use_file_for_err)
@@ -5100,12 +5106,15 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
            goto failed;
        }
     }
-    else if (!use_out_for_err && pipe(fd_err) < 0)
+    else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0)
        goto failed;
 
-    channel = add_channel();
-    if (channel == NULL)
-       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,6 +5126,10 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
 
     if (pid == 0)
     {
+# ifdef FEAT_CHANNEL
+       int             null_fd = -1;
+# endif
+
        /* child */
        reset_signals();                /* handle signals normally */
 
@@ -5131,15 +5144,31 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
 
        /* 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_file_for_in)
-           close(fd_in[1]);
-       close(0);
-       ignored = dup(fd_in[0]);
-       close(fd_in[0]);
+       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_out_for_err)
+       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,11 +5183,21 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
        }
 
        /* 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]);
+       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,17 +5222,23 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
        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
+    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);
+       channel_set_job(channel, job, options);
 #  ifdef FEAT_GUI
-    channel_gui_register(channel);
+       channel_gui_register(channel);
 #  endif
+    }
 # endif
 
+    /* success! */
     return;
 
 failed: ;
index d70c024db995ae61163147ce029a84f105aed73b..7115ede9cae9b05cef9ed2e6c81c2dc952bb6c9f 100644 (file)
@@ -1417,8 +1417,8 @@ struct channel_S {
 #define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
 
 typedef enum {
+    JIO_PIPE,      /* default */
     JIO_NULL,
-    JIO_PIPE,
     JIO_FILE,
     JIO_BUFFER,
     JIO_OUT
index fa494d31808cdfd035e570740fd6e0d757126bbb..0f2b542e058f2914189ee3aade5b7161f6020c20 100644 (file)
@@ -784,6 +784,58 @@ func Test_pipe_io_one_buffer()
   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 = ''
index d5da687309914098b2d69b2498cfb1b8c4dd399b..fa1a40f1315982915eb800062f0f126f007efe39 100644 (file)
@@ -10,7 +10,12 @@ import sys
 if __name__ == "__main__":
 
     if len(sys.argv) > 1:
-        print(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()
index 8c82f67c3ea48116d0845e9d0781699aaedccd01..380c2242d7514524dd776297d6a6ecc87b947dbc 100644 (file)
@@ -743,6 +743,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1518,
 /**/
     1517,
 /**/