Patch 7.4.1231
Problem:    JSON messages are not parsed properly.
Solution:   Queue received messages.
Files:      src/eval,c src/channel.c, src/json.c, src/proto/eval.pro,
            src/proto/channel.pro, src/proto/json.pro, src/structs.h


*** ../vim-7.4.1230/src/channel.c       2016-01-31 20:24:09.962066926 +0100
--- src/channel.c       2016-02-01 02:02:48.158391509 +0100
***************
*** 74,85 ****
      struct readqueue  *next;
      struct readqueue  *prev;
  };
! typedef struct readqueue queue_T;
  
  typedef struct {
      sock_T    ch_fd;  /* the socket, -1 for a closed channel */
      int             ch_idx;   /* used by channel_poll_setup() */
!     queue_T   ch_head;        /* dummy node, header for circular queue */
  
      int             ch_error; /* When TRUE an error was reported.  Avoids 
giving
                         * pages full of error messages when the other side
--- 74,93 ----
      struct readqueue  *next;
      struct readqueue  *prev;
  };
! typedef struct readqueue readq_T;
! 
! struct jsonqueue
! {
!     typval_T          *value;
!     struct jsonqueue  *next;
!     struct jsonqueue  *prev;
! };
! typedef struct jsonqueue jsonq_T;
  
  typedef struct {
      sock_T    ch_fd;  /* the socket, -1 for a closed channel */
      int             ch_idx;   /* used by channel_poll_setup() */
!     readq_T   ch_head;        /* dummy node, header for circular queue */
  
      int             ch_error; /* When TRUE an error was reported.  Avoids 
giving
                         * pages full of error messages when the other side
***************
*** 100,106 ****
      char_u    *ch_callback;   /* function to call when a msg is not handled */
      char_u    *ch_req_callback;       /* function to call for current request 
*/
  
!     int             ch_json_mode;
  } channel_T;
  
  /*
--- 108,115 ----
      char_u    *ch_callback;   /* function to call when a msg is not handled */
      char_u    *ch_req_callback;       /* function to call for current request 
*/
  
!     int             ch_json_mode;     /* TRUE for a json channel */
!     jsonq_T   ch_json_head;   /* dummy node, header for circular queue */
  } channel_T;
  
  /*
***************
*** 125,130 ****
--- 134,140 ----
  {
      int               idx;
      channel_T *new_channels;
+     channel_T *ch;
  
      if (channels != NULL)
        for (idx = 0; idx < channel_count; ++idx)
***************
*** 139,156 ****
      if (channels != NULL)
        mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
      channels = new_channels;
!     (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T));
  
!     channels[channel_count].ch_fd = (sock_T)-1;
  #ifdef FEAT_GUI_X11
!     channels[channel_count].ch_inputHandler = (XtInputId)NULL;
  #endif
  #ifdef FEAT_GUI_GTK
!     channels[channel_count].ch_inputHandler = 0;
  #endif
  #ifdef FEAT_GUI_W32
!     channels[channel_count].ch_inputHandler = -1;
  #endif
  
      return channel_count++;
  }
--- 149,172 ----
      if (channels != NULL)
        mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
      channels = new_channels;
!     ch = &channels[channel_count];
!     (void)vim_memset(ch, 0, sizeof(channel_T));
  
!     ch->ch_fd = (sock_T)-1;
  #ifdef FEAT_GUI_X11
!     ch->ch_inputHandler = (XtInputId)NULL;
  #endif
  #ifdef FEAT_GUI_GTK
!     ch->ch_inputHandler = 0;
  #endif
  #ifdef FEAT_GUI_W32
!     ch->ch_inputHandler = -1;
  #endif
+     /* initialize circular queues */
+     ch->ch_head.next = &ch->ch_head;
+     ch->ch_head.prev = &ch->ch_head;
+     ch->ch_json_head.next = &ch->ch_json_head;
+     ch->ch_json_head.prev = &ch->ch_json_head;
  
      return channel_count++;
  }
