Patch 7.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.
Files:      src/channel.c, src/netbeans.c, src/proto/channel.pro


*** ../vim-7.4.1905/src/channel.c       2016-06-05 16:10:49.537012299 +0200
--- src/channel.c       2016-06-07 22:09:11.450339521 +0200
***************
*** 1550,1555 ****
--- 1550,1584 ----
  }
  
  /*
+  * 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,1581 ****
--- 1605,1611 ----
  
  /*
   * 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,1605 ****
      p = res;
      for (node = head->rq_next; node != NULL; node = node->rq_next)
      {
!       STRCPY(p, node->rq_buffer);
        p += node->rq_buflen;
      }
      *p = NUL;
--- 1629,1635 ----
      p = res;
      for (node = head->rq_next; node != NULL; node = node->rq_next)
      {
!       mch_memmove(p, node->rq_buffer, node->rq_buflen);
        p += node->rq_buflen;
      }
      *p = NUL;
***************
*** 1611,1620 ****
--- 1641,1673 ----
        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,1643 ****
      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)
        {
            last_node = last_node->rq_next;
            len += last_node->rq_buflen;
--- 1690,1696 ----
      len = node->rq_buflen + last_node->rq_buflen + 1;
      if (want_nl)
        while (last_node->rq_next != NULL
!               && channel_first_nl(last_node) == NULL)
        {
            last_node = last_node->rq_next;
            len += last_node->rq_buflen;
***************
*** 1646,1659 ****
      p = newbuf = alloc(len);
      if (newbuf == NULL)
        return FAIL;        /* out of memory */
!     STRCPY(p, node->rq_buffer);
      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);
        p += n->rq_buflen;
        vim_free(n->rq_buffer);
      }
--- 1699,1712 ----
      p = newbuf = alloc(len);
      if (newbuf == NULL)
        return FAIL;        /* out of memory */
!     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;
!       mch_memmove(p, n->rq_buffer, n->rq_buflen);
        p += n->rq_buflen;
        vim_free(n->rq_buffer);
      }
***************
*** 1691,1696 ****
--- 1744,1751 ----
      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,2288 ****
--- 2338,2344 ----
      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,2393 ****
        {
            char_u  *nl;
            char_u  *buf;
  
            /* 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);
                if (nl != NULL)
                    break;
                if (channel_collapse(channel, part, TRUE) == FAIL)
                    return FALSE; /* incomplete message */
            }
!           if (nl[1] == NUL)
            {
                /* get the whole buffer, drop the NL */
                msg = channel_get(channel, part);
--- 2431,2457 ----
        {
            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)
            {
!               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 */
            }
!           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,2410 ****
            }
            else
            {
!               /* 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);
            }
        }
        else
            /* For a raw channel we don't know where the message ends, just
!            * get everything we have. */
            msg = channel_get_all(channel, part);
  
        if (msg == NULL)
            return FALSE; /* out of memory (and avoids Coverity warning) */
--- 2459,2477 ----
            }
            else
            {
!               /* 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));
!               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.
!            * 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,2687 ****
  }
  
  /*
-  * 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
--- 2735,2740 ----
***************
*** 3043,3061 ****
      ch_mode_T mode = channel->ch_part[part].ch_mode;
      sock_T    fd = channel->ch_part[part].ch_fd;
      char_u    *nl;
  
      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;
  
        /* Wait for up to the channel timeout. */
        if (fd == INVALID_FD)
--- 3096,3118 ----
      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)
      {
!       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,3081 ****
      }
      else
      {
!       nl = vim_strchr(buf, NL);
!       if (nl[1] == NUL)
        {
            /* get the whole buffer */
            msg = channel_get(channel, part);
--- 3131,3147 ----
      }
      else
      {
!       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,3092 ****
            /* 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);
        }
      }
      if (log_fd != NULL)
--- 3152,3158 ----
            /* Copy the message into allocated memory and remove it from the
             * buffer. */
            msg = vim_strnsave(buf, (int)(nl - buf));
!           channel_consume(channel, part, (int)(nl - buf) + 1);
        }
      }
      if (log_fd != NULL)
