To: vim_dev@googlegroups.com Subject: Patch 7.4.1369 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1369 Problem: Channels don't have a queue for stderr. Solution: Have a queue for each part of the channel. Files: src/channel.c, src/eval.c, src/structs.h, src/netbeans.c, src/gui_w32.c, src/proto/channel.pro *** ../vim-7.4.1368/src/channel.c 2016-02-19 23:23:08.756935131 +0100 --- src/channel.c 2016-02-20 18:13:21.640521000 +0100 *************** *** 274,280 **** channel_T * add_channel(void) { ! int which; channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T)); if (channel == NULL) --- 274,280 ---- channel_T * add_channel(void) { ! int part; channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T)); if (channel == NULL) *************** *** 284,308 **** ch_log(channel, "Created channel"); #ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which <= CHAN_IN; ++which) #else ! which = CHAN_SOCK; #endif { ! channel->ch_pfd[which].ch_fd = CHAN_FD_INVALID; #ifdef FEAT_GUI_X11 ! channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; #endif #ifdef FEAT_GUI_GTK ! channel->ch_pfd[which].ch_inputHandler = 0; #endif #ifdef FEAT_GUI_W32 ! channel->ch_pfd[which].ch_inputHandler = -1; #endif } - channel->ch_timeout = 2000; - if (first_channel != NULL) { first_channel->ch_prev = channel; --- 284,307 ---- ch_log(channel, "Created channel"); #ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part <= PART_IN; ++part) #else ! part = PART_SOCK; #endif { ! channel->ch_part[part].ch_fd = INVALID_FD; #ifdef FEAT_GUI_X11 ! channel->ch_part[part].ch_inputHandler = (XtInputId)NULL; #endif #ifdef FEAT_GUI_GTK ! channel->ch_part[part].ch_inputHandler = 0; #endif #ifdef FEAT_GUI_W32 ! channel->ch_part[part].ch_inputHandler = -1; #endif + channel->ch_part[part].ch_timeout = 2000; } if (first_channel != NULL) { first_channel->ch_prev = channel; *************** *** 349,365 **** static void channel_read_netbeans(int id) { ! channel_T *channel = channel_from_id(id); if (channel == NULL) ch_errorn(NULL, "Channel %d not found", id); else ! channel_read(channel, -1, "messageFromNetbeans"); } #endif /* * Read a command from netbeans. */ #ifdef FEAT_GUI_X11 static void --- 348,373 ---- static void channel_read_netbeans(int id) { ! channel_T *channel = channel_from_id(id); ! int part; if (channel == NULL) ch_errorn(NULL, "Channel %d not found", id); else ! { ! /* TODO: check stderr */ ! if (channel->CH_SOCK_FD != INVALID_FD) ! part = PART_SOCK; ! else ! part = PART_OUT; ! channel_read(channel, part, "messageFromNetbeans"); ! } } #endif /* * Read a command from netbeans. + * TODO: instead of channel ID use the FD. */ #ifdef FEAT_GUI_X11 static void *************** *** 382,396 **** #endif static void ! channel_gui_register_one(channel_T *channel, int which) { # ifdef FEAT_GUI_X11 /* Tell notifier we are interested in being called * when there is input on the editor connection socket. */ ! if (channel->ch_pfd[which].ch_inputHandler == (XtInputId)NULL) ! channel->ch_pfd[which].ch_inputHandler = XtAppAddInput( (XtAppContext)app_context, ! channel->ch_pfd[which].ch_fd, (XtPointer)(XtInputReadMask + XtInputExceptMask), messageFromNetbeans, (XtPointer)(long)channel->ch_id); --- 390,404 ---- #endif static void ! channel_gui_register_one(channel_T *channel, int part) { # ifdef FEAT_GUI_X11 /* Tell notifier we are interested in being called * when there is input on the editor connection socket. */ ! if (channel->ch_part[part].ch_inputHandler == (XtInputId)NULL) ! channel->ch_part[part].ch_inputHandler = XtAppAddInput( (XtAppContext)app_context, ! channel->ch_part[part].ch_fd, (XtPointer)(XtInputReadMask + XtInputExceptMask), messageFromNetbeans, (XtPointer)(long)channel->ch_id); *************** *** 398,406 **** # ifdef FEAT_GUI_GTK /* Tell gdk we are interested in being called when there * is input on the editor connection socket. */ ! if (channel->ch_pfd[which].ch_inputHandler == 0) ! channel->ch_pfd[which].ch_inputHandler = gdk_input_add( ! (gint)channel->ch_pfd[which].ch_fd, (GdkInputCondition) ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), messageFromNetbeans, --- 406,414 ---- # ifdef FEAT_GUI_GTK /* Tell gdk we are interested in being called when there * is input on the editor connection socket. */ ! if (channel->ch_part[part].ch_inputHandler == 0) ! channel->ch_part[part].ch_inputHandler = gdk_input_add( ! (gint)channel->ch_part[part].ch_fd, (GdkInputCondition) ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), messageFromNetbeans, *************** *** 409,417 **** # ifdef FEAT_GUI_W32 /* Tell Windows we are interested in receiving message when there * is input on the editor connection socket. */ ! if (channel->ch_pfd[which].ch_inputHandler == -1) ! channel->ch_pfd[which].ch_inputHandler = WSAAsyncSelect( ! channel->ch_pfd[which].ch_fd, s_hwnd, WM_NETBEANS, FD_READ); # endif # endif --- 417,425 ---- # ifdef FEAT_GUI_W32 /* Tell Windows we are interested in receiving message when there * is input on the editor connection socket. */ ! if (channel->ch_part[part].ch_inputHandler == -1) ! channel->ch_part[part].ch_inputHandler = WSAAsyncSelect( ! channel->ch_part[part].ch_fd, s_hwnd, WM_NETBEANS, FD_READ); # endif # endif *************** *** 424,436 **** if (!CH_HAS_GUI) return; ! if (channel->CH_SOCK != CHAN_FD_INVALID) ! channel_gui_register_one(channel, CHAN_SOCK); # ifdef CHANNEL_PIPES ! if (channel->CH_OUT != CHAN_FD_INVALID) ! channel_gui_register_one(channel, CHAN_OUT); ! if (channel->CH_ERR != CHAN_FD_INVALID) ! channel_gui_register_one(channel, CHAN_ERR); # endif } --- 432,444 ---- if (!CH_HAS_GUI) return; ! if (channel->CH_SOCK_FD != INVALID_FD) ! channel_gui_register_one(channel, PART_SOCK); # ifdef CHANNEL_PIPES ! if (channel->CH_OUT_FD != INVALID_FD) ! channel_gui_register_one(channel, PART_OUT); ! if (channel->CH_ERR_FD != INVALID_FD) ! channel_gui_register_one(channel, PART_ERR); # endif } *************** *** 450,482 **** static void channel_gui_unregister(channel_T *channel) { ! int which; #ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which < CHAN_IN; ++which) #else ! which = CHAN_SOCK; #endif { # ifdef FEAT_GUI_X11 ! if (channel->ch_pfd[which].ch_inputHandler != (XtInputId)NULL) { ! XtRemoveInput(channel->ch_pfd[which].ch_inputHandler); ! channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; } # else # ifdef FEAT_GUI_GTK ! if (channel->ch_pfd[which].ch_inputHandler != 0) { ! gdk_input_remove(channel->ch_pfd[which].ch_inputHandler); ! channel->ch_pfd[which].ch_inputHandler = 0; } # else # ifdef FEAT_GUI_W32 ! if (channel->ch_pfd[which].ch_inputHandler == 0) { ! WSAAsyncSelect(channel->ch_pfd[which].ch_fd, s_hwnd, 0, 0); ! channel->ch_pfd[which].ch_inputHandler = -1; } # endif # endif --- 458,490 ---- static void channel_gui_unregister(channel_T *channel) { ! int part; #ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) #else ! part = PART_SOCK; #endif { # ifdef FEAT_GUI_X11 ! if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL) { ! XtRemoveInput(channel->ch_part[part].ch_inputHandler); ! channel->ch_part[part].ch_inputHandler = (XtInputId)NULL; } # else # ifdef FEAT_GUI_GTK ! if (channel->ch_part[part].ch_inputHandler != 0) { ! gdk_input_remove(channel->ch_part[part].ch_inputHandler); ! channel->ch_part[part].ch_inputHandler = 0; } # else # ifdef FEAT_GUI_W32 ! if (channel->ch_part[part].ch_inputHandler == 0) { ! WSAAsyncSelect(channel->ch_part[part].ch_fd, s_hwnd, 0, 0); ! channel->ch_part[part].ch_inputHandler = -1; } # endif # endif *************** *** 721,727 **** #endif } ! channel->CH_SOCK = (sock_T)sd; channel->ch_close_cb = close_cb; #ifdef FEAT_GUI --- 729,735 ---- #endif } ! channel->CH_SOCK_FD = (sock_T)sd; channel->ch_close_cb = close_cb; #ifdef FEAT_GUI *************** *** 735,743 **** void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err) { ! channel->CH_IN = in; ! channel->CH_OUT = out; ! channel->CH_ERR = err; } #endif --- 743,751 ---- void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err) { ! channel->CH_IN_FD = in; ! channel->CH_OUT_FD = out; ! channel->CH_ERR_FD = err; } #endif *************** *** 753,762 **** void channel_set_options(channel_T *channel, jobopt_T *options) { if (options->jo_set & JO_MODE) ! channel->ch_mode = options->jo_mode; if (options->jo_set & JO_TIMEOUT) ! channel->ch_timeout = options->jo_timeout; if (options->jo_set & JO_CALLBACK) { --- 761,774 ---- void channel_set_options(channel_T *channel, jobopt_T *options) { + int part; + if (options->jo_set & JO_MODE) ! for (part = PART_SOCK; part <= PART_IN; ++part) ! channel->ch_part[part].ch_mode = options->jo_mode; if (options->jo_set & JO_TIMEOUT) ! for (part = PART_SOCK; part <= PART_IN; ++part) ! channel->ch_part[part].ch_timeout = options->jo_timeout; if (options->jo_set & JO_CALLBACK) { *************** *** 769,780 **** } /* ! * Set the callback for channel "channel" for the response with "id". */ void ! channel_set_req_callback(channel_T *channel, char_u *callback, int id) { ! cbq_T *head = &channel->ch_cb_head; cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T)); if (item != NULL) --- 781,796 ---- } /* ! * Set the callback for "channel"/"part" for the response with "id". */ void ! channel_set_req_callback( ! channel_T *channel, ! int part, ! char_u *callback, ! int id) { ! cbq_T *head = &channel->ch_part[part].ch_cb_head; cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T)); if (item != NULL) *************** *** 813,826 **** } /* ! * 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(channel_T *channel) { ! readq_T *head = &channel->ch_head; readq_T *node = head->rq_next; char_u *p; --- 829,842 ---- } /* ! * Return the first buffer from channel "channel"/"part" and remove it. * The caller must free it. * Returns NULL if there is nothing. */ char_u * ! channel_get(channel_T *channel, int part) { ! readq_T *head = &channel->ch_part[part].ch_head; readq_T *node = head->rq_next; char_u *p; *************** *** 838,863 **** } /* ! * Returns the whole buffer contents concatenated. */ static char_u * ! channel_get_all(channel_T *channel) { /* Concatenate everything into one buffer. * TODO: avoid multiple allocations. */ ! while (channel_collapse(channel) == OK) ; ! return channel_get(channel); } /* ! * Collapses the first and second buffer in the channel "channel". * Returns FAIL if that is not possible. */ int ! channel_collapse(channel_T *channel) { ! readq_T *head = &channel->ch_head; readq_T *node = head->rq_next; char_u *p; --- 854,879 ---- } /* ! * Returns the whole buffer contents concatenated for "channel"/"part". */ static char_u * ! channel_get_all(channel_T *channel, int part) { /* Concatenate everything into one buffer. * TODO: avoid multiple allocations. */ ! while (channel_collapse(channel, part) == OK) ; ! return channel_get(channel, part); } /* ! * Collapses the first and second buffer for "channel"/"part". * Returns FAIL if that is not possible. */ int ! channel_collapse(channel_T *channel, int part) { ! readq_T *head = &channel->ch_part[part].ch_head; readq_T *node = head->rq_next; char_u *p; *************** *** 882,912 **** } /* ! * Use the read buffer of channel "channel" and parse a JSON messages that is * complete. The messages are added to the queue. * Return TRUE if there is more to read. */ static int ! channel_parse_json(channel_T *channel) { js_read_T reader; typval_T listtv; jsonq_T *item; ! jsonq_T *head = &channel->ch_json_head; int ret; ! if (channel_peek(channel) == NULL) return FALSE; /* TODO: make reader work properly */ ! /* reader.js_buf = channel_peek(channel); */ ! reader.js_buf = channel_get_all(channel); reader.js_used = 0; reader.js_fill = NULL; /* reader.js_fill = channel_fill; */ reader.js_cookie = channel; ret = json_decode(&reader, &listtv, ! channel->ch_mode == MODE_JS ? JSON_JS : 0); if (ret == OK) { /* Only accept the response when it is a list with at least two --- 898,985 ---- } /* ! * Store "buf[len]" on "channel"/"part". ! * Returns OK or FAIL. ! */ ! static int ! channel_save(channel_T *channel, int part, char_u *buf, int len) ! { ! readq_T *node; ! readq_T *head = &channel->ch_part[part].ch_head; ! char_u *p; ! int i; ! ! node = (readq_T *)alloc(sizeof(readq_T)); ! if (node == NULL) ! return FAIL; /* out of memory */ ! node->rq_buffer = alloc(len + 1); ! if (node->rq_buffer == NULL) ! { ! vim_free(node); ! return FAIL; /* out of memory */ ! } ! ! if (channel->ch_part[part].ch_mode == MODE_NL) ! { ! /* Drop any CR before a NL. */ ! p = node->rq_buffer; ! for (i = 0; i < len; ++i) ! if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL) ! *p++ = buf[i]; ! *p = NUL; ! } ! else ! { ! mch_memmove(node->rq_buffer, buf, len); ! node->rq_buffer[len] = NUL; ! } ! ! /* append node to the tail of the queue */ ! node->rq_next = NULL; ! node->rq_prev = head->rq_prev; ! if (head->rq_prev == NULL) ! head->rq_next = node; ! else ! head->rq_prev->rq_next = node; ! head->rq_prev = node; ! ! if (log_fd != NULL) ! { ! ch_log_lead("RECV ", channel); ! fprintf(log_fd, "'"); ! if (fwrite(buf, len, 1, log_fd) != 1) ! return FAIL; ! fprintf(log_fd, "'\n"); ! } ! return OK; ! } ! ! /* ! * Use the read buffer of "channel"/"part" and parse a JSON messages that is * complete. The messages are added to the queue. * Return TRUE if there is more to read. */ static int ! channel_parse_json(channel_T *channel, int part) { js_read_T reader; typval_T listtv; jsonq_T *item; ! jsonq_T *head = &channel->ch_part[part].ch_json_head; int ret; ! if (channel_peek(channel, part) == NULL) return FALSE; /* TODO: make reader work properly */ ! /* reader.js_buf = channel_peek(channel, part); */ ! reader.js_buf = channel_get_all(channel, part); reader.js_used = 0; reader.js_fill = NULL; /* reader.js_fill = channel_fill; */ reader.js_cookie = channel; ret = json_decode(&reader, &listtv, ! channel->ch_part[part].ch_mode == MODE_JS ? JSON_JS : 0); if (ret == OK) { /* Only accept the response when it is a list with at least two *************** *** 948,954 **** * TODO: insert in front */ if (reader.js_buf[reader.js_used] != NUL) { ! channel_save(channel, reader.js_buf + reader.js_used, (int)(reader.js_end - reader.js_buf) - reader.js_used); ret = TRUE; } --- 1021,1027 ---- * TODO: insert in front */ if (reader.js_buf[reader.js_used] != NUL) { ! channel_save(channel, part, reader.js_buf + reader.js_used, (int)(reader.js_end - reader.js_buf) - reader.js_used); ret = TRUE; } *************** *** 1002,1010 **** * Return FAIL otherwise. */ static int ! channel_get_json(channel_T *channel, int id, typval_T **rettv) { ! jsonq_T *head = &channel->ch_json_head; jsonq_T *item = head->jq_next; while (item != NULL) --- 1075,1083 ---- * Return FAIL otherwise. */ static int ! channel_get_json(channel_T *channel, int part, int id, typval_T **rettv) { ! jsonq_T *head = &channel->ch_part[part].ch_json_head; jsonq_T *item = head->jq_next; while (item != NULL) *************** *** 1014,1021 **** if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) || (id <= 0 && (tv->v_type != VAR_NUMBER ! || tv->vval.v_number == 0 ! || tv->vval.v_number != channel->ch_block_id))) { *rettv = item->jq_value; remove_json_node(head, item); --- 1087,1094 ---- if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) || (id <= 0 && (tv->v_type != VAR_NUMBER ! || tv->vval.v_number == 0 ! || tv->vval.v_number != channel->ch_part[part].ch_block_id))) { *rettv = item->jq_value; remove_json_node(head, item); *************** *** 1027,1038 **** } /* ! * Execute a command received over channel "channel". * "cmd" is the command string, "arg2" the second argument. * "arg3" is the third argument, NULL if missing. */ static void ! channel_exe_cmd(channel_T *channel, char_u *cmd, typval_T *arg2, typval_T *arg3) { char_u *arg; --- 1100,1116 ---- } /* ! * Execute a command received over "channel"/"part" * "cmd" is the command string, "arg2" the second argument. * "arg3" is the third argument, NULL if missing. */ static void ! channel_exe_cmd( ! channel_T *channel, ! int part, ! char_u *cmd, ! typval_T *arg2, ! typval_T *arg3) { char_u *arg; *************** *** 1090,1096 **** typval_T *tv; typval_T err_tv; char_u *json = NULL; ! int options = channel->ch_mode == MODE_JS ? JSON_JS : 0; /* Don't pollute the display with errors. */ ++emsg_skip; --- 1168,1175 ---- typval_T *tv; typval_T err_tv; char_u *json = NULL; ! int options = channel->ch_part[part].ch_mode == MODE_JS ! ? JSON_JS : 0; /* Don't pollute the display with errors. */ ++emsg_skip; *************** *** 1114,1120 **** } if (json != NULL) { ! channel_send(channel, json, "eval"); vim_free(json); } } --- 1193,1199 ---- } if (json != NULL) { ! channel_send(channel, part, json, "eval"); vim_free(json); } } *************** *** 1128,1139 **** } /* ! * Invoke a callback for channel "channel" if needed. ! * TODO: add "which" argument, read stderr. * Return TRUE when a message was handled, there might be another one. */ static int ! may_invoke_callback(channel_T *channel) { char_u *msg = NULL; typval_T *listtv = NULL; --- 1207,1217 ---- } /* ! * Invoke a callback for "channel"/"part" if needed. * Return TRUE when a message was handled, there might be another one. */ static int ! may_invoke_callback(channel_T *channel, int part) { char_u *msg = NULL; typval_T *listtv = NULL; *************** *** 1141,1160 **** typval_T *typetv; typval_T argv[3]; int seq_nr = -1; ! ch_mode_T ch_mode = channel->ch_mode; if (channel->ch_close_cb != NULL) /* this channel is handled elsewhere (netbeans) */ return FALSE; if (ch_mode == MODE_JSON || ch_mode == MODE_JS) { /* Get any json message in the queue. */ ! if (channel_get_json(channel, -1, &listtv) == FAIL) { /* Parse readahead, return when there is still no message. */ ! channel_parse_json(channel); ! if (channel_get_json(channel, -1, &listtv) == FAIL) return FALSE; } --- 1219,1244 ---- typval_T *typetv; typval_T argv[3]; int seq_nr = -1; ! ch_mode_T ch_mode = channel->ch_part[part].ch_mode; ! char_u *callback = NULL; if (channel->ch_close_cb != NULL) /* this channel is handled elsewhere (netbeans) */ return FALSE; + if (channel->ch_part[part].ch_callback != NULL) + callback = channel->ch_part[part].ch_callback; + else + callback = channel->ch_callback; + if (ch_mode == MODE_JSON || ch_mode == MODE_JS) { /* Get any json message in the queue. */ ! if (channel_get_json(channel, part, -1, &listtv) == FAIL) { /* Parse readahead, return when there is still no message. */ ! channel_parse_json(channel, part); ! if (channel_get_json(channel, part, -1, &listtv) == FAIL) return FALSE; } *************** *** 1170,1176 **** if (list->lv_len == 3) arg3 = &list->lv_last->li_tv; ch_logs(channel, "Executing %s command", (char *)cmd); ! channel_exe_cmd(channel, cmd, &argv[1], arg3); free_tv(listtv); return TRUE; } --- 1254,1260 ---- if (list->lv_len == 3) arg3 = &list->lv_last->li_tv; ch_logs(channel, "Executing %s command", (char *)cmd); ! channel_exe_cmd(channel, part, cmd, &argv[1], arg3); free_tv(listtv); return TRUE; } *************** *** 1184,1190 **** } seq_nr = typetv->vval.v_number; } ! else if (channel_peek(channel) == NULL) { /* nothing to read on RAW or NL channel */ return FALSE; --- 1268,1274 ---- } seq_nr = typetv->vval.v_number; } ! else if (channel_peek(channel, part) == NULL) { /* nothing to read on RAW or NL channel */ return FALSE; *************** *** 1192,1200 **** else { /* If there is no callback drop the message. */ ! if (channel->ch_callback == NULL) { ! while ((msg = channel_get(channel)) != NULL) vim_free(msg); return FALSE; } --- 1276,1284 ---- else { /* If there is no callback drop the message. */ ! if (callback == NULL) { ! while ((msg = channel_get(channel, part)) != NULL) vim_free(msg); return FALSE; } *************** *** 1208,1223 **** * not try to concatenate the first and the second buffer. */ while (TRUE) { ! buf = channel_peek(channel); nl = vim_strchr(buf, NL); if (nl != NULL) break; ! if (channel_collapse(channel) == FAIL) return FALSE; /* incomplete message */ } if (nl[1] == NUL) /* get the whole buffer */ ! msg = channel_get(channel); else { /* Copy the message into allocated memory and remove it from --- 1292,1307 ---- * 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) == FAIL) return FALSE; /* incomplete message */ } if (nl[1] == NUL) /* get the whole buffer */ ! msg = channel_get(channel, part); else { /* Copy the message into allocated memory and remove it from *************** *** 1229,1235 **** else /* For a raw channel we don't know where the message ends, just * get everything we have. */ ! msg = channel_get_all(channel); argv[1].v_type = VAR_STRING; argv[1].vval.v_string = msg; --- 1313,1319 ---- else /* For a raw channel we don't know where the message ends, just * get everything we have. */ ! msg = channel_get_all(channel, part); argv[1].v_type = VAR_STRING; argv[1].vval.v_string = msg; *************** *** 1237,1243 **** if (seq_nr > 0) { ! cbq_T *head = &channel->ch_cb_head; cbq_T *item = head->cq_next; int done = FALSE; --- 1321,1327 ---- if (seq_nr > 0) { ! cbq_T *head = &channel->ch_part[part].ch_cb_head; cbq_T *item = head->cq_next; int done = FALSE; *************** *** 1261,1271 **** if (!done) ch_log(channel, "Dropping message without callback"); } ! else if (channel->ch_callback != NULL) { /* invoke the channel callback */ ch_log(channel, "Invoking channel callback"); ! invoke_callback(channel, channel->ch_callback, argv); } else ch_log(channel, "Dropping message"); --- 1345,1355 ---- if (!done) ch_log(channel, "Dropping message without callback"); } ! else if (callback != NULL) { /* invoke the channel callback */ ch_log(channel, "Invoking channel callback"); ! invoke_callback(channel, callback, argv); } else ch_log(channel, "Dropping message"); *************** *** 1284,1292 **** int channel_can_write_to(channel_T *channel) { ! return channel != NULL && (channel->CH_SOCK != CHAN_FD_INVALID #ifdef CHANNEL_PIPES ! || channel->CH_IN != CHAN_FD_INVALID #endif ); } --- 1368,1376 ---- int channel_can_write_to(channel_T *channel) { ! return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD #ifdef CHANNEL_PIPES ! || channel->CH_IN_FD != INVALID_FD #endif ); } *************** *** 1298,1308 **** int channel_is_open(channel_T *channel) { ! return channel != NULL && (channel->CH_SOCK != CHAN_FD_INVALID #ifdef CHANNEL_PIPES ! || channel->CH_IN != CHAN_FD_INVALID ! || channel->CH_OUT != CHAN_FD_INVALID ! || channel->CH_ERR != CHAN_FD_INVALID #endif ); } --- 1382,1392 ---- int channel_is_open(channel_T *channel) { ! return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD #ifdef CHANNEL_PIPES ! || channel->CH_IN_FD != INVALID_FD ! || channel->CH_OUT_FD != INVALID_FD ! || channel->CH_ERR_FD != INVALID_FD #endif ); } *************** *** 1333,1358 **** channel_gui_unregister(channel); #endif ! if (channel->CH_SOCK != CHAN_FD_INVALID) { ! sock_close(channel->CH_SOCK); ! channel->CH_SOCK = CHAN_FD_INVALID; } #if defined(CHANNEL_PIPES) ! if (channel->CH_IN != CHAN_FD_INVALID) { ! fd_close(channel->CH_IN); ! channel->CH_IN = CHAN_FD_INVALID; } ! if (channel->CH_OUT != CHAN_FD_INVALID) { ! fd_close(channel->CH_OUT); ! channel->CH_OUT = CHAN_FD_INVALID; } ! if (channel->CH_ERR != CHAN_FD_INVALID) { ! fd_close(channel->CH_ERR); ! channel->CH_ERR = CHAN_FD_INVALID; } #endif --- 1417,1442 ---- channel_gui_unregister(channel); #endif ! if (channel->CH_SOCK_FD != INVALID_FD) { ! sock_close(channel->CH_SOCK_FD); ! channel->CH_SOCK_FD = INVALID_FD; } #if defined(CHANNEL_PIPES) ! if (channel->CH_IN_FD != INVALID_FD) { ! fd_close(channel->CH_IN_FD); ! channel->CH_IN_FD = INVALID_FD; } ! if (channel->CH_OUT_FD != INVALID_FD) { ! fd_close(channel->CH_OUT_FD); ! channel->CH_OUT_FD = INVALID_FD; } ! if (channel->CH_ERR_FD != INVALID_FD) { ! fd_close(channel->CH_ERR_FD); ! channel->CH_ERR_FD = INVALID_FD; } #endif *************** *** 1361,1430 **** } /* ! * Store "buf[len]" on channel "channel". ! * Returns OK or FAIL. ! */ ! int ! channel_save(channel_T *channel, char_u *buf, int len) ! { ! readq_T *node; ! readq_T *head = &channel->ch_head; ! char_u *p; ! int i; ! ! node = (readq_T *)alloc(sizeof(readq_T)); ! if (node == NULL) ! return FAIL; /* out of memory */ ! node->rq_buffer = alloc(len + 1); ! if (node->rq_buffer == NULL) ! { ! vim_free(node); ! return FAIL; /* out of memory */ ! } ! ! if (channel->ch_mode == MODE_NL) ! { ! /* Drop any CR before a NL. */ ! p = node->rq_buffer; ! for (i = 0; i < len; ++i) ! if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL) ! *p++ = buf[i]; ! *p = NUL; ! } ! else ! { ! mch_memmove(node->rq_buffer, buf, len); ! node->rq_buffer[len] = NUL; ! } ! ! /* append node to the tail of the queue */ ! node->rq_next = NULL; ! node->rq_prev = head->rq_prev; ! if (head->rq_prev == NULL) ! head->rq_next = node; ! else ! head->rq_prev->rq_next = node; ! head->rq_prev = node; ! ! if (log_fd != NULL) ! { ! ch_log_lead("RECV ", channel); ! fprintf(log_fd, "'"); ! if (fwrite(buf, len, 1, log_fd) != 1) ! return FAIL; ! fprintf(log_fd, "'\n"); ! } ! return OK; ! } ! ! /* ! * Return the first buffer from the channel without removing it. * Returns NULL if there is nothing. */ char_u * ! channel_peek(channel_T *channel) { ! readq_T *head = &channel->ch_head; if (head->rq_next == NULL) return NULL; --- 1445,1457 ---- } /* ! * 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; *************** *** 1432,1447 **** } /* ! * Clear the read buffer on channel "channel". */ ! void ! channel_clear(channel_T *channel) { ! jsonq_T *json_head = &channel->ch_json_head; ! cbq_T *cb_head = &channel->ch_cb_head; ! while (channel_peek(channel) != NULL) ! vim_free(channel_get(channel)); while (cb_head->cq_next != NULL) { --- 1459,1474 ---- } /* ! * Clear the read buffer on "channel"/"part". */ ! static void ! channel_clear_one(channel_T *channel, int part) { ! jsonq_T *json_head = &channel->ch_part[part].ch_json_head; ! cbq_T *cb_head = &channel->ch_part[part].ch_cb_head; ! while (channel_peek(channel, part) != NULL) ! vim_free(channel_get(channel, part)); while (cb_head->cq_next != NULL) { *************** *** 1458,1463 **** --- 1485,1505 ---- remove_json_node(json_head, json_head->jq_next); } + vim_free(channel->ch_part[part].ch_callback); + channel->ch_part[part].ch_callback = NULL; + } + + /* + * Clear all the read buffers on "channel". + */ + void + channel_clear(channel_T *channel) + { + channel_clear_one(channel, PART_SOCK); + #ifdef CHANNEL_PIPES + channel_clear_one(channel, PART_OUT); + channel_clear_one(channel, PART_ERR); + #endif vim_free(channel->ch_callback); channel->ch_callback = NULL; } *************** *** 1492,1498 **** ch_logn(channel, "Waiting for up to %d msec", timeout); # ifdef WIN32 ! if (fd != channel->CH_SOCK) { DWORD nread; int diff; --- 1534,1540 ---- ch_logn(channel, "Waiting for up to %d msec", timeout); # ifdef WIN32 ! if (fd != channel->CH_SOCK_FD) { DWORD nread; int diff; *************** *** 1567,1596 **** } /* - * Get the file descriptor to read from, either the socket or stdout. - * TODO: should have a way to read stderr. - */ - static sock_T - get_read_fd(channel_T *channel) - { - if (channel->CH_SOCK != CHAN_FD_INVALID) - return channel->CH_SOCK; - #if defined(CHANNEL_PIPES) - if (channel->CH_OUT != CHAN_FD_INVALID) - return channel->CH_OUT; - #endif - ch_error(channel, "channel_read() called while socket is closed"); - return CHAN_FD_INVALID; - } - - /* * Read from channel "channel" for as long as there is something to read. ! * "which" is CHAN_SOCK, CHAN_OUT or CHAN_ERR. When -1 use CHAN_SOCK or ! * CHAN_OUT, the one that is open. * The data is put in the read queue. */ void ! channel_read(channel_T *channel, int which, char *func) { static char_u *buf = NULL; int len = 0; --- 1609,1620 ---- } /* * Read from channel "channel" for as long as there is something to read. ! * "part" is PART_SOCK, PART_OUT or PART_ERR. * The data is put in the read queue. */ void ! channel_read(channel_T *channel, int part, char *func) { static char_u *buf = NULL; int len = 0; *************** *** 1598,1610 **** sock_T fd; int use_socket = FALSE; ! if (which < 0) ! fd = get_read_fd(channel); ! else ! fd = channel->ch_pfd[which].ch_fd; ! if (fd == CHAN_FD_INVALID) return; ! use_socket = fd == channel->CH_SOCK; /* Allocate a buffer to read into. */ if (buf == NULL) --- 1622,1634 ---- sock_T fd; int use_socket = FALSE; ! fd = channel->ch_part[part].ch_fd; ! if (fd == INVALID_FD) ! { ! ch_error(channel, "channel_read() called while socket is closed"); return; ! } ! use_socket = fd == channel->CH_SOCK_FD; /* Allocate a buffer to read into. */ if (buf == NULL) *************** *** 1629,1635 **** break; /* error or nothing more to read */ /* Store the read message in the queue. */ ! channel_save(channel, buf, len); readlen += len; if (len < MAXMSGSIZE) break; /* did read everything that's available */ --- 1653,1659 ---- break; /* error or nothing more to read */ /* Store the read message in the queue. */ ! channel_save(channel, part, buf, len); readlen += len; if (len < MAXMSGSIZE) break; /* did read everything that's available */ *************** *** 1660,1666 **** * -> channel_read() */ ch_errors(channel, "%s(): Cannot read", func); ! channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); /* TODO: When reading from stdout is not possible, should we try to * keep stdin and stderr open? Probably not, assume the other side --- 1684,1691 ---- * -> channel_read() */ ch_errors(channel, "%s(): Cannot read", func); ! channel_save(channel, part, ! (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); /* TODO: When reading from stdout is not possible, should we try to * keep stdin and stderr open? Probably not, assume the other side *************** *** 1684,1726 **** } /* ! * Read from RAW or NL channel "channel". Blocks until there is something to * read or the timeout expires. - * TODO: add "which" argument and read from stderr. * Returns what was read in allocated memory. * Returns NULL in case of error or timeout. */ char_u * ! channel_read_block(channel_T *channel) { char_u *buf; char_u *msg; ! ch_mode_T mode = channel->ch_mode; ! sock_T fd = get_read_fd(channel); char_u *nl; ch_logsn(channel, "Blocking %s read, timeout: %d msec", ! mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout); while (TRUE) { ! buf = channel_peek(channel); if (buf != NULL && (mode == MODE_RAW || (mode == MODE_NL && vim_strchr(buf, NL) != NULL))) break; ! if (buf != NULL && channel_collapse(channel) == OK) continue; /* Wait for up to the channel timeout. */ ! if (fd == CHAN_FD_INVALID ! || channel_wait(channel, fd, channel->ch_timeout) == FAIL) return NULL; ! channel_read(channel, -1, "channel_read_block"); } if (mode == MODE_RAW) { ! msg = channel_get_all(channel); } else { --- 1709,1751 ---- } /* ! * Read from RAW or NL "channel"/"part". 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. */ char_u * ! channel_read_block(channel_T *channel, int part) { char_u *buf; char_u *msg; ! ch_mode_T mode = channel->ch_part[part].ch_mode; ! int timeout = channel->ch_part[part].ch_timeout; ! 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) == OK) continue; /* Wait for up to the channel timeout. */ ! if (fd == INVALID_FD ! || channel_wait(channel, fd, timeout) == FAIL) return NULL; ! channel_read(channel, part, "channel_read_block"); } if (mode == MODE_RAW) { ! msg = channel_get_all(channel, part); } else { *************** *** 1728,1734 **** if (nl[1] == NUL) { /* get the whole buffer */ ! msg = channel_get(channel); *nl = NUL; } else --- 1753,1759 ---- if (nl[1] == NUL) { /* get the whole buffer */ ! msg = channel_get(channel, part); *nl = NUL; } else *************** *** 1745,1770 **** } /* ! * Read one JSON message with ID "id" from channel "channel" and store the * result in "rettv". * Blocks until the message is received or the timeout is reached. */ int ! channel_read_json_block(channel_T *channel, int id, typval_T **rettv) { int more; sock_T fd; ch_log(channel, "Reading JSON"); ! channel->ch_block_id = id; for (;;) { ! more = channel_parse_json(channel); /* search for messsage "id" */ ! if (channel_get_json(channel, id, rettv) == OK) { ! channel->ch_block_id = 0; return OK; } --- 1770,1795 ---- } /* ! * Read one JSON message with ID "id" from "channel"/"part" and store the * result in "rettv". * Blocks until the message is received or the timeout is reached. */ int ! channel_read_json_block(channel_T *channel, int part, int id, typval_T **rettv) { int more; sock_T fd; ch_log(channel, "Reading JSON"); ! channel->ch_part[part].ch_block_id = id; for (;;) { ! more = channel_parse_json(channel, part); /* search for messsage "id" */ ! if (channel_get_json(channel, part, id, rettv) == OK) { ! channel->ch_part[part].ch_block_id = 0; return OK; } *************** *** 1776,1815 **** continue; /* Wait for up to the channel timeout. */ ! fd = get_read_fd(channel); ! if (fd == CHAN_FD_INVALID ! || channel_wait(channel, fd, channel->ch_timeout) == FAIL) break; ! channel_read(channel, -1, "channel_read_json_block"); } } ! channel->ch_block_id = 0; return FAIL; } # if defined(WIN32) || defined(PROTO) /* ! * Lookup the channel from the socket. Set "which" to the fd index. * Returns NULL when the socket isn't found. */ channel_T * ! channel_fd2channel(sock_T fd, int *whichp) { channel_T *channel; ! int i; ! if (fd != CHAN_FD_INVALID) for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (i = CHAN_SOCK; i < CHAN_IN; ++i) # else ! i = CHAN_SOCK; # endif ! if (channel->ch_pfd[i].ch_fd == fd) { ! *whichp = i; return channel; } } --- 1801,1840 ---- continue; /* Wait for up to the channel timeout. */ ! fd = channel->ch_part[part].ch_fd; ! if (fd == INVALID_FD || channel_wait(channel, fd, ! channel->ch_part[part].ch_timeout) == FAIL) break; ! channel_read(channel, part, "channel_read_json_block"); } } ! channel->ch_part[part].ch_block_id = 0; return FAIL; } # if defined(WIN32) || defined(PROTO) /* ! * Lookup the channel from the socket. Set "part" to the fd index. * Returns NULL when the socket isn't found. */ channel_T * ! channel_fd2channel(sock_T fd, int *part) { channel_T *channel; ! int part; ! if (fd != INVALID_FD) for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) # else ! part = PART_SOCK; # endif ! if (channel->ch_part[part].ch_fd == fd) { ! *part = part; return channel; } } *************** *** 1820,1826 **** channel_handle_events(void) { channel_T *channel; ! int which; static int loop = 0; /* Skip heavily polling */ --- 1845,1851 ---- channel_handle_events(void) { channel_T *channel; ! int part; static int loop = 0; /* Skip heavily polling */ *************** *** 1831,1874 **** { # ifdef FEAT_GUI_W32 /* only check the pipes */ ! for (which = CHAN_OUT; which < CHAN_ERR; ++which) # else # ifdef CHANNEL_PIPES /* check the socket and pipes */ ! for (which = CHAN_SOCK; which < CHAN_ERR; ++which) # else /* only check the socket */ ! which = CHAN_SOCK; # endif # endif ! channel_read(channel, which, "channel_handle_events"); } } # endif /* ! * Write "buf" (NUL terminated string) to channel "channel". * When "fun" is not NULL an error message might be given. * Return FAIL or OK. */ int ! channel_send(channel_T *channel, char_u *buf, char *fun) { int len = (int)STRLEN(buf); int res; ! sock_T fd = CHAN_FD_INVALID; ! int use_socket = FALSE; ! if (channel->CH_SOCK != CHAN_FD_INVALID) ! { ! fd = channel->CH_SOCK; ! use_socket = TRUE; ! } ! #if defined(CHANNEL_PIPES) ! else if (channel->CH_IN != CHAN_FD_INVALID) ! fd = channel->CH_IN; ! #endif ! if (fd == CHAN_FD_INVALID) { if (!channel->ch_error && fun != NULL) { --- 1856,1890 ---- { # ifdef FEAT_GUI_W32 /* only check the pipes */ ! for (part = PART_OUT; part <= PART_ERR; ++part) # else # ifdef CHANNEL_PIPES /* check the socket and pipes */ ! for (part = PART_SOCK; part <= PART_ERR; ++part) # else /* only check the socket */ ! part = PART_SOCK; # endif # endif ! channel_read(channel, part, "channel_handle_events"); } } # endif /* ! * Write "buf" (NUL terminated string) to "channel"/"part". * When "fun" is not NULL an error message might be given. * Return FAIL or OK. */ int ! channel_send(channel_T *channel, int part, char_u *buf, char *fun) { int len = (int)STRLEN(buf); int res; ! sock_T fd; ! fd = channel->ch_part[part].ch_fd; ! if (fd == INVALID_FD) { if (!channel->ch_error && fun != NULL) { *************** *** 1888,1894 **** fflush(log_fd); } ! if (use_socket) res = sock_write(fd, (char *)buf, len); else res = fd_write(fd, (char *)buf, len); --- 1904,1910 ---- fflush(log_fd); } ! if (part == PART_SOCK) res = sock_write(fd, (char *)buf, len); else res = fd_write(fd, (char *)buf, len); *************** *** 1919,1943 **** int nfd = nfd_in; channel_T *channel; struct pollfd *fds = fds_in; ! int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else ! which = CHAN_SOCK; # endif { ! if (channel->ch_pfd[which].ch_fd != CHAN_FD_INVALID) { ! channel->ch_pfd[which].ch_poll_idx = nfd; ! fds[nfd].fd = channel->ch_pfd[which].ch_fd; fds[nfd].events = POLLIN; nfd++; } else ! channel->ch_pfd[which].ch_poll_idx = -1; } } --- 1935,1959 ---- int nfd = nfd_in; channel_T *channel; struct pollfd *fds = fds_in; ! int part; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) # else ! part = PART_SOCK; # endif { ! if (channel->ch_part[part].ch_fd != INVALID_FD) { ! channel->ch_part[part].ch_poll_idx = nfd; ! fds[nfd].fd = channel->ch_part[part].ch_fd; fds[nfd].events = POLLIN; nfd++; } else ! channel->ch_part[part].ch_poll_idx = -1; } } *************** *** 1953,1973 **** int ret = ret_in; channel_T *channel; struct pollfd *fds = fds_in; ! int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which < CH_IN; ++which) # else ! which = CHAN_SOCK; # endif { ! int idx = channel->ch_pfd[which].ch_poll_idx; if (ret > 0 && idx != -1 && fds[idx].revents & POLLIN) { ! channel_read(channel, which, "channel_poll_check"); --ret; } } --- 1969,1989 ---- int ret = ret_in; channel_T *channel; struct pollfd *fds = fds_in; ! int part; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) # else ! part = PART_SOCK; # endif { ! int idx = channel->ch_part[part].ch_poll_idx; if (ret > 0 && idx != -1 && fds[idx].revents & POLLIN) { ! channel_read(channel, part, "channel_poll_check"); --ret; } } *************** *** 1987,2005 **** int maxfd = maxfd_in; channel_T *channel; fd_set *rfds = rfds_in; ! int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else ! which = CHAN_SOCK; # endif { ! sock_T fd = channel->ch_pfd[which].ch_fd; ! if (fd != CHAN_FD_INVALID) { FD_SET((int)fd, rfds); if (maxfd < (int)fd) --- 2003,2021 ---- int maxfd = maxfd_in; channel_T *channel; fd_set *rfds = rfds_in; ! int part; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) # else ! part = PART_SOCK; # endif { ! sock_T fd = channel->ch_part[part].ch_fd; ! if (fd != INVALID_FD) { FD_SET((int)fd, rfds); if (maxfd < (int)fd) *************** *** 2020,2040 **** int ret = ret_in; channel_T *channel; fd_set *rfds = rfds_in; ! int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else ! which = CHAN_SOCK; # endif { ! sock_T fd = channel->ch_pfd[which].ch_fd; ! if (ret > 0 && fd != CHAN_FD_INVALID && FD_ISSET(fd, rfds)) { ! channel_read(channel, which, "channel_select_check"); --ret; } } --- 2036,2056 ---- int ret = ret_in; channel_T *channel; fd_set *rfds = rfds_in; ! int part; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { # ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) # else ! part = PART_SOCK; # endif { ! sock_T fd = channel->ch_part[part].ch_fd; ! if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds)) { ! channel_read(channel, part, "channel_select_check"); --ret; } } *************** *** 2055,2078 **** channel_T *channel = first_channel; int ret = FALSE; int r; while (channel != NULL) { ! /* Increase the refcount, in case the handler causes the channel to be ! * unreferenced or closed. */ ! ++channel->ch_refcount; ! r = may_invoke_callback(channel); ! if (channel_unref(channel)) ! /* channel was freed, start over */ ! channel = first_channel; ! ! if (r == OK) { ! channel = first_channel; /* something was done, start over */ ! ret = TRUE; } else channel = channel->ch_next; } return ret; } --- 2071,2105 ---- channel_T *channel = first_channel; int ret = FALSE; int r; + int part = PART_SOCK; while (channel != NULL) { ! if (channel->ch_part[part].ch_fd != INVALID_FD) { ! /* Increase the refcount, in case the handler causes the channel ! * to be unreferenced or closed. */ ! ++channel->ch_refcount; ! r = may_invoke_callback(channel, part); ! if (r == OK) ! ret = TRUE; ! if (channel_unref(channel) || r == OK) ! { ! /* channel was freed or something was done, start over */ ! channel = first_channel; ! part = PART_SOCK; ! continue; ! } } + #ifdef CHANNEL_PIPES + if (part < PART_ERR) + ++part; else + #endif + { channel = channel->ch_next; + part = PART_SOCK; + } } return ret; } *************** *** 2085,2121 **** { int abort = FALSE; channel_T *channel; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { ! jsonq_T *head = &channel->ch_json_head; ! jsonq_T *item = head->jq_next; ! ! while (item != NULL) { ! list_T *l = item->jq_value->vval.v_list; ! if (l->lv_copyID != copyID) { ! l->lv_copyID = copyID; ! abort = abort || set_ref_in_list(l, copyID, NULL); } - item = item->jq_next; } } return abort; } /* ! * Return the mode of channel "channel". * If "channel" is invalid returns MODE_JSON. */ ch_mode_T ! channel_get_mode(channel_T *channel) { if (channel == NULL) return MODE_JSON; ! return channel->ch_mode; } #endif /* FEAT_CHANNEL */ --- 2112,2182 ---- { int abort = FALSE; channel_T *channel; + int part; for (channel = first_channel; channel != NULL; channel = channel->ch_next) { ! #ifdef CHANNEL_PIPES ! for (part = PART_SOCK; part < PART_IN; ++part) ! #else ! part = PART_SOCK; ! #endif { ! jsonq_T *head = &channel->ch_part[part].ch_json_head; ! jsonq_T *item = head->jq_next; ! while (item != NULL) { ! list_T *l = item->jq_value->vval.v_list; ! ! if (l->lv_copyID != copyID) ! { ! l->lv_copyID = copyID; ! abort = abort || set_ref_in_list(l, copyID, NULL); ! } ! item = item->jq_next; } } } return abort; } /* ! * Return the "part" to write to for "channel". ! */ ! int ! channel_part_send(channel_T *channel) ! { ! #ifdef CHANNEL_PIPES ! if (channel->CH_SOCK_FD == INVALID_FD) ! return PART_IN; ! #endif ! return PART_SOCK; ! } ! ! /* ! * Return the default "part" to read from for "channel". ! */ ! int ! channel_part_read(channel_T *channel) ! { ! #ifdef CHANNEL_PIPES ! if (channel->CH_SOCK_FD == INVALID_FD) ! return PART_OUT; ! #endif ! return PART_SOCK; ! } ! ! /* ! * Return the mode of "channel"/"part" * If "channel" is invalid returns MODE_JSON. */ ch_mode_T ! channel_get_mode(channel_T *channel, int part) { if (channel == NULL) return MODE_JSON; ! return channel->ch_part[part].ch_mode; } #endif /* FEAT_CHANNEL */ *** ../vim-7.4.1368/src/eval.c 2016-02-20 13:54:39.141147074 +0100 --- src/eval.c 2016-02-20 18:14:07.676034381 +0100 *************** *** 10112,10144 **** static void f_ch_readraw(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; /* TODO: use timeout from the options */ channel = get_channel_arg(&argvars[0]); if (channel != NULL) ! rettv->vval.v_string = channel_read_block(channel); } /* * common for "sendexpr()" and "sendraw()" * Returns the channel if the caller should read the response. * Otherwise returns NULL. */ static channel_T * ! send_common(typval_T *argvars, char_u *text, int id, char *fun) { channel_T *channel; jobopt_T opt; channel = get_channel_arg(&argvars[0]); if (channel == NULL) return NULL; opt.jo_callback = NULL; if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL) --- 10112,10153 ---- static void f_ch_readraw(typval_T *argvars, typval_T *rettv) { ! channel_T *channel; ! int part; /* return an empty string by default */ rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; /* TODO: use timeout from the options */ + /* TODO: read from stderr */ channel = get_channel_arg(&argvars[0]); if (channel != NULL) ! { ! part = channel_part_read(channel); ! rettv->vval.v_string = channel_read_block(channel, part); ! } } /* * common for "sendexpr()" and "sendraw()" * Returns the channel if the caller should read the response. + * Sets "part_read" to the the read fd. * Otherwise returns NULL. */ static channel_T * ! send_common(typval_T *argvars, char_u *text, int id, char *fun, int *part_read) { channel_T *channel; jobopt_T opt; + int part_send; channel = get_channel_arg(&argvars[0]); if (channel == NULL) return NULL; + part_send = channel_part_send(channel); + *part_read = channel_part_read(channel); opt.jo_callback = NULL; if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL) *************** *** 10147,10155 **** /* Set the callback. An empty callback means no callback and not reading * the response. */ if (opt.jo_callback != NULL && *opt.jo_callback != NUL) ! channel_set_req_callback(channel, opt.jo_callback, id); ! if (channel_send(channel, text, fun) == OK && opt.jo_callback == NULL) return channel; return NULL; } --- 10156,10165 ---- /* Set the callback. An empty callback means no callback and not reading * the response. */ if (opt.jo_callback != NULL && *opt.jo_callback != NUL) ! channel_set_req_callback(channel, part_send, opt.jo_callback, id); ! if (channel_send(channel, part_send, text, fun) == OK ! && opt.jo_callback == NULL) return channel; return NULL; } *************** *** 10165,10170 **** --- 10175,10182 ---- channel_T *channel; int id; ch_mode_T ch_mode; + int part_send; + int part_read; /* return an empty string by default */ rettv->v_type = VAR_STRING; *************** *** 10173,10183 **** channel = get_channel_arg(&argvars[0]); if (channel == NULL) return; ! ch_mode = channel_get_mode(channel); ! if (ch_mode == MODE_RAW) { ! EMSG(_("E912: cannot use ch_sendexpr() with a raw channel")); return; } --- 10185,10196 ---- channel = get_channel_arg(&argvars[0]); if (channel == NULL) return; + part_send = channel_part_send(channel); ! ch_mode = channel_get_mode(channel, part_send); ! if (ch_mode == MODE_RAW || ch_mode == MODE_NL) { ! EMSG(_("E912: cannot use ch_sendexpr() with a raw or nl channel")); return; } *************** *** 10187,10197 **** if (text == NULL) return; ! channel = send_common(argvars, text, id, "sendexpr"); vim_free(text); if (channel != NULL) { ! if (channel_read_json_block(channel, id, &listtv) == OK) { list_T *list = listtv->vval.v_list; --- 10200,10210 ---- if (text == NULL) return; ! channel = send_common(argvars, text, id, "sendexpr", &part_read); vim_free(text); if (channel != NULL) { ! if (channel_read_json_block(channel, part_read, id, &listtv) == OK) { list_T *list = listtv->vval.v_list; *************** *** 10213,10227 **** char_u buf[NUMBUFLEN]; char_u *text; channel_T *channel; /* return an empty string by default */ rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; text = get_tv_string_buf(&argvars[1], buf); ! channel = send_common(argvars, text, 0, "sendraw"); if (channel != NULL) ! rettv->vval.v_string = channel_read_block(channel); } /* --- 10226,10241 ---- char_u buf[NUMBUFLEN]; char_u *text; channel_T *channel; + int part_read; /* return an empty string by default */ rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; text = get_tv_string_buf(&argvars[1], buf); ! channel = send_common(argvars, text, 0, "sendraw", &part_read); if (channel != NULL) ! rettv->vval.v_string = channel_read_block(channel, part_read); } /* *** ../vim-7.4.1368/src/structs.h 2016-02-19 22:33:31.500263323 +0100 --- src/structs.h 2016-02-20 18:09:31.126937161 +0100 *************** *** 1303,1321 **** /* Ordering matters, it is used in for loops: IN is last, only SOCK/OUT/ERR * are polled. */ ! #define CHAN_SOCK 0 ! #define CH_SOCK ch_pfd[CHAN_SOCK].ch_fd #if defined(UNIX) || defined(WIN32) # define CHANNEL_PIPES ! # define CHAN_FD_INVALID (-1) ! # define CHAN_OUT 1 ! # define CHAN_ERR 2 ! # define CHAN_IN 3 ! # define CH_OUT ch_pfd[CHAN_OUT].ch_fd ! # define CH_ERR ch_pfd[CHAN_ERR].ch_fd ! # define CH_IN ch_pfd[CHAN_IN].ch_fd #endif /* The per-fd info for a channel. */ --- 1303,1321 ---- /* Ordering matters, it is used in for loops: IN is last, only SOCK/OUT/ERR * are polled. */ ! #define PART_SOCK 0 ! #define CH_SOCK_FD ch_part[PART_SOCK].ch_fd #if defined(UNIX) || defined(WIN32) # define CHANNEL_PIPES ! # define INVALID_FD (-1) ! # define PART_OUT 1 ! # define PART_ERR 2 ! # define PART_IN 3 ! # define CH_OUT_FD ch_part[PART_OUT].ch_fd ! # define CH_ERR_FD ch_part[PART_ERR].ch_fd ! # define CH_IN_FD ch_part[PART_IN].ch_fd #endif /* The per-fd info for a channel. */ *************** *** 1335,1341 **** #ifdef WIN32 int ch_inputHandler; /* ret.value of WSAAsyncSelect() */ #endif ! } chan_fd_T; struct channel_S { channel_T *ch_next; --- 1335,1352 ---- #ifdef WIN32 int ch_inputHandler; /* ret.value of WSAAsyncSelect() */ #endif ! ! ch_mode_T ch_mode; ! int ch_timeout; /* request timeout in msec */ ! ! readq_T ch_head; /* header for circular raw read queue */ ! jsonq_T ch_json_head; /* header for circular json read queue */ ! int ch_block_id; /* ID that channel_read_json_block() is ! waiting for */ ! ! cbq_T ch_cb_head; /* dummy node for per-request callbacks */ ! char_u *ch_callback; /* call when a msg is not handled */ ! } chanpart_T; struct channel_S { channel_T *ch_next; *************** *** 1343,1351 **** int ch_id; /* ID of the channel */ ! chan_fd_T ch_pfd[4]; /* info for socket, out, err and in */ ! ! 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 --- 1354,1360 ---- int ch_id; /* ID of the channel */ ! chanpart_T ch_part[4]; /* info for socket, out, err and in */ int ch_error; /* When TRUE an error was reported. Avoids * giving pages full of error messages when *************** *** 1355,1369 **** void (*ch_close_cb)(void); /* callback for when channel is closed */ ! int ch_block_id; /* ID that channel_read_json_block() is ! waiting for */ ! char_u *ch_callback; /* function to call when a msg is not handled */ ! cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ ! ! ch_mode_T ch_mode; ! jsonq_T ch_json_head; /* dummy node, header for circular queue */ ! ! int ch_timeout; /* request timeout in msec */ job_T *ch_job; /* Job that uses this channel; this does not * count as a reference to avoid a circular --- 1364,1370 ---- void (*ch_close_cb)(void); /* callback for when channel is closed */ ! char_u *ch_callback; /* call when any msg is not handled */ job_T *ch_job; /* Job that uses this channel; this does not * count as a reference to avoid a circular *************** *** 1372,1381 **** int ch_refcount; /* reference count */ }; ! #define JO_MODE 1 ! #define JO_CALLBACK 2 ! #define JO_WAITTIME 4 ! #define JO_TIMEOUT 8 #define JO_ALL 0xffffff /* --- 1373,1382 ---- int ch_refcount; /* reference count */ }; ! #define JO_MODE 1 /* all modes */ ! #define JO_CALLBACK 2 /* channel callback */ ! #define JO_WAITTIME 4 /* only for ch_open() */ ! #define JO_TIMEOUT 8 /* all timeouts */ #define JO_ALL 0xffffff /* *** ../vim-7.4.1368/src/netbeans.c 2016-02-18 22:23:21.173660406 +0100 --- src/netbeans.c 2016-02-20 18:02:44.615146657 +0100 *************** *** 385,391 **** while (nb_channel != NULL) { ! buffer = channel_peek(nb_channel); if (buffer == NULL) break; /* nothing to read */ --- 385,391 ---- while (nb_channel != NULL) { ! buffer = channel_peek(nb_channel, PART_SOCK); if (buffer == NULL) break; /* nothing to read */ *************** *** 396,402 **** /* Command isn't complete. If there is no following buffer, * return (wait for more). If there is another buffer following, * prepend the text to that buffer and delete this one. */ ! if (channel_collapse(nb_channel) == FAIL) return; } else --- 396,402 ---- /* Command isn't complete. If there is no following buffer, * return (wait for more). If there is another buffer following, * prepend the text to that buffer and delete this one. */ ! if (channel_collapse(nb_channel, PART_SOCK) == FAIL) return; } else *************** *** 409,415 **** if (*p == NUL) { own_node = TRUE; ! channel_get(nb_channel); } else own_node = FALSE; --- 409,415 ---- if (*p == NUL) { own_node = TRUE; ! channel_get(nb_channel, PART_SOCK); } else own_node = FALSE; *************** *** 757,763 **** nb_send(char *buf, char *fun) { if (nb_channel != NULL) ! channel_send(nb_channel, (char_u *)buf, fun); } /* --- 757,763 ---- nb_send(char *buf, char *fun) { if (nb_channel != NULL) ! channel_send(nb_channel, PART_SOCK, (char_u *)buf, fun); } /* *** ../vim-7.4.1368/src/gui_w32.c 2016-02-20 13:54:39.129147199 +0100 --- src/gui_w32.c 2016-02-20 18:14:29.663801987 +0100 *************** *** 1930,1944 **** #ifdef FEAT_CHANNEL if (msg.message == WM_NETBEANS) { ! int what; ! channel_T *channel = channel_fd2channel((sock_T)msg.wParam, &what); if (channel != NULL) { /* Disable error messages, they can mess up the display and throw * an exception. */ ++emsg_off; ! channel_read(channel, what, "process_message"); --emsg_off; } return; --- 1930,1944 ---- #ifdef FEAT_CHANNEL if (msg.message == WM_NETBEANS) { ! int part; ! channel_T *channel = channel_fd2channel((sock_T)msg.wParam, &part); if (channel != NULL) { /* Disable error messages, they can mess up the display and throw * an exception. */ ++emsg_off; ! channel_read(channel, part, "process_message"); --emsg_off; } return; *** ../vim-7.4.1368/src/proto/channel.pro 2016-02-19 23:21:21.674060254 +0100 --- src/proto/channel.pro 2016-02-20 18:14:56.927513852 +0100 *************** *** 11,39 **** void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err); void channel_set_job(channel_T *channel, job_T *job); void channel_set_options(channel_T *channel, jobopt_T *options); ! void channel_set_req_callback(channel_T *channel, char_u *callback, int id); ! char_u *channel_get(channel_T *channel); ! int channel_collapse(channel_T *channel); int channel_can_write_to(channel_T *channel); int channel_is_open(channel_T *channel); char *channel_status(channel_T *channel); void channel_close(channel_T *channel); ! int channel_save(channel_T *channel, char_u *buf, int len); ! char_u *channel_peek(channel_T *channel); void channel_clear(channel_T *channel); void channel_free_all(void); int channel_get_id(void); ! void channel_read(channel_T *channel, int which, char *func); ! char_u *channel_read_block(channel_T *channel); ! int channel_read_json_block(channel_T *channel, int id, typval_T **rettv); ! channel_T *channel_fd2channel(sock_T fd, int *whichp); void channel_handle_events(void); ! int channel_send(channel_T *channel, char_u *buf, char *fun); int channel_poll_setup(int nfd_in, void *fds_in); int channel_poll_check(int ret_in, void *fds_in); int channel_select_setup(int maxfd_in, void *rfds_in); int channel_select_check(int ret_in, void *rfds_in); int channel_parse_messages(void); int set_ref_in_channel(int copyID); ! ch_mode_T channel_get_mode(channel_T *channel); /* vim: set ft=c : */ --- 11,40 ---- void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err); void channel_set_job(channel_T *channel, job_T *job); void channel_set_options(channel_T *channel, jobopt_T *options); ! void channel_set_req_callback(channel_T *channel, int part, char_u *callback, int id); ! char_u *channel_get(channel_T *channel, int part); ! int channel_collapse(channel_T *channel, int part); int channel_can_write_to(channel_T *channel); int channel_is_open(channel_T *channel); char *channel_status(channel_T *channel); void channel_close(channel_T *channel); ! char_u *channel_peek(channel_T *channel, int part); void channel_clear(channel_T *channel); void channel_free_all(void); int channel_get_id(void); ! void channel_read(channel_T *channel, int part, char *func); ! char_u *channel_read_block(channel_T *channel, int part); ! int channel_read_json_block(channel_T *channel, int part, int id, typval_T **rettv); ! channel_T *channel_fd2channel(sock_T fd, int *part); void channel_handle_events(void); ! int channel_send(channel_T *channel, int part, char_u *buf, char *fun); int channel_poll_setup(int nfd_in, void *fds_in); int channel_poll_check(int ret_in, void *fds_in); int channel_select_setup(int maxfd_in, void *rfds_in); int channel_select_check(int ret_in, void *rfds_in); int channel_parse_messages(void); int set_ref_in_channel(int copyID); ! int channel_part_send(channel_T *channel); ! int channel_part_read(channel_T *channel); ! ch_mode_T channel_get_mode(channel_T *channel, int part); /* vim: set ft=c : */ *** ../vim-7.4.1368/src/version.c 2016-02-20 15:48:58.397925180 +0100 --- src/version.c 2016-02-20 17:51:09.530345535 +0100 *************** *** 749,750 **** --- 749,752 ---- { /* Add new patch number below this line */ + /**/ + 1369, /**/ -- "A mouse can be just as dangerous as a bullet or a bomb." (US Representative Lamar Smith, R-Texas) /// Bram Moolenaar -- Bram@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 ///