***************
*** 412,492 ****
      void
  channel_set_req_callback(int idx, char_u *callback)
  {
      vim_free(channels[idx].ch_req_callback);
      channels[idx].ch_req_callback = callback == NULL
                                               ? NULL : vim_strsave(callback);
  }
  
  /*
!  * Decode JSON "msg", which must have the form "[expr1, expr2, expr3]".
!  * Put "expr1" in "tv1".
!  * Put "expr2" in "tv2".
!  * Put "expr3" in "tv3". If "tv3" is NULL there is no "expr3".
!  *
!  * Return OK or FAIL.
   */
      int
! channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3)
  {
      js_read_T reader;
      typval_T  listtv;
  
!     reader.js_buf = msg;
      reader.js_eof = TRUE;
      reader.js_used = 0;
!     json_decode(&reader, &listtv);
! 
!     if (listtv.v_type == VAR_LIST)
!     {
!       list_T *list = listtv.vval.v_list;
! 
!       if (list->lv_len == 2 || (tv3 != NULL && list->lv_len == 3))
        {
!           /* Move the item from the list and then change the type to avoid the
!            * item being freed. */
!           *tv1 = list->lv_first->li_tv;
!           list->lv_first->li_tv.v_type = VAR_NUMBER;
!           *tv2 = list->lv_first->li_next->li_tv;
!           list->lv_first->li_next->li_tv.v_type = VAR_NUMBER;
!           if (tv3 != NULL)
            {
!               if (list->lv_len == 3)
!               {
!                   *tv3 = list->lv_last->li_tv;
!                   list->lv_last->li_tv.v_type = VAR_NUMBER;
!               }
!               else
!                   tv3->v_type = VAR_UNKNOWN;
            }
-           list_unref(list);
-           return OK;
        }
      }
- 
-     /* give error message? */
-     clear_tv(&listtv);
-     return FAIL;
  }
  
  /*
!  * Invoke the "callback" on channel "idx".
   */
      static void