*** ../vim-7.4.1905/src/netbeans.c      2016-06-04 17:17:07.042146086 +0200
--- src/netbeans.c      2016-06-07 21:11:33.302387091 +0200
***************
*** 382,399 ****
      void
  netbeans_parse_messages(void)
  {
      char_u    *buffer;
      char_u    *p;
      int               own_node;
  
      while (nb_channel != NULL)
      {
!       buffer = channel_peek(nb_channel, PART_SOCK);
!       if (buffer == NULL)
            break;      /* nothing to read */
  
        /* Locate the first line in the first buffer. */
!       p = vim_strchr(buffer, '\n');
        if (p == NULL)
        {
            /* Command isn't complete.  If there is no following buffer,
--- 382,400 ----
      void
  netbeans_parse_messages(void)
  {
+     readq_T   *node;
      char_u    *buffer;
      char_u    *p;
      int               own_node;
  
      while (nb_channel != NULL)
      {
!       node = channel_peek(nb_channel, PART_SOCK);
!       if (node == NULL)
            break;      /* nothing to read */
  
        /* Locate the first line in the first buffer. */
!       p = channel_first_nl(node);
        if (p == NULL)
        {
            /* Command isn't complete.  If there is no following buffer,
***************
*** 418,431 ****
                own_node = FALSE;
  
            /* now, parse and execute the commands */
!           nb_parse_cmd(buffer);
  
            if (own_node)
                /* buffer finished, dispose of it */
!               vim_free(buffer);
            else
                /* more follows, move it to the start */
!               STRMOVE(buffer, p);
        }
      }
  }
--- 419,432 ----
                own_node = FALSE;
  
            /* now, parse and execute the commands */
!           nb_parse_cmd(node->rq_buffer);
  
            if (own_node)
                /* buffer finished, dispose of it */
!               vim_free(node->rq_buffer);
            else
                /* more follows, move it to the start */
!               channel_consume(nb_channel, PART_SOCK, (int)(p - buffer));
        }
      }
  }
*** ../vim-7.4.1905/src/proto/channel.pro       2016-06-04 17:17:07.042146086 
+0200
--- src/proto/channel.pro       2016-06-07 21:11:54.838386794 +0200
***************
*** 17,30 ****
  void channel_buffer_free(buf_T *buf);
  void channel_write_any_lines(void);
  void channel_write_new_lines(buf_T *buf);
  char_u *channel_get(channel_T *channel, int part);
  int channel_collapse(channel_T *channel, int part, int want_nl);
  int channel_can_write_to(channel_T *channel);
  int channel_is_open(channel_T *channel);
  char *channel_status(channel_T *channel);
  void channel_info(channel_T *channel, dict_T *dict);
  void channel_close(channel_T *channel, int invoke_close_cb);
- char_u *channel_peek(channel_T *channel, int part);
  void channel_clear(channel_T *channel);
  void channel_free_all(void);
  char_u *channel_read_block(channel_T *channel, int part, int timeout);
--- 17,32 ----
  void channel_buffer_free(buf_T *buf);
  void channel_write_any_lines(void);
  void channel_write_new_lines(buf_T *buf);
+ readq_T *channel_peek(channel_T *channel, int part);
+ char_u *channel_first_nl(readq_T *node);
  char_u *channel_get(channel_T *channel, int part);
+ void channel_consume(channel_T *channel, int part, int len);
  int channel_collapse(channel_T *channel, int part, int want_nl);
  int channel_can_write_to(channel_T *channel);
  int channel_is_open(channel_T *channel);
  char *channel_status(channel_T *channel);
  void channel_info(channel_T *channel, dict_T *dict);
  void channel_close(channel_T *channel, int invoke_close_cb);
  void channel_clear(channel_T *channel);
  void channel_free_all(void);
  char_u *channel_read_block(channel_T *channel, int part, int timeout);
*** ../vim-7.4.1905/src/version.c       2016-06-06 21:38:39.159553227 +0200
--- src/version.c       2016-06-07 22:10:43.882338249 +0200
***************
*** 755,756 ****
--- 755,758 ----
  {   /* Add new patch number below this line */
+ /**/
+     1906,
  /**/

-- 
Q: Should I clean my house or work on Vim?
A: Whatever contains more bugs.

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui