summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-12-09 19:13:13 +0100
committerBram Moolenaar <Bram@vim.org>2017-12-09 19:13:13 +0100
commit620ca2da372dc9c892022faff83d363c67cc5c45 (patch)
treef1315ceb93d6cdee927169ee0e349a3b352dcbb5
parent05684310a53c8a4804441c1c6f8b7fc9e8194940 (diff)
patch 8.0.1381: ch_readraw() waits for NL if channel mode is NLv8.0.1381
Problem: ch_readraw() waits for NL if channel mode is NL. Solution: Pass a "raw" flag to channel_read_block(). (Yasuhiro Matsumoto)
-rw-r--r--src/channel.c26
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/testdir/test_channel.vim27
-rw-r--r--src/testdir/test_channel_pipe.py4
-rw-r--r--src/version.c4
5 files changed, 52 insertions, 10 deletions
diff --git a/src/channel.c b/src/channel.c
index 8fc705058a..f7eded21e2 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3313,11 +3313,12 @@ channel_read(channel_T *channel, ch_part_T part, char *func)
/*
* Read from RAW or NL "channel"/"part". Blocks until there is something to
* read or the timeout expires.
+ * When "raw" is TRUE don't block waiting on a NL.
* Returns what was read in allocated memory.
* Returns NULL in case of error or timeout.
*/
- char_u *
-channel_read_block(channel_T *channel, ch_part_T part, int timeout)
+ static char_u *
+channel_read_block(channel_T *channel, ch_part_T part, int timeout, int raw)
{
char_u *buf;
char_u *msg;
@@ -3327,7 +3328,7 @@ channel_read_block(channel_T *channel, ch_part_T part, int timeout)
readq_T *node;
ch_log(channel, "Blocking %s read, timeout: %d msec",
- mode == MODE_RAW ? "RAW" : "NL", timeout);
+ mode == MODE_RAW ? "RAW" : "NL", timeout);
while (TRUE)
{
@@ -3340,6 +3341,10 @@ channel_read_block(channel_T *channel, ch_part_T part, int timeout)
break;
if (channel_collapse(channel, part, mode == MODE_NL) == OK)
continue;
+ /* If not blocking or nothing more is coming then return what we
+ * have. */
+ if (raw || fd == INVALID_FD)
+ break;
}
/* Wait for up to the channel timeout. */
@@ -3366,11 +3371,16 @@ channel_read_block(channel_T *channel, ch_part_T part, int timeout)
nl = channel_first_nl(node);
/* Convert NUL to NL, the internal representation. */
- for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
+ for (p = buf; (nl == NULL || p < nl) && p < buf + node->rq_buflen; ++p)
if (*p == NUL)
*p = NL;
- if (nl + 1 == buf + node->rq_buflen)
+ if (nl == NULL)
+ {
+ /* must be a closed channel with missing NL */
+ msg = channel_get(channel, part);
+ }
+ else if (nl + 1 == buf + node->rq_buflen)
{
/* get the whole buffer */
msg = channel_get(channel, part);
@@ -3513,7 +3523,8 @@ common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
timeout = opt.jo_timeout;
if (raw || mode == MODE_RAW || mode == MODE_NL)
- rettv->vval.v_string = channel_read_block(channel, part, timeout);
+ rettv->vval.v_string = channel_read_block(channel, part,
+ timeout, raw);
else
{
if (opt.jo_set & JO_ID)
@@ -3955,7 +3966,8 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
timeout = opt.jo_timeout;
else
timeout = channel_get_timeout(channel, part_read);
- rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
+ rettv->vval.v_string = channel_read_block(channel, part_read,
+ timeout, TRUE);
}
free_job_options(&opt);
}
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 40742adad3..3738edcee2 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -31,7 +31,6 @@ void channel_close(channel_T *channel, int invoke_close_cb);
void channel_close_in(channel_T *channel);
void channel_clear(channel_T *channel);
void channel_free_all(void);
-char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout);
void common_channel_read(typval_T *argvars, typval_T *rettv, int raw);
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
void channel_handle_events(int only_keep_open);
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 034bd39778..1859afc5b8 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -515,7 +515,7 @@ func Test_nl_pipe()
call assert_equal("AND this", ch_readraw(handle))
call ch_sendraw(handle, "split this line\n")
- call assert_equal("this linethis linethis line", ch_readraw(handle))
+ call assert_equal("this linethis linethis line", ch_read(handle))
let reply = ch_evalraw(handle, "quit\n")
call assert_equal("Goodbye!", reply)
@@ -1266,6 +1266,31 @@ func Test_read_in_close_cb()
endtry
endfunc
+" Use channel in NL mode but received text does not end in NL.
+func Test_read_in_close_cb_incomplete()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_read_in_close_cb_incomplete()')
+
+ let g:Ch_received = ''
+ func! CloseHandler(chan)
+ while ch_status(a:chan, {'part': 'out'}) == 'buffered'
+ let g:Ch_received .= ch_read(a:chan)
+ endwhile
+ endfunc
+ let job = job_start(s:python . " test_channel_pipe.py incomplete",
+ \ {'close_cb': 'CloseHandler'})
+ call assert_equal("run", job_status(job))
+ try
+ call WaitFor('g:Ch_received != ""')
+ call assert_equal('incomplete', g:Ch_received)
+ finally
+ call job_stop(job)
+ delfunc CloseHandler
+ endtry
+endfunc
+
func Test_out_cb_lambda()
if !has('job')
return
diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py
index a67a81a853..940378624b 100644
--- a/src/testdir/test_channel_pipe.py
+++ b/src/testdir/test_channel_pipe.py
@@ -14,6 +14,10 @@ if __name__ == "__main__":
if sys.argv[1].startswith("err"):
print(sys.argv[1], file=sys.stderr)
sys.stderr.flush()
+ elif sys.argv[1].startswith("incomplete"):
+ print(sys.argv[1], end='')
+ sys.stdout.flush()
+ sys.exit(0)
else:
print(sys.argv[1])
sys.stdout.flush()
diff --git a/src/version.c b/src/version.c
index fad2fdc05b..8ae4769504 100644
--- a/src/version.c
+++ b/src/version.c
@@ -772,7 +772,9 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
- 1390,
+ 1381,
+/**/
+ 1380,
/**/
1379,
/**/