! invoke_callback(int idx, char_u *callback, typval_T *argv)
  {
!     typval_T  rettv;
!     int               dummy;
  
!     argv[0].v_type = VAR_NUMBER;
!     argv[0].vval.v_number = idx;
  
!     call_func(callback, (int)STRLEN(callback),
!                            &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
!     /* If an echo command was used the cursor needs to be put back where
!      * it belongs. */
!     setcursor();
!     cursor_on();
!     out_flush();
  }
  
  /*
--- 428,615 ----
      void
  channel_set_req_callback(int idx, char_u *callback)
  {
+     /* TODO: make a list of callbacks */
      vim_free(channels[idx].ch_req_callback);
      channels[idx].ch_req_callback = callback == NULL
                                               ? NULL : vim_strsave(callback);
  }
  
  /*
!  * Invoke the "callback" on channel "idx".
!  */
!     static void
! invoke_callback(int idx, char_u *callback, typval_T *argv)
! {
!     typval_T  rettv;
!     int               dummy;
! 
!     argv[0].v_type = VAR_NUMBER;
!     argv[0].vval.v_number = idx;
! 
!     call_func(callback, (int)STRLEN(callback),
!                            &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
!     /* If an echo command was used the cursor needs to be put back where
!      * it belongs. */
!     setcursor();
!     cursor_on();
!     out_flush();
! }
! 
! /*
!  * Return the first buffer from the channel and remove it.
!  * The caller must free it.
!  * Returns NULL if there is nothing.
!  */
!     char_u *
! channel_get(int idx)
! {
!     readq_T *head = &channels[idx].ch_head;
!     readq_T *node;
!     char_u *p;
! 
!     if (head->next == head || head->next == NULL)
!       return NULL;
!     node = head->next;
!     /* dispose of the node but keep the buffer */
!     p = node->buffer;
!     head->next = node->next;
!     node->next->prev = node->prev;
!     vim_free(node);
!     return p;
! }
! 
! /*
!  * Returns the whole buffer contents concatenated.
!  */
!     static char_u *
! channel_get_all(int idx)
! {
!     /* Concatenate everything into one buffer.
!      * TODO: avoid multiple allocations. */
!     while (channel_collapse(idx) == OK)
!       ;
!     return channel_get(idx);
! }
! 
! /*
!  * Collapses the first and second buffer in the channel "idx".
!  * Returns FAIL if that is not possible.
   */
      int
! channel_collapse(int idx)
! {
!     readq_T *head = &channels[idx].ch_head;
!     readq_T *node = head->next;
!     char_u  *p;
! 
!     if (node == head || node == NULL || node->next == head)
!       return FAIL;
! 
!     p = alloc((unsigned)(STRLEN(node->buffer)
!                                          + STRLEN(node->next->buffer) + 1));
!     if (p == NULL)
!       return FAIL;        /* out of memory */
!     STRCPY(p, node->buffer);
!     STRCAT(p, node->next->buffer);
!     vim_free(node->next->buffer);
!     node->next->buffer = p;
! 
!     /* dispose of the node and buffer */
!     head->next = node->next;
!     node->next->prev = node->prev;
!     vim_free(node->buffer);
!     vim_free(node);
!     return OK;
! }
! 
! /*
!  * Use the read buffer of channel "ch_idx" and parse JSON messages that are
!  * complete.  The messages are added to the queue.
!  */
!     void
! channel_read_json(int ch_idx)
  {
      js_read_T reader;
      typval_T  listtv;
+     jsonq_T   *item;
+     jsonq_T   *head = &channels[ch_idx].ch_json_head;
  
!     if (channel_peek(ch_idx) == NULL)
!       return;
! 
!     /* TODO: make reader work properly */
!     /* reader.js_buf = channel_peek(ch_idx); */
!     reader.js_buf = channel_get_all(ch_idx);
      reader.js_eof = TRUE;
+     /* reader.js_eof = FALSE; */
      reader.js_used = 0;
!     /* reader.js_fill = channel_fill; */
!     reader.js_cookie = &ch_idx;
!     if (json_decode(&reader, &listtv) == OK)
!     {
!       item = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
!       if (item == NULL)
!           clear_tv(&listtv);
!       else
        {
!           item->value = alloc_tv();
!           if (item->value == NULL)
            {
!               vim_free(item);
!               clear_tv(&listtv);
!           }
!           else
!           {
!               *item->value = listtv;
!               item->prev = head->prev;
!               head->prev = item;
!               item->next = head;
!               item->prev->next = item;
            }
        }
      }
  }
  
  /*
!  * Remove "node" from the queue that it is in and free it.
!  * Caller should have freed or used node->value.
   */
      static void
! remove_json_node(jsonq_T *node)
  {
!     node->prev->next = node->next;
!     node->next->prev = node->prev;
!     vim_free(node);
! }
  
! /*
!  * Get a message from the JSON queue for channel "ch_idx".
!  * When "id" is positive it must match the first number in the list.
!  * When "id" is zero or negative jut get the first message.
!  * Return OK when found and return the value in "rettv".
!  * Return FAIL otherwise.
!  */
!     static int
! channel_get_json(int ch_idx, int id, typval_T **rettv)
! {
!     jsonq_T *head = &channels[ch_idx].ch_json_head;
!     jsonq_T *item = head->next;
  
!     while (item != head)
!     {
!       list_T      *l = item->value->vval.v_list;
!       typval_T    *tv = &l->lv_first->li_tv;
! 
!       if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
!             || id <= 0)
!       {
!           *rettv = item->value;
!           remove_json_node(item);
!           return OK;
!       }
!       item = item->next;
!     }
!     return FAIL;
  }
  
  /*
***************
*** 524,530 ****
      {
        exarg_T ea;
  
!       ea.forceit = *arg != NUL;
        ex_redraw(&ea);
        showruler(FALSE);
        setcursor();
--- 647,653 ----
      {
        exarg_T ea;
  
!       ea.forceit = arg != NULL && *arg != NUL;
        ex_redraw(&ea);
        showruler(FALSE);
        setcursor();
***************
*** 577,646 ****
      static void
  may_invoke_callback(int idx)
  {
!     char_u    *msg;
!     typval_T  typetv;
      typval_T  argv[3];
-     typval_T  arg3;
-     char_u    *cmd = NULL;
      int               seq_nr = -1;
!     int               ret = OK;
  
      if (channel_peek(idx) == NULL)
        return;
  
!     /* Concatenate everything into one buffer.
!      * TODO: only read what the callback will use.
!      * TODO: avoid multiple allocations. */
!     while (channel_collapse(idx) == OK)
!       ;
!     msg = channel_get(idx);
! 
!     if (channels[idx].ch_json_mode)
      {
!       ret = channel_decode_json(msg, &typetv, &argv[1], &arg3);
!       if (ret == OK)
        {
!           /* TODO: error if arg3 is set when it shouldn't? */
!           if (typetv.v_type == VAR_STRING)
!               cmd = typetv.vval.v_string;
!           else if (typetv.v_type == VAR_NUMBER)
!               seq_nr = typetv.vval.v_number;
        }
-     }
-     else
-     {
-       argv[1].v_type = VAR_STRING;
-       argv[1].vval.v_string = msg;
-     }
  
