On Friday, 5 February 2016 13:37:07 UTC-8, Bram Moolenaar wrote:
> Patch 7.4.1263
> Problem: ch_open() hangs when the server isn't running.
> Solution: Add a timeout. Use a dict to pass arguments. (Yasuhiro Matsumoto)
> Files: runtime/doc/eval.txt, runtime/doc/channel.txt, src/channel.c,
> src/eval.c, src/netbeans.c, src/os_win32.c, src/proto/channel.pro,
> src/testdir/test_channel.vim
>
>
> *** ../vim-7.4.1262/runtime/doc/eval.txt 2016-02-02 20:46:29.715412004
> +0100
> --- runtime/doc/eval.txt 2016-02-05 21:53:15.728780022 +0100
> ***************
> *** 1786,1793 ****
> any call {func} with arguments {arglist}
> ceil( {expr}) Float round {expr} up
> ch_close( {handle}) none close a channel
> ! ch_open( {address}, {mode} [, {callback}])
> ! Number open a channel
> ch_sendexpr( {handle}, {expr} [, {callback}])
> any send {expr} over JSON channel {handle}
> ch_sendraw( {handle}, {string} [, {callback}])
> --- 1811,1817 ----
> any call {func} with arguments {arglist}
> ceil( {expr}) Float round {expr} up
> ch_close( {handle}) none close a channel
> ! ch_open( {address} [, {argdict})] Number open a channel to {address}
> ch_sendexpr( {handle}, {expr} [, {callback}])
> any send {expr} over JSON channel {handle}
> ch_sendraw( {handle}, {string} [, {callback}])
> ***************
> *** 2641,2647 ****
> ch_close({handle}) *ch_close()*
> Close channel {handle}. See |channel|.
>
> ! ch_open({address}, {mode} [, {callback}]) *ch_open()*
> Open a channel to {address}. See |channel|.
> Returns the channel handle on success. Returns a negative
> number for failure.
> --- 2669,2675 ----
> ch_close({handle}) *ch_close()*
> Close channel {handle}. See |channel|.
>
> ! ch_open({address} [, {argdict}]) *ch_open()*
> Open a channel to {address}. See |channel|.
> Returns the channel handle on success. Returns a negative
> number for failure.
> ***************
> *** 2649,2661 ****
> {address} has the form "hostname:port", e.g.,
> "localhost:8765".
>
> ! {mode} is either "json" or "raw". See |channel-mode| for the
> ! meaning.
> !
> ! {callback} is a function that handles received messages on the
> ! channel. See |channel-callback|.
>
> ! ch_sendexpr({handle}, {expr} [, {callback}]) ch_*sendexpr()*
> Send {expr} over JSON channel {handle}. See |channel-use|.
>
> When {callback} is given returns immediately. Without
> --- 2677,2697 ----
> {address} has the form "hostname:port", e.g.,
> "localhost:8765".
>
> ! If {argdict} is given it must be a |Directory|. The optional
> ! items are:
> ! mode "raw" or "json".
> ! Default "json".
> ! callback function to call for requests with a zero
> ! sequence number. See |channel-callback|.
> ! Default: none.
> ! waittime Specify connect timeout as milliseconds.
> ! Negative means forever.
> ! Default: 0.
> ! timeout Specify response read timeout value as
> ! milliseconds.
> ! Default: 2000.
>
> ! ch_sendexpr({handle}, {expr} [, {callback}]) *ch_sendexpr()*
> Send {expr} over JSON channel {handle}. See |channel-use|.
>
> When {callback} is given returns immediately. Without
> *** ../vim-7.4.1262/runtime/doc/channel.txt 2016-01-31 20:24:09.970066843
> +0100
> --- runtime/doc/channel.txt 2016-02-05 22:13:51.287732962 +0100
> ***************
> *** 1,4 ****
> ! *channel.txt* For Vim version 7.4. Last change: 2016 Jan 31
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> --- 1,4 ----
> ! *channel.txt* For Vim version 7.4. Last change: 2016 Feb 05
>
>
> VIM REFERENCE MANUAL by Bram Moolenaar
> ***************
> *** 11,17 ****
> Vim uses channels to communicate with other processes.
> A channel uses a socket. *socket-interface*
>
> ! Vim current supports up to 10 simultanious channels.
> The Netbeans interface also uses a channel. |netbeans|
>
> 1. Demo |channel-demo|
> --- 11,17 ----
> Vim uses channels to communicate with other processes.
> A channel uses a socket. *socket-interface*
>
> ! Vim current supports up to 10 simultaneous channels.
> The Netbeans interface also uses a channel. |netbeans|
>
> 1. Demo |channel-demo|
> ***************
> *** 32,44 ****
> Run it in one terminal. We will call this T1.
>
> Run Vim in another terminal. Connect to the demo server with: >
> ! let handle = connect('localhost:8765', 'json')
>
> In T1 you should see:
> === socket opened === ~
>
> You can now send a message to the server: >
> ! echo sendexpr(handle, 'hello!')
>
> The message is received in T1 and a response is sent back to Vim.
> You can see the raw messages in T1. What Vim sends is:
> --- 32,44 ----
> Run it in one terminal. We will call this T1.
>
> Run Vim in another terminal. Connect to the demo server with: >
> ! let handle = ch_open('localhost:8765')
>
> In T1 you should see:
> === socket opened === ~
>
> You can now send a message to the server: >
> ! echo ch_sendexpr(handle, 'hello!')
>
> The message is received in T1 and a response is sent back to Vim.
> You can see the raw messages in T1. What Vim sends is:
> ***************
> *** 57,104 ****
> func MyHandler(handle, msg)
> echo "from the handler: " . a:msg
> endfunc
> ! call sendexpr(handle, 'hello!', "MyHandler")
>
> Instead of giving a callback with every send call, it can also be specified
> when opening the channel: >
> ! call disconnect(handle)
> ! let handle = connect('localhost:8765', 'json', "MyHandler")
> ! call sendexpr(handle, 'hello!', 0)
>
>
> ==============================================================================
> 2. Opening a channel *channel-open*
>
> ! To open a channel:
> ! let handle = connect({address}, {mode}, {callback})
>
> {address} has the form "hostname:port". E.g., "localhost:8765".
>
> ! {mode} can be: *channel-mode*
> ! "json" - Use JSON, see below; most convenient way
> "raw" - Use raw messages
>
> *channel-callback*
> ! {callback} is a function that is called when a message is received that is
> not
> handled otherwise. It gets two arguments: the channel handle and the
> received
> message. Example: >
> func Handle(handle, msg)
> echo 'Received: ' . a:msg
> endfunc
> ! let handle = connect("localhost:8765", 'json', "Handle")
>
> ! When {mode} is "json" the "msg" argument is the body of the received
> message,
> converted to Vim types.
> ! When {mode} is "raw" the "msg" argument is the whole message as a string.
>
> ! When {mode} is "json" the {callback} is optional. When omitted it is only
> possible to receive a message after sending one.
>
> The handler can be added or changed later: >
> ! call sethandler(handle, {callback})
> ! When {callback} is empty (zero or an empty string) the handler is removed.
>
> Once done with the channel, disconnect it like this: >
> ! call disconnect(handle)
>
> Currently up to 10 channels can be in use at the same time. *E897*
>
> --- 57,118 ----
> func MyHandler(handle, msg)
> echo "from the handler: " . a:msg
> endfunc
> ! call ch_sendexpr(handle, 'hello!', "MyHandler")
>
> Instead of giving a callback with every send call, it can also be specified
> when opening the channel: >
> ! call ch_close(handle)
> ! let handle = ch_open('localhost:8765', {'callback': "MyHandler"})
> ! call ch_sendexpr(handle, 'hello!', 0)
>
>
> ==============================================================================
> 2. Opening a channel *channel-open*
>
> ! To open a channel: >
> ! let handle = ch_open({address} [, {argdict}])
>
> {address} has the form "hostname:port". E.g., "localhost:8765".
>
> ! {argdict} is a dictionary with optional entries:
> !
> ! "mode" can be: *channel-mode*
> ! "json" - Use JSON, see below; most convenient way. Default.
> "raw" - Use raw messages
>
> *channel-callback*
> ! "callback" is a function that is called when a message is received that is
> not
> handled otherwise. It gets two arguments: the channel handle and the
> received
> message. Example: >
> func Handle(handle, msg)
> echo 'Received: ' . a:msg
> endfunc
> ! let handle = ch_open("localhost:8765", 'json', "Handle")
> !
> ! "waittime" is the time to wait for the connection to be made in
> milliseconds.
> ! The default is zero, don't wait, which is useful if the server is supposed
> to
> ! be running already. A negative number waits forever.
> !
> ! "timeout" is the time to wait for a request when blocking, using
> ! ch_sendexpr(). Again in millisecons. The default si 2000 (2 seconds).
>
> ! When "mode" is "json" the "msg" argument is the body of the received
> message,
> converted to Vim types.
> ! When "mode" is "raw" the "msg" argument is the whole message as a string.
>
> ! When "mode" is "json" the "callback" is optional. When omitted it is only
> possible to receive a message after sending one.
>
> The handler can be added or changed later: >
> ! call ch_setcallback(handle, {callback})
> ! When "callback is empty (zero or an empty string) the handler is removed.
> ! NOT IMPLEMENTED YET
> !
> ! The timeout can be changed later: >
> ! call ch_settimeout(handle, {msec})
> ! NOT IMPLEMENTED YET
>
> Once done with the channel, disconnect it like this: >
> ! call ch_close(handle)
>
> Currently up to 10 channels can be in use at the same time. *E897*
>
> ***************
> *** 112,126 ****
> 3. Using a JSON channel *channel-use*
>
> If {mode} is "json" then a message can be sent synchronously like this: >
> ! let response = sendexpr(handle, {expr})
> This awaits a response from the other side.
>
> To send a message, without handling a response: >
> ! call sendexpr(handle, {expr}, 0)
>
> To send a message and letting the response handled by a specific function,
> asynchronously: >
> ! call sendexpr(handle, {expr}, {callback})
>
> The {expr} is converted to JSON and wrapped in an array. An example of the
> message that the receiver will get when {expr} is the string "hello":
> --- 126,140 ----
> 3. Using a JSON channel *channel-use*
>
> If {mode} is "json" then a message can be sent synchronously like this: >
> ! let response = ch_sendexpr(handle, {expr})
> This awaits a response from the other side.
>
> To send a message, without handling a response: >
> ! call ch_sendexpr(handle, {expr}, 0)
>
> To send a message and letting the response handled by a specific function,
> asynchronously: >
> ! call ch_sendexpr(handle, {expr}, {callback})
>
> The {expr} is converted to JSON and wrapped in an array. An example of the
> message that the receiver will get when {expr} is the string "hello":
> ***************
> *** 148,154 ****
> Then channel handler will then get {response} converted to Vim types. If
> the
> channel does not have a handler the message is dropped.
>
> ! On read error or disconnect() the string "DETACH" is sent, if still
> possible.
> The channel will then be inactive.
>
>
> ==============================================================================
> --- 162,168 ----
> Then channel handler will then get {response} converted to Vim types. If
> the
> channel does not have a handler the message is dropped.
>
> ! On read error or ch_close() the string "DETACH" is sent, if still possible.
> The channel will then be inactive.
>
>
> ==============================================================================
> ***************
> *** 200,206 ****
>
> Command "normal" ~
>
> ! The "normal" command is executed like with |:normal!|, commands are not
> mapped. Example to open the folds under the cursor:
> ["normal" "zO"]
>
> --- 214,220 ----
>
> Command "normal" ~
>
> ! The "normal" command is executed like with ":normal!", commands are not
> mapped. Example to open the folds under the cursor:
> ["normal" "zO"]
>
> ***************
> *** 230,248 ****
> 5. Using a raw channel *channel-raw*
>
> If {mode} is "raw" then a message can be send like this: >
> ! let response = sendraw(handle, {string})
> The {string} is sent as-is. The response will be what can be read from the
> channel right away. Since Vim doesn't know how to recognize the end of the
> message you need to take care of it yourself.
>
> To send a message, without expecting a response: >
> ! call sendraw(handle, {string}, 0)
> The process can send back a response, the channel handler will be called
> with
> it.
>
> To send a message and letting the response handled by a specific function,
> asynchronously: >
> ! call sendraw(handle, {string}, {callback})
>
> This {string} can also be JSON, use |jsonencode()| to create it and
> |jsondecode()| to handle a received JSON message.
> --- 244,262 ----
> 5. Using a raw channel *channel-raw*
>
> If {mode} is "raw" then a message can be send like this: >
> ! let response = ch_sendraw(handle, {string})
> The {string} is sent as-is. The response will be what can be read from the
> channel right away. Since Vim doesn't know how to recognize the end of the
> message you need to take care of it yourself.
>
> To send a message, without expecting a response: >
> ! call ch_sendraw(handle, {string}, 0)
> The process can send back a response, the channel handler will be called
> with
> it.
>
> To send a message and letting the response handled by a specific function,
> asynchronously: >
> ! call ch_sendraw(handle, {string}, {callback})
>
> This {string} can also be JSON, use |jsonencode()| to create it and
> |jsondecode()| to handle a received JSON message.
> *** ../vim-7.4.1262/src/channel.c 2016-02-05 21:04:02.820081559 +0100
> --- src/channel.c 2016-02-05 22:30:40.557174945 +0100
> ***************
> *** 42,47 ****
> --- 42,49 ----
> # define SOCK_ERRNO errno = WSAGetLastError()
> # undef ECONNREFUSED
> # define ECONNREFUSED WSAECONNREFUSED
> + # undef EWOULDBLOCK
> + # define EWOULDBLOCK WSAEWOULDBLOCK
> # ifdef EINTR
> # undef EINTR
> # endif
> ***************
> *** 119,124 ****
> --- 121,128 ----
>
> int ch_json_mode; /* TRUE for a json channel */
> jsonq_T ch_json_head; /* dummy node, header for circular queue */
> +
> + int ch_timeout; /* request timeout in msec */
> } channel_T;
>
> /*
> ***************
> *** 133,138 ****
> --- 137,184 ----
> */
> FILE *debugfd = NULL;
>
> + #ifdef _WIN32
> + # undef PERROR
> + # define PERROR(msg) (void)emsg3((char_u *)"%s: %s", \
> + (char_u *)msg, (char_u *)strerror_win32(errno))
> +
> + static char *
> + strerror_win32(int eno)
> + {
> + static LPVOID msgbuf = NULL;
> + char_u *ptr;
> +
> + if (msgbuf)
> + LocalFree(msgbuf);
> + FormatMessage(
> + FORMAT_MESSAGE_ALLOCATE_BUFFER |
> + FORMAT_MESSAGE_FROM_SYSTEM |
> + FORMAT_MESSAGE_IGNORE_INSERTS,
> + NULL,
> + eno,
> + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
> + (LPTSTR) &msgbuf,
> + 0,
> + NULL);
> + /* chomp \r or \n */
> + for (ptr = (char_u *)msgbuf; *ptr; ptr++)
> + switch (*ptr)
> + {
> + case '\r':
> + STRMOVE(ptr, ptr + 1);
> + ptr--;
> + break;
> + case '\n':
> + if (*(ptr + 1) == '\0')
> + *ptr = '\0';
> + else
> + *ptr = ' ';
> + break;
> + }
> + return msgbuf;
> + }
> + #endif
> +
> /*
> * Add a new channel slot, return the index.
> * The channel isn't actually used into ch_fd is set >= 0;
> ***************
> *** 182,187 ****
> --- 228,235 ----
> ch->ch_json_head.next = &ch->ch_json_head;
> ch->ch_json_head.prev = &ch->ch_json_head;
>
> + ch->ch_timeout = 2000;
> +
> return channel_count++;
> }
>
> ***************
> *** 303,319 ****
> * Returns a negative number for failure.
> */
> int
> ! channel_open(char *hostname, int port_in, void (*close_cb)(void))
> {
> int sd;
> struct sockaddr_in server;
> struct hostent * host;
> #ifdef WIN32
> u_short port = port_in;
> #else
> int port = port_in;
> #endif
> int idx;
>
> #ifdef WIN32
> channel_init_winsock();
> --- 351,369 ----
> * Returns a negative number for failure.
> */
> int
> ! channel_open(char *hostname, int port_in, int waittime, void
> (*close_cb)(void))
> {
> int sd;
> struct sockaddr_in server;
> struct hostent * host;
> #ifdef WIN32
> u_short port = port_in;
> + u_long val = 1;
> #else
> int port = port_in;
> #endif
> int idx;
> + int ret;
>
> #ifdef WIN32
> channel_init_winsock();
> ***************
> *** 348,410 ****
> }
> memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
>
> ! /* Connect to server */
> ! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
> {
> ! SOCK_ERRNO;
> ! CHERROR("channel_open: Connect failed with errno %d\n", errno);
> ! if (errno == ECONNREFUSED)
> {
> sock_close(sd);
> ! if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
> ! {
> ! SOCK_ERRNO;
> ! CHERROR("socket() retry in channel_open()\n", "");
> ! PERROR("E900: socket() retry in channel_open()");
> ! return -1;
> ! }
> ! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
> ! {
> ! int retries = 36;
> ! int success = FALSE;
>
> ! SOCK_ERRNO;
> ! while (retries-- && ((errno == ECONNREFUSED)
> ! || (errno == EINTR)))
> ! {
> ! CHERROR("retrying...\n", "");
> ! mch_delay(3000L, TRUE);
> ! ui_breakcheck();
> ! if (got_int)
> ! {
> ! errno = EINTR;
> ! break;
> ! }
> ! if (connect(sd, (struct sockaddr *)&server,
> ! sizeof(server)) == 0)
> ! {
> ! success = TRUE;
> ! break;
> ! }
> ! SOCK_ERRNO;
> ! }
> ! if (!success)
> ! {
> ! /* Get here when the server can't be found. */
> ! CHERROR("Cannot connect to port after retry\n", "");
> ! PERROR(_("E899: Cannot connect to port after retry2"));
> ! sock_close(sd);
> ! return -1;
> ! }
> ! }
> }
> ! else
> {
> CHERROR("Cannot connect to port\n", "");
> PERROR(_("E902: Cannot connect to port"));
> sock_close(sd);
> return -1;
> }
> }
>
> channels[idx].ch_fd = sd;
> --- 398,518 ----
> }
> memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
>
> ! if (waittime >= 0)
> {
> ! /* Make connect non-blocking. */
> ! if (
> ! #ifdef _WIN32
> ! ioctlsocket(sd, FIONBIO, &val) < 0
> ! #else
> ! fcntl(sd, F_SETFL, O_NONBLOCK) < 0
> ! #endif
> ! )
> {
> + SOCK_ERRNO;
> + CHERROR("channel_open: Connect failed with errno %d\n", errno);
> sock_close(sd);
> ! return -1;
> ! }
> ! }
>
> ! /* Try connecting to the server. */
> ! ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
> ! SOCK_ERRNO;
> ! if (ret < 0)
> ! {
> ! if (errno != EWOULDBLOCK && errno != EINPROGRESS)
> ! {
> ! CHERROR("channel_open: Connect failed with errno %d\n", errno);
> ! CHERROR("Cannot connect to port\n", "");
> ! PERROR(_("E902: Cannot connect to port"));
> ! sock_close(sd);
> ! return -1;
> }
> ! }
> !
> ! if (waittime >= 0)
> ! {
> ! struct timeval tv;
> ! fd_set rfds, wfds;
> !
> ! FD_ZERO(&rfds);
> ! FD_ZERO(&wfds);
> ! FD_SET(sd, &rfds);
> ! FD_SET(sd, &wfds);
> ! tv.tv_sec = waittime;
> ! tv.tv_usec = 0;
> ! ret = select((int)sd+1, &rfds, &wfds, NULL, &tv);
> ! if (ret < 0)
> {
> + SOCK_ERRNO;
> + CHERROR("channel_open: Connect failed with errno %d\n", errno);
> CHERROR("Cannot connect to port\n", "");
> PERROR(_("E902: Cannot connect to port"));
> sock_close(sd);
> return -1;
> }
> + if (!FD_ISSET(sd, &rfds) && !FD_ISSET(sd, &wfds))
> + {
> + errno = ECONNREFUSED;
> + CHERROR("Cannot connect to port\n", "");
> + PERROR(_("E902: Cannot connect to port"));
> + sock_close(sd);
> + return -1;
> + }
> +
> + #ifdef _WIN32
> + val = 0;
> + ioctlsocket(sd, FIONBIO, &val);
> + #else
> + fcntl(sd, F_SETFL, 0);
> + #endif
> + }
> +
> + if (errno == ECONNREFUSED)
> + {
> + sock_close(sd);
> + if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
> + {
> + SOCK_ERRNO;
> + CHERROR("socket() retry in channel_open()\n", "");
> + PERROR("E900: socket() retry in channel_open()");
> + return -1;
> + }
> + if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
> + {
> + int retries = 36;
> + int success = FALSE;
> +
> + SOCK_ERRNO;
> + while (retries-- && ((errno == ECONNREFUSED)
> + || (errno == EINTR)))
> + {
> + CHERROR("retrying...\n", "");
> + mch_delay(3000L, TRUE);
> + ui_breakcheck();
> + if (got_int)
> + {
> + errno = EINTR;
> + break;
> + }
> + if (connect(sd, (struct sockaddr *)&server,
> + sizeof(server)) == 0)
> + {
> + success = TRUE;
> + break;
> + }
> + SOCK_ERRNO;
> + }
> + if (!success)
> + {
> + /* Get here when the server can't be found. */
> + CHERROR("Cannot connect to port after retry\n", "");
> + PERROR(_("E899: Cannot connect to port after retry2"));
> + sock_close(sd);
> + return -1;
> + }
> + }
> }
>
> channels[idx].ch_fd = sd;
> ***************
> *** 427,432 ****
> --- 535,549 ----
> }
>
> /*
> + * Set the read timeout of channel "idx".
> + */
> + void
> + channel_set_timeout(int idx, int timeout)
> + {
> + channels[idx].ch_timeout = timeout;
> + }
> +
> + /*
> * Set the callback for channel "idx".
> */
> void
> ***************
> *** 898,903 ****
> --- 1015,1021 ----
> #endif
> vim_free(channel->ch_callback);
> channel->ch_callback = NULL;
> + channel->ch_timeout = 2000;
>
> while (channel_peek(idx) != NULL)
> vim_free(channel_get(idx));
> ***************
> *** 1148,1156 ****
> {
> if (channel_peek(idx) == NULL)
> {
> ! /* Wait for up to 2 seconds.
> ! * TODO: use timeout set on the channel. */
> ! if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
> return NULL;
> channel_read(idx);
> }
> --- 1266,1273 ----
> {
> if (channel_peek(idx) == NULL)
> {
> ! /* Wait for up to the channel timeout. */
> ! if (channel_wait(channels[idx].ch_fd, channels[idx].ch_timeout) == FAIL)
> return NULL;
> channel_read(idx);
> }
> ***************
> *** 1161,1167 ****
> /*
> * 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)
> --- 1278,1284 ----
> /*
> * Read one JSON message from channel "ch_idx" with ID "id" and store the
> * result in "rettv".
> ! * Blocks until the message is received or the timeout is reached.
> */
> int
> channel_read_json_block(int ch_idx, int id, typval_T **rettv)
> ***************
> *** 1183,1192 ****
> if (channel_parse_messages())
> continue;
>
> ! /* Wait for up to 2 seconds.
> ! * TODO: use timeout set on the channel. */
> if (channels[ch_idx].ch_fd < 0
> ! || channel_wait(channels[ch_idx].ch_fd, 2000) == FAIL)
> break;
> channel_read(ch_idx);
> }
> --- 1300,1309 ----
> if (channel_parse_messages())
> continue;
>
> ! /* Wait for up to the channel timeout. */
> if (channels[ch_idx].ch_fd < 0
> ! || channel_wait(channels[ch_idx].ch_fd,
> ! channels[ch_idx].ch_timeout) == FAIL)
> break;
> channel_read(ch_idx);
> }
> *** ../vim-7.4.1262/src/eval.c 2016-02-05 21:04:02.816081601 +0100
> --- src/eval.c 2016-02-05 22:16:43.797919909 +0100
> ***************
> *** 8005,8011 ****
> #endif
> #ifdef FEAT_CHANNEL
> {"ch_close", 1, 1, f_ch_close},
> ! {"ch_open", 2, 3, f_ch_open},
> {"ch_sendexpr", 2, 3, f_ch_sendexpr},
> {"ch_sendraw", 2, 3, f_ch_sendraw},
> #endif
> --- 8005,8011 ----
> #endif
> #ifdef FEAT_CHANNEL
> {"ch_close", 1, 1, f_ch_close},
> ! {"ch_open", 1, 2, f_ch_open},
> {"ch_sendexpr", 2, 3, f_ch_sendexpr},
> {"ch_sendraw", 2, 3, f_ch_sendraw},
> #endif
> ***************
> *** 9743,9763 ****
> char_u *address;
> char_u *mode;
> char_u *callback = NULL;
> - char_u buf1[NUMBUFLEN];
> char_u *p;
> int port;
> ! int json_mode = FALSE;
>
> /* default: fail */
> rettv->vval.v_number = -1;
>
> address = get_tv_string(&argvars[0]);
> ! mode = get_tv_string_buf(&argvars[1], buf1);
> ! if (argvars[2].v_type != VAR_UNKNOWN)
> {
> ! callback = get_callback(&argvars[2]);
> ! if (callback == NULL)
> ! return;
> }
>
> /* parse address */
> --- 9743,9765 ----
> char_u *address;
> char_u *mode;
> char_u *callback = NULL;
> char_u *p;
> + char *rest;
> int port;
> ! int waittime = 0;
> ! int timeout = 2000;
> ! int json_mode = TRUE;
> ! int ch_idx;
>
> /* default: fail */
> rettv->vval.v_number = -1;
>
> address = get_tv_string(&argvars[0]);
> ! if (argvars[1].v_type != VAR_UNKNOWN
> ! && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
> {
> ! EMSG(_(e_invarg));
> ! return;
> }
>
> /* parse address */
> ***************
> *** 9768,9797 ****
> return;
> }
> *p++ = NUL;
> ! port = atoi((char *)p);
> ! if (*address == NUL || port <= 0)
> {
> p[-1] = ':';
> EMSG2(_(e_invarg2), address);
> return;
> }
>
> ! /* parse mode */
> ! if (STRCMP(mode, "json") == 0)
> ! json_mode = TRUE;
> ! else if (STRCMP(mode, "raw") != 0)
> {
> ! EMSG2(_(e_invarg2), mode);
> return;
> }
>
> ! rettv->vval.v_number = channel_open((char *)address, port, NULL);
> ! if (rettv->vval.v_number >= 0)
> {
> ! channel_set_json_mode(rettv->vval.v_number, json_mode);
> if (callback != NULL && *callback != NUL)
> ! channel_set_callback(rettv->vval.v_number, callback);
> }
> }
>
> /*
> --- 9770,9821 ----
> return;
> }
> *p++ = NUL;
> ! port = strtol((char *)p, &rest, 10);
> ! if (*address == NUL || port <= 0 || *rest != NUL)
> {
> p[-1] = ':';
> EMSG2(_(e_invarg2), address);
> return;
> }
>
> ! if (argvars[1].v_type == VAR_DICT)
> ! {
> ! /* parse argdict */
> ! dict_T *dict = argvars[1].vval.v_dict;
> !
> ! if (dict_find(dict, (char_u *)"mode", -1) != NULL)
> ! {
> ! mode = get_dict_string(dict, (char_u *)"mode", FALSE);
> ! if (STRCMP(mode, "raw") == 0)
> ! json_mode = FALSE;
> ! else if (STRCMP(mode, "json") != 0)
> ! {
> ! EMSG2(_(e_invarg2), mode);
> ! return;
> ! }
> ! }
> ! if (dict_find(dict, (char_u *)"waittime", -1) != NULL)
> ! waittime = get_dict_number(dict, (char_u *)"waittime");
> ! if (dict_find(dict, (char_u *)"timeout", -1) != NULL)
> ! timeout = get_dict_number(dict, (char_u *)"timeout");
> ! if (dict_find(dict, (char_u *)"callback", -1) != NULL)
> ! callback = get_dict_string(dict, (char_u *)"callback", FALSE);
> ! }
> ! if (waittime < 0 || timeout < 0)
> {
> ! EMSG(_(e_invarg));
> return;
> }
>
> ! ch_idx = channel_open((char *)address, port, waittime, NULL);
> ! if (ch_idx >= 0)
> {
> ! channel_set_json_mode(ch_idx, json_mode);
> ! channel_set_timeout(ch_idx, timeout);
> if (callback != NULL && *callback != NUL)
> ! channel_set_callback(ch_idx, callback);
> }
> + rettv->vval.v_number = ch_idx;
> }
>
> /*
> *** ../vim-7.4.1262/src/netbeans.c 2016-01-30 19:39:45.277838615 +0100
> --- src/netbeans.c 2016-02-05 21:33:03.745601600 +0100
> ***************
> *** 213,219 ****
> if (hostname != NULL && address != NULL && password != NULL)
> {
> port = atoi(address);
> ! nb_channel_idx = channel_open(hostname, port, nb_channel_closed);
> if (nb_channel_idx >= 0)
> {
> /* success */
> --- 213,219 ----
> if (hostname != NULL && address != NULL && password != NULL)
> {
> port = atoi(address);
> ! nb_channel_idx = channel_open(hostname, port, 0, nb_channel_closed);
> if (nb_channel_idx >= 0)
> {
> /* success */
> *** ../vim-7.4.1262/src/os_win32.c 2016-02-01 21:32:51.622375175 +0100
> --- src/os_win32.c 2016-02-05 22:06:02.832675296 +0100
> ***************
> *** 1123,1128 ****
> --- 1123,1151 ----
> SetConsoleMode(g_hConIn, cmodein);
> }
>
> + #ifdef FEAT_CHANNEL
> + static int
> + handle_channel_event(void)
> + {
> + int ret;
> + fd_set rfds;
> + int maxfd;
> +
> + FD_ZERO(&rfds);
> + maxfd = channel_select_setup(-1, &rfds);
> + if (maxfd >= 0)
> + {
> + struct timeval tv;
> +
> + tv.tv_sec = 0;
> + tv.tv_usec = 0;
> + ret = select(maxfd + 1, &rfds, NULL, NULL, &tv);
> + if (ret > 0 && channel_select_check(ret, &rfds) > 0)
> + return TRUE;
> + }
> + return FALSE;
> + }
> + #endif
>
> /*
> * Decode a MOUSE_EVENT. If it's a valid event, return MOUSE_LEFT,
> ***************
> *** 1443,1453 ****
> INPUT_RECORD ir;
> DWORD cRecords;
> WCHAR ch, ch2;
> - #ifdef FEAT_CHANNEL
> - int ret;
> - fd_set rfds;
> - int maxfd;
> - #endif
>
> if (msec > 0)
> /* Wait until the specified time has elapsed. */
> --- 1466,1471 ----
> ***************
> *** 1472,1489 ****
> #endif
>
> #ifdef FEAT_CHANNEL
> ! FD_ZERO(&rfds);
> ! maxfd = channel_select_setup(-1, &rfds);
> ! if (maxfd >= 0)
> ! {
> ! struct timeval tv;
> !
> ! tv.tv_sec = 0;
> ! tv.tv_usec = 0;
> ! ret = select(maxfd + 1, &rfds, NULL, NULL, &tv);
> ! if (ret > 0 && channel_select_check(ret, &rfds) > 0)
> ! return TRUE;
> ! }
> #endif
>
> if (0
> --- 1490,1497 ----
> #endif
>
> #ifdef FEAT_CHANNEL
> ! if (handle_channel_event())
> ! return TRUE;
> #endif
>
> if (0
> *** ../vim-7.4.1262/src/proto/channel.pro 2016-02-05 21:04:02.820081559
> +0100
> --- src/proto/channel.pro 2016-02-05 22:06:28.492404449 +0100
> ***************
> *** 1,7 ****
> /* channel.c */
> void channel_gui_register_all(void);
> ! int channel_open(char *hostname, int port_in, void (*close_cb)(void));
> 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 id);
> char_u *channel_get(int idx);
> --- 1,8 ----
> /* channel.c */
> void channel_gui_register_all(void);
> ! int channel_open(char *hostname, int port_in, int waittime, void
> (*close_cb)(void));
> void channel_set_json_mode(int idx, int json_mode);
> + void channel_set_timeout(int idx, int timeout);
> void channel_set_callback(int idx, char_u *callback);
> void channel_set_req_callback(int idx, char_u *callback, int id);
> char_u *channel_get(int idx);
> *** ../vim-7.4.1262/src/testdir/test_channel.vim 2016-02-05
> 21:04:02.820081559 +0100
> --- src/testdir/test_channel.vim 2016-02-05 22:14:30.227322354 +0100
> ***************
> *** 57,63 ****
> endif
> let s:port = l[0]
>
> ! let handle = ch_open('localhost:' . s:port, 'json')
> return handle
> endfunc
>
> --- 57,63 ----
> endif
> let s:port = l[0]
>
> ! let handle = ch_open('localhost:' . s:port)
> return handle
> endfunc
>
> ***************
> *** 128,134 ****
> endif
> call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>
> ! let newhandle = ch_open('localhost:' . s:port, 'json')
> call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
> call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>
> --- 128,134 ----
> endif
> call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>
> ! let newhandle = ch_open('localhost:' . s:port)
> call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
> call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>
> *** ../vim-7.4.1262/src/version.c 2016-02-05 21:04:02.820081559 +0100
> --- src/version.c 2016-02-05 21:34:01.308992175 +0100
> ***************
> *** 744,745 ****
> --- 744,747 ----
> { /* Add new patch number below this line */
> + /**/
> + 1263,
> /**/
>
> --
> hundred-and-one symptoms of being an internet addict:
> 145. You e-mail your boss, informing him you'll be late.
>
> /// 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 ///
I got error when I built gvim.exe:
channel.c: In function ‘channel_open’:
channel.c:424:39: error: ‘EINPROGRESS’ undeclared (first use in this function)
channel.c:424:39: note: each undeclared identifier is reported only once for
each function it appears in
Make_cyg_ming.mak:890: recipe for target 'gobji386/channel.o' failed
make: *** [gobji386/channel.o] Error 1
The command I'm using the following command as the command:
make -B -f Make_cyg.mak PYTHON=/cygdrive/c/Marslo/MyProgramFiles/Python27
DYNAMIC_PYTHON=yes PYTHON_VER=27
PYTHON3=/cygdrive/c/Marslo/MyProgramFiles/Python35 DYNAMIC_PYTHON3=yes
PYTHON3_VER=35 FEATURES=huge IME=yes GIME=yes MBYTE=yes CSCOPE=yes
USERNAME=Marslo.Jiao USERDOMAIN=China GUI=yes
Is there anything I should install in my cygwin?
Thanks in advance.
- marslo
--
--
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.