summaryrefslogtreecommitdiff
path: root/src/channel.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-06-07 22:16:36 +0200
committerBram Moolenaar <Bram@vim.org>2016-06-07 22:16:36 +0200
commit5f1032d2a55b9417a0a6fa225e35089c98a5a419 (patch)
tree5a44e80e39eba782524fdb963604cbadf7e73bf6 /src/channel.c
parentfdd82fe365d0e287bafc71f98c039cb5af8ed827 (diff)
downloadvim-git-5f1032d2a55b9417a0a6fa225e35089c98a5a419.tar.gz
patch 7.4.1906v7.4.1906
Problem: Collapsing channel buffers and searching for NL does not work properly. (Xavier de Gary, Ramel Eshed) Solution: Do not assume the buffer contains a NUL or not. Change NUL bytes to NL to avoid the string is truncated.
Diffstat (limited to 'src/channel.c')
-rw-r--r--src/channel.c136
1 files changed, 101 insertions, 35 deletions
diff --git a/src/channel.c b/src/channel.c
index e60d49e4c..d6ab030de 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1550,6 +1550,35 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
}
/*
+ * Return the first node from "channel"/"part" without removing it.
+ * Returns NULL if there is nothing.
+ */
+ readq_T *
+channel_peek(channel_T *channel, int part)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+
+ return head->rq_next;
+}
+
+/*
+ * Return a pointer to the first NL in "node".
+ * Skips over NUL characters.
+ * Returns NULL if there is no NL.
+ */
+ char_u *
+channel_first_nl(readq_T *node)
+{
+ char_u *buffer = node->rq_buffer;
+ long_u i;
+
+ for (i = 0; i < node->rq_buflen; ++i)
+ if (buffer[i] == NL)
+ return buffer + i;
+ return NULL;
+}
+
+/*
* Return the first buffer from channel "channel"/"part" and remove it.
* The caller must free it.
* Returns NULL if there is nothing.
@@ -1576,6 +1605,7 @@ channel_get(channel_T *channel, int part)
/*
* Returns the whole buffer contents concatenated for "channel"/"part".
+ * Replaces NUL bytes with NL.
*/
static char_u *
channel_get_all(channel_T *channel, int part)
@@ -1599,7 +1629,7 @@ channel_get_all(channel_T *channel, int part)
p = res;
for (node = head->rq_next; node != NULL; node = node->rq_next)
{
- STRCPY(p, node->rq_buffer);
+ mch_memmove(p, node->rq_buffer, node->rq_buflen);
p += node->rq_buflen;
}
*p = NUL;
@@ -1611,10 +1641,33 @@ channel_get_all(channel_T *channel, int part)
vim_free(p);
} while (p != NULL);
+ /* turn all NUL into NL */
+ while (len > 0)
+ {
+ --len;
+ if (res[len] == NUL)
+ res[len] = NL;
+ }
+
return res;
}
/*
+ * Consume "len" bytes from the head of "channel"/"part".
+ * Caller must check these bytes are available.
+ */
+ void
+channel_consume(channel_T *channel, int part, int len)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+ readq_T *node = head->rq_next;
+ char_u *buf = node->rq_buffer;
+
+ mch_memmove(buf, buf + len, node->rq_buflen - len);
+ node->rq_buflen -= len;
+}
+
+/*
* Collapses the first and second buffer for "channel"/"part".
* Returns FAIL if that is not possible.
* When "want_nl" is TRUE collapse more buffers until a NL is found.
@@ -1637,7 +1690,7 @@ channel_collapse(channel_T *channel, int part, int want_nl)
len = node->rq_buflen + last_node->rq_buflen + 1;
if (want_nl)
while (last_node->rq_next != NULL
- && vim_strchr(last_node->rq_buffer, NL) == NULL)
+ && channel_first_nl(last_node) == NULL)
{
last_node = last_node->rq_next;
len += last_node->rq_buflen;
@@ -1646,14 +1699,14 @@ channel_collapse(channel_T *channel, int part, int want_nl)
p = newbuf = alloc(len);
if (newbuf == NULL)
return FAIL; /* out of memory */
- STRCPY(p, node->rq_buffer);
+ mch_memmove(p, node->rq_buffer, node->rq_buflen);
p += node->rq_buflen;
vim_free(node->rq_buffer);
node->rq_buffer = newbuf;
for (n = node; n != last_node; )
{
n = n->rq_next;
- STRCPY(p, n->rq_buffer);
+ mch_memmove(p, n->rq_buffer, n->rq_buflen);
p += n->rq_buflen;
vim_free(n->rq_buffer);
}
@@ -1691,6 +1744,8 @@ channel_save(channel_T *channel, int part, char_u *buf, int len,
node = (readq_T *)alloc(sizeof(readq_T));
if (node == NULL)
return FAIL; /* out of memory */
+ /* A NUL is added at the end, because netbeans code expects that.
+ * Otherwise a NUL may appear inside the text. */
node->rq_buffer = alloc(len + 1);
if (node->rq_buffer == NULL)
{
@@ -2283,6 +2338,7 @@ may_invoke_callback(channel_T *channel, int part)
char_u *callback = NULL;
partial_T *partial = NULL;
buf_T *buffer = NULL;
+ char_u *p;
if (channel->ch_nb_close_cb != NULL)
/* this channel is handled elsewhere (netbeans) */
@@ -2375,19 +2431,27 @@ may_invoke_callback(channel_T *channel, int part)
{
char_u *nl;
char_u *buf;
+ readq_T *node;
/* See if we have a message ending in NL in the first buffer. If
* not try to concatenate the first and the second buffer. */
while (TRUE)
{
- buf = channel_peek(channel, part);
- nl = vim_strchr(buf, NL);
+ node = channel_peek(channel, part);
+ nl = channel_first_nl(node);
if (nl != NULL)
break;
if (channel_collapse(channel, part, TRUE) == FAIL)
return FALSE; /* incomplete message */
}
- if (nl[1] == NUL)
+ buf = node->rq_buffer;
+
+ /* Convert NUL to NL, the internal representation. */
+ for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
+ if (*p == NUL)
+ *p = NL;
+
+ if (nl + 1 == buf + node->rq_buflen)
{
/* get the whole buffer, drop the NL */
msg = channel_get(channel, part);
@@ -2395,16 +2459,19 @@ may_invoke_callback(channel_T *channel, int part)
}
else
{
- /* Copy the message into allocated memory and remove it from
- * the buffer. */
+ /* Copy the message into allocated memory (excluding the NL)
+ * and remove it from the buffer (including the NL). */
msg = vim_strnsave(buf, (int)(nl - buf));
- mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
+ channel_consume(channel, part, (int)(nl - buf) + 1);
}
}
else
+ {
/* For a raw channel we don't know where the message ends, just
- * get everything we have. */
+ * get everything we have.
+ * Convert NUL to NL, the internal representation. */
msg = channel_get_all(channel, part);
+ }
if (msg == NULL)
return FALSE; /* out of memory (and avoids Coverity warning) */
@@ -2668,20 +2735,6 @@ channel_close(channel_T *channel, int invoke_close_cb)
}
/*
- * Return the first buffer from "channel"/"part" without removing it.
- * Returns NULL if there is nothing.
- */
- char_u *
-channel_peek(channel_T *channel, int part)
-{
- readq_T *head = &channel->ch_part[part].ch_head;
-
- if (head->rq_next == NULL)
- return NULL;
- return head->rq_next->rq_buffer;
-}
-
-/*
* Clear the read buffer on "channel"/"part".
*/
static void
@@ -3043,19 +3096,23 @@ channel_read_block(channel_T *channel, int part, int timeout)
ch_mode_T mode = channel->ch_part[part].ch_mode;
sock_T fd = channel->ch_part[part].ch_fd;
char_u *nl;
+ readq_T *node;
ch_logsn(channel, "Blocking %s read, timeout: %d msec",
mode == MODE_RAW ? "RAW" : "NL", timeout);
while (TRUE)
{
- buf = channel_peek(channel, part);
- if (buf != NULL && (mode == MODE_RAW
- || (mode == MODE_NL && vim_strchr(buf, NL) != NULL)))
- break;
- if (buf != NULL && channel_collapse(channel, part, mode == MODE_NL)
- == OK)
- continue;
+ node = channel_peek(channel, part);
+ if (node != NULL)
+ {
+ if (mode == MODE_RAW || (mode == MODE_NL
+ && channel_first_nl(node) != NULL))
+ /* got a complete message */
+ break;
+ if (channel_collapse(channel, part, mode == MODE_NL) == OK)
+ continue;
+ }
/* Wait for up to the channel timeout. */
if (fd == INVALID_FD)
@@ -3074,8 +3131,17 @@ channel_read_block(channel_T *channel, int part, int timeout)
}
else
{
- nl = vim_strchr(buf, NL);
- if (nl[1] == NUL)
+ char_u *p;
+
+ buf = node->rq_buffer;
+ nl = channel_first_nl(node);
+
+ /* Convert NUL to NL, the internal representation. */
+ for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
+ if (*p == NUL)
+ *p = NL;
+
+ if (nl + 1 == buf + node->rq_buflen)
{
/* get the whole buffer */
msg = channel_get(channel, part);
@@ -3086,7 +3152,7 @@ channel_read_block(channel_T *channel, int part, int timeout)
/* Copy the message into allocated memory and remove it from the
* buffer. */
msg = vim_strnsave(buf, (int)(nl - buf));
- mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
+ channel_consume(channel, part, (int)(nl - buf) + 1);
}
}
if (log_fd != NULL)