!     if (ret == OK)
!     {
!       if (cmd != NULL)
        {
!           channel_exe_cmd(idx, cmd, &argv[1], &arg3);
        }
!       else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
!       {
!           /* TODO: check the sequence number */
!           /* invoke the one-time callback */
!           invoke_callback(idx, channels[idx].ch_req_callback, argv);
!           channels[idx].ch_req_callback = NULL;
!       }
!       else if (channels[idx].ch_callback != NULL)
        {
!           /* invoke the channel callback */
!           invoke_callback(idx, channels[idx].ch_callback, argv);
        }
-       /* else: drop the message */
  
!       if (channels[idx].ch_json_mode)
        {
!           clear_tv(&typetv);
!           clear_tv(&argv[1]);
!           clear_tv(&arg3);
        }
      }
  
      vim_free(msg);
  }
  
--- 700,788 ----
      static void
  may_invoke_callback(int idx)
  {
!     char_u    *msg = NULL;
!     typval_T  *listtv = NULL;
!     list_T    *list;
!     typval_T  *typetv;
      typval_T  argv[3];
      int               seq_nr = -1;
!     int               json_mode = channels[idx].ch_json_mode;
  
      if (channel_peek(idx) == NULL)
        return;
+     if (channels[idx].ch_close_cb != NULL)
+       /* this channel is handled elsewhere (netbeans) */
+       return;
  
!     if (json_mode)
      {
!       /* Get any json message. Return if there isn't one. */
!       channel_read_json(idx);
!       if (channel_get_json(idx, -1, &listtv) == FAIL)
!           return;
!       if (listtv->v_type != VAR_LIST)
        {
!           /* TODO: give error */
!           clear_tv(listtv);
!           return;
        }
  
!       list = listtv->vval.v_list;
!       if (list->lv_len < 2)
        {
!           /* TODO: give error */
!           clear_tv(listtv);
!           return;
        }
! 
!       argv[1] = list->lv_first->li_next->li_tv;
!       typetv = &list->lv_first->li_tv;
!       if (typetv->v_type == VAR_STRING)
        {
!           typval_T    *arg3 = NULL;
!           char_u      *cmd = typetv->vval.v_string;
! 
!           /* ["cmd", arg] */
!           if (list->lv_len == 3)
!               arg3 = &list->lv_last->li_tv;
!           channel_exe_cmd(idx, cmd, &argv[1], arg3);
!           clear_tv(listtv);
!           return;
        }
  
!       if (typetv->v_type != VAR_NUMBER)
        {
!           /* TODO: give error */
!           clear_tv(listtv);
!           return;
        }
+       seq_nr = typetv->vval.v_number;
+     }
+     else
+     {
+       /* For a raw channel we don't know where the message ends, just get
+        * everything. */
+       msg = channel_get_all(idx);
+       argv[1].v_type = VAR_STRING;
+       argv[1].vval.v_string = msg;
+     }
+ 
+     if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
+     {
+       /* TODO: check the sequence number */
+       /* invoke the one-time callback */
+       invoke_callback(idx, channels[idx].ch_req_callback, argv);
+       channels[idx].ch_req_callback = NULL;
+     }
+     else if (channels[idx].ch_callback != NULL)
+     {
+       /* invoke the channel callback */
+       invoke_callback(idx, channels[idx].ch_callback, argv);
      }
+     /* else: drop the message TODO: give error */
  
+     if (listtv != NULL)
+       clear_tv(listtv);
      vim_free(msg);
  }
  
***************
*** 661,677 ****
      void
  channel_close(int idx)
  {
!     channel_T         *channel = &channels[idx];
  
      if (channel->ch_fd >= 0)
      {
        sock_close(channel->ch_fd);
        channel->ch_fd = -1;
  #ifdef FEAT_GUI
        channel_gui_unregister(idx);
  #endif
        vim_free(channel->ch_callback);
        channel->ch_callback = NULL;
      }
  }
  
--- 803,831 ----
      void
  channel_close(int idx)
  {
!     channel_T *channel = &channels[idx];
!     jsonq_T   *jhead;
  
      if (channel->ch_fd >= 0)
      {
        sock_close(channel->ch_fd);
        channel->ch_fd = -1;
+       channel->ch_close_cb = NULL;
  #ifdef FEAT_GUI
        channel_gui_unregister(idx);
  #endif
        vim_free(channel->ch_callback);
        channel->ch_callback = NULL;
+ 
+       while (channel_peek(idx) != NULL)
+           vim_free(channel_get(idx));
+ 
+       jhead = &channel->ch_json_head;
+       while (jhead->next != jhead)
+       {
+           clear_tv(jhead->next->value);
+           remove_json_node(jhead->next);
+       }
      }
  }
  
***************
*** 682,691 ****
      int
  channel_save(int idx, char_u *buf, int len)
  {
!     queue_T *node;
!     queue_T *head = &channels[idx].ch_head;
  
!     node = (queue_T *)alloc(sizeof(queue_T));
      if (node == NULL)
        return FAIL;        /* out of memory */
      node->buffer = alloc(len + 1);
--- 836,845 ----
      int
  channel_save(int idx, char_u *buf, int len)
  {
!     readq_T *node;
!     readq_T *head = &channels[idx].ch_head;
  
!     node = (readq_T *)alloc(sizeof(readq_T));
      if (node == NULL)
        return FAIL;        /* out of memory */
      node->buffer = alloc(len + 1);
***************
*** 697,708 ****
      mch_memmove(node->buffer, buf, (size_t)len);
      node->buffer[len] = NUL;
  
-     if (head->next == NULL)   /* initialize circular queue */
-     {
-       head->next = head;
-       head->prev = head;
-     }
- 
      /* insert node at tail of queue */
      node->next = head;
      node->prev = head->prev;
--- 851,856 ----
***************
*** 726,732 ****
      char_u *
  channel_peek(int idx)
  {
!     queue_T *head = &channels[idx].ch_head;
  
      if (head->next == head || head->next == NULL)
        return NULL;
--- 874,880 ----
      char_u *
  channel_peek(int idx)
  {
!     readq_T *head = &channels[idx].ch_head;
  
      if (head->next == head || head->next == NULL)
        return NULL;
***************
*** 734,801 ****
  }
  
  /*
-  * Return the first buffer from the channel and remove it.
-  * The caller must free it.
-  * Returns NULL if there is nothing.
-  */
-     char_u *
- channel_get(int idx)
- {
-     queue_T *head = &channels[idx].ch_head;
-     queue_T *node;
-     char_u *p;
- 
-     if (head->next == head || head->next == NULL)
-       return NULL;
-     node = head->next;
-     /* dispose of the node but keep the buffer */
-     p = node->buffer;
-     head->next = node->next;
-     node->next->prev = node->prev;
-     vim_free(node);
-     return p;
- }
- 
- /*
-  * Collapses the first and second buffer in the channel "idx".
-  * Returns FAIL if that is not possible.
-  */
-     int
- channel_collapse(int idx)
- {
-     queue_T *head = &channels[idx].ch_head;
-     queue_T *node = head->next;
-     char_u  *p;
- 
-     if (node == head || node == NULL || node->next == head)
-       return FAIL;
- 
-     p = alloc((unsigned)(STRLEN(node->buffer)
-                                          + STRLEN(node->next->buffer) + 1));
-     if (p == NULL)
-       return FAIL;        /* out of memory */
-     STRCPY(p, node->buffer);
-     STRCAT(p, node->next->buffer);
-     vim_free(node->next->buffer);
-     node->next->buffer = p;
- 
-     /* dispose of the node and buffer */
-     head->next = node->next;
-     node->next->prev = node->prev;
-     vim_free(node->buffer);
-     vim_free(node);
-     return OK;
- }
- 
- /*
   * Clear the read buffer on channel "idx".
   */
      void
  channel_clear(int idx)
  {
!     queue_T *head = &channels[idx].ch_head;
!     queue_T *node = head->next;
!     queue_T *next;
  
      while (node != NULL && node != head)
      {
--- 882,895 ----
  }
  
  /*
   * Clear the read buffer on channel "idx".
   */
      void
  channel_clear(int idx)
  {
!     readq_T *head = &channels[idx].ch_head;
!     readq_T *node = head->next;
!     readq_T *next;
  
      while (node != NULL && node != head)
      {
***************
*** 947,954 ****
  }
  
  /*
!  * Read from channel "idx".  Blocks until there is something to read or the
!  * timeout expires.
   * Returns what was read in allocated memory.
   * Returns NULL in case of error or timeout.
   */
--- 1041,1048 ----
  }
  
  /*
!  * Read from raw channel "idx".  Blocks until there is something to read or
!  * the timeout expires.
   * Returns what was read in allocated memory.
   * Returns NULL in case of error or timeout.
   */
***************
*** 964,975 ****
        channel_read(idx);
      }
  
!     /* Concatenate everything into one buffer.
!      * TODO: avoid multiple allocations. */
!     while (channel_collapse(idx) == OK)
!       ;
  
!     return channel_get(idx);
  }
  
  # if defined(WIN32) || defined(PROTO)
--- 1058,1089 ----
        channel_read(idx);
      }
  
!     return channel_get_all(idx);
! }
  
! /*
!  * Read one JSON message from channel "ch_idx" with ID "id" and store the
!  * result in "rettv".
!  * Blocks until the message is received.
!  */
!     int
! channel_read_json_block(int ch_idx, int id, typval_T **rettv)
! {
!     for (;;)
!     {
!       channel_read_json(ch_idx);
! 
!       /* search for messsage "id" */
!       if (channel_get_json(ch_idx, id, rettv) == OK)
!           return OK;
! 
!       /* Wait for up to 2 seconds.
!        * TODO: use timeout set on the channel. */
!       if (channel_wait(channels[ch_idx].ch_fd, 2000) == FAIL)
!           break;
!       channel_read(ch_idx);
!     }
!     return FAIL;
  }
  
  # if defined(WIN32) || defined(PROTO)
*** ../vim-7.4.1230/src/json.c  2016-01-31 20:24:09.966066885 +0100
--- src/json.c  2016-01-31 22:49:58.975253082 +0100
***************
*** 549,562 ****
  
  /*
   * Decode the JSON from "reader" and store the result in "res".
   */
!     void
  json_decode(js_read_T *reader, typval_T *res)
  {
      json_skip_white(reader);
      json_decode_item(reader, res);
      json_skip_white(reader);
      if (reader->js_buf[reader->js_used] != NUL)
!       EMSG(_(e_invarg));
  }
  #endif
--- 549,564 ----
  
  /*
   * Decode the JSON from "reader" and store the result in "res".
+  * Return OK or FAIL;
   */
!     int
  json_decode(js_read_T *reader, typval_T *res)
  {
      json_skip_white(reader);
      json_decode_item(reader, res);
      json_skip_white(reader);
      if (reader->js_buf[reader->js_used] != NUL)
!       return FAIL;
!     return OK;
  }
  #endif
*** ../vim-7.4.1230/src/proto/eval.pro  2016-01-28 22:36:15.052065044 +0100
--- src/proto/eval.pro  2016-01-31 23:02:33.143409845 +0100
***************
*** 101,106 ****
--- 101,107 ----
  char_u *v_exception(char_u *oldval);
  char_u *v_throwpoint(char_u *oldval);
  char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
+ typval_T *alloc_tv(void);
  void free_tv(typval_T *varp);
  void clear_tv(typval_T *varp);
  long get_tv_number_chk(typval_T *varp, int *denote);
*** ../vim-7.4.1230/src/proto/channel.pro       2016-01-31 20:24:09.970066843 
+0100
--- src/proto/channel.pro       2016-01-31 22:55:53.875563126 +0100
***************
*** 4,10 ****
  void channel_set_json_mode(int idx, int json_mode);
  void channel_set_callback(int idx, char_u *callback);
  void channel_set_req_callback(int idx, char_u *callback);
- int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T 
*tv3);
  int channel_is_open(int idx);
  void channel_close(int idx);
  int channel_save(int idx, char_u *buf, int len);
--- 4,9 ----
***************
*** 15,20 ****
--- 14,21 ----
  int channel_get_id(void);
  void channel_read(int idx);
  char_u *channel_read_block(int idx);
+ int channel_read_json_block(int ch_idx, int id, typval_T **rettv);
+ void channel_read_json(int ch_idx);
  int channel_socket2idx(sock_T fd);
  int channel_send(int idx, char_u *buf, char *fun);
  int channel_poll_setup(int nfd_in, void *fds_in);
*** ../vim-7.4.1230/src/proto/json.pro  2016-01-31 20:24:09.970066843 +0100
--- src/proto/json.pro  2016-01-31 22:56:25.115238152 +0100
***************
*** 1,5 ****
  /* json.c */
  char_u *json_encode(typval_T *val);
  char_u *json_encode_nr_expr(int nr, typval_T *val);
! void json_decode(js_read_T *reader, typval_T *res);
  /* vim: set ft=c : */
--- 1,5 ----
  /* json.c */
  char_u *json_encode(typval_T *val);
  char_u *json_encode_nr_expr(int nr, typval_T *val);
! int json_decode(js_read_T *reader, typval_T *res);
  /* vim: set ft=c : */
*** ../vim-7.4.1230/src/structs.h       2016-01-29 23:20:35.313308119 +0100
--- src/structs.h       2016-01-31 21:19:43.711391593 +0100
***************
*** 2693,2697 ****
      char_u    *js_end;        /* NUL in js_buf when js_eof is FALSE */
      int               js_used;        /* bytes used from js_buf */
      int               js_eof;         /* when TRUE js_buf is all there is */
!     FILE      *js_fd;         /* file descriptor to read more from */
  } js_read_T;
--- 2693,2698 ----
      char_u    *js_end;        /* NUL in js_buf when js_eof is FALSE */
      int               js_used;        /* bytes used from js_buf */
      int               js_eof;         /* when TRUE js_buf is all there is */
!     int               (*js_fill)(void *); /* function to fill the buffer */
!     void      *js_cookie;     /* passed to js_fill */
  } js_read_T;
*** ../vim-7.4.1230/src/version.c       2016-02-01 21:32:51.622375175 +0100
--- src/version.c       2016-02-01 21:35:02.833003291 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     1231,
  /**/

-- 
>From "know your smileys":
 |-(    Contact lenses, but has lost them

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui