blob: 5a7e2a730138dad01e0ef812f17da267d3619bba [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaare0874f82016-01-24 20:36:41 +01002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 */
8
9/*
10 * Implements communication through a socket or any file handle.
11 */
12
13#include "vim.h"
14
Bram Moolenaar509ce2a2016-03-11 22:52:15 +010015#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +010016
Bram Moolenaard04a0202016-01-26 23:30:18 +010017/* TRUE when netbeans is running with a GUI. */
18#ifdef FEAT_GUI
19# define CH_HAS_GUI (gui.in_use || gui.starting)
20#endif
21
Bram Moolenaar3f7d0902016-11-12 21:13:42 +010022/* Note: when making changes here also adjust configure.ac. */
Bram Moolenaard04a0202016-01-26 23:30:18 +010023#ifdef WIN32
24/* WinSock API is separated from C API, thus we can't use read(), write(),
25 * errno... */
26# define SOCK_ERRNO errno = WSAGetLastError()
27# undef ECONNREFUSED
28# define ECONNREFUSED WSAECONNREFUSED
Bram Moolenaar4d919d72016-02-05 22:36:41 +010029# undef EWOULDBLOCK
30# define EWOULDBLOCK WSAEWOULDBLOCK
Bram Moolenaard42119f2016-02-28 20:51:49 +010031# undef EINPROGRESS
32# define EINPROGRESS WSAEINPROGRESS
Bram Moolenaard04a0202016-01-26 23:30:18 +010033# ifdef EINTR
34# undef EINTR
35# endif
36# define EINTR WSAEINTR
Bram Moolenaard8070362016-02-15 21:56:54 +010037# define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0)
38# define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0)
39# define sock_close(sd) closesocket((SOCKET)sd)
Bram Moolenaard04a0202016-01-26 23:30:18 +010040#else
41# include <netdb.h>
42# include <netinet/in.h>
43
44# include <sys/socket.h>
45# ifdef HAVE_LIBGEN_H
46# include <libgen.h>
47# endif
48# define SOCK_ERRNO
49# define sock_write(sd, buf, len) write(sd, buf, len)
50# define sock_read(sd, buf, len) read(sd, buf, len)
51# define sock_close(sd) close(sd)
Bram Moolenaar0943a092016-02-16 13:11:17 +010052# define fd_read(fd, buf, len) read(fd, buf, len)
Bram Moolenaard8070362016-02-15 21:56:54 +010053# define fd_write(sd, buf, len) write(sd, buf, len)
54# define fd_close(sd) close(sd)
Bram Moolenaard04a0202016-01-26 23:30:18 +010055#endif
56
Bram Moolenaardc0ccae2016-10-09 17:28:01 +020057static void channel_read(channel_T *channel, ch_part_T part, char *func);
Bram Moolenaarb2658a12016-04-26 17:16:24 +020058
Bram Moolenaar187db502016-02-27 14:44:26 +010059/* Whether a redraw is needed for appending a line to a buffer. */
60static int channel_need_redraw = FALSE;
61
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +020062/* Whether we are inside channel_parse_messages() or another situation where it
63 * is safe to invoke callbacks. */
64static int safe_to_invoke_callback = 0;
Bram Moolenaar187db502016-02-27 14:44:26 +010065
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +020066static char *part_names[] = {"sock", "out", "err", "in"};
67
Bram Moolenaard8070362016-02-15 21:56:54 +010068#ifdef WIN32
69 static int
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +010070fd_read(sock_T fd, char *buf, size_t len)
Bram Moolenaard8070362016-02-15 21:56:54 +010071{
72 HANDLE h = (HANDLE)fd;
73 DWORD nread;
74
75 if (!ReadFile(h, buf, (DWORD)len, &nread, NULL))
76 return -1;
77 return (int)nread;
78}
79
80 static int
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +010081fd_write(sock_T fd, char *buf, size_t len)
Bram Moolenaard8070362016-02-15 21:56:54 +010082{
83 HANDLE h = (HANDLE)fd;
84 DWORD nwrite;
85
86 if (!WriteFile(h, buf, (DWORD)len, &nwrite, NULL))
87 return -1;
88 return (int)nwrite;
89}
90
91 static void
92fd_close(sock_T fd)
93{
94 HANDLE h = (HANDLE)fd;
95
96 CloseHandle(h);
97}
98#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +010099
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100100/* Log file opened with ch_logfile(). */
101static FILE *log_fd = NULL;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100102#ifdef FEAT_RELTIME
103static proftime_T log_start;
104#endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100105
106 void
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100107ch_logfile(char_u *fname, char_u *opt)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100108{
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100109 FILE *file = NULL;
110
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100111 if (log_fd != NULL)
112 fclose(log_fd);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100113
114 if (*fname != NUL)
115 {
116 file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
117 if (file == NULL)
118 {
119 EMSG2(_(e_notopen), fname);
120 return;
121 }
122 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100123 log_fd = file;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100124
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100125 if (log_fd != NULL)
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100126 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100127 fprintf(log_fd, "==== start log session ====\n");
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100128#ifdef FEAT_RELTIME
129 profile_start(&log_start);
130#endif
131 }
132}
133
134 int
Bram Moolenaarcf089462016-06-12 21:18:43 +0200135ch_log_active(void)
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100136{
137 return log_fd != NULL;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100138}
139
140 static void
Bram Moolenaar77073442016-02-13 23:23:53 +0100141ch_log_lead(char *what, channel_T *ch)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100142{
143 if (log_fd != NULL)
144 {
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100145#ifdef FEAT_RELTIME
146 proftime_T log_now;
147
148 profile_start(&log_now);
149 profile_sub(&log_now, &log_start);
150 fprintf(log_fd, "%s ", profile_msg(&log_now));
151#endif
Bram Moolenaar77073442016-02-13 23:23:53 +0100152 if (ch != NULL)
153 fprintf(log_fd, "%son %d: ", what, ch->ch_id);
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100154 else
155 fprintf(log_fd, "%s: ", what);
156 }
157}
158
Bram Moolenaard0b65022016-03-06 21:50:33 +0100159static int did_log_msg = TRUE;
160
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100161 void
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200162ch_log(channel_T *ch, const char *fmt, ...)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100163{
164 if (log_fd != NULL)
165 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200166 va_list ap;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100167
Bram Moolenaar77073442016-02-13 23:23:53 +0100168 ch_log_lead("", ch);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200169 va_start(ap, fmt);
170 vfprintf(log_fd, fmt, ap);
171 va_end(ap);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100172 fputc('\n', log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100173 fflush(log_fd);
Bram Moolenaard0b65022016-03-06 21:50:33 +0100174 did_log_msg = TRUE;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100175 }
176}
177
178 static void
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200179ch_error(channel_T *ch, const char *fmt, ...)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100180{
181 if (log_fd != NULL)
182 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200183 va_list ap;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100184
Bram Moolenaar77073442016-02-13 23:23:53 +0100185 ch_log_lead("ERR ", ch);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200186 va_start(ap, fmt);
187 vfprintf(log_fd, fmt, ap);
188 va_end(ap);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100189 fputc('\n', log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100190 fflush(log_fd);
Bram Moolenaard0b65022016-03-06 21:50:33 +0100191 did_log_msg = TRUE;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100192 }
193}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100194
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100195#ifdef _WIN32
196# undef PERROR
197# define PERROR(msg) (void)emsg3((char_u *)"%s: %s", \
198 (char_u *)msg, (char_u *)strerror_win32(errno))
199
200 static char *
201strerror_win32(int eno)
202{
203 static LPVOID msgbuf = NULL;
204 char_u *ptr;
205
206 if (msgbuf)
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200207 {
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100208 LocalFree(msgbuf);
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200209 msgbuf = NULL;
210 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100211 FormatMessage(
212 FORMAT_MESSAGE_ALLOCATE_BUFFER |
213 FORMAT_MESSAGE_FROM_SYSTEM |
214 FORMAT_MESSAGE_IGNORE_INSERTS,
215 NULL,
216 eno,
217 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
218 (LPTSTR) &msgbuf,
219 0,
220 NULL);
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200221 if (msgbuf != NULL)
222 /* chomp \r or \n */
223 for (ptr = (char_u *)msgbuf; *ptr; ptr++)
224 switch (*ptr)
225 {
226 case '\r':
227 STRMOVE(ptr, ptr + 1);
228 ptr--;
229 break;
230 case '\n':
231 if (*(ptr + 1) == '\0')
232 *ptr = '\0';
233 else
234 *ptr = ' ';
235 break;
236 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100237 return msgbuf;
238}
239#endif
240
Bram Moolenaar77073442016-02-13 23:23:53 +0100241/*
242 * The list of all allocated channels.
243 */
244static channel_T *first_channel = NULL;
245static int next_ch_id = 0;
246
247/*
248 * Allocate a new channel. The refcount is set to 1.
249 * The channel isn't actually used until it is opened.
250 * Returns NULL if out of memory.
251 */
252 channel_T *
253add_channel(void)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100254{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200255 ch_part_T part;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100256 channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T));
Bram Moolenaare0874f82016-01-24 20:36:41 +0100257
Bram Moolenaar77073442016-02-13 23:23:53 +0100258 if (channel == NULL)
259 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100260
Bram Moolenaar77073442016-02-13 23:23:53 +0100261 channel->ch_id = next_ch_id++;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100262 ch_log(channel, "Created channel");
Bram Moolenaar77073442016-02-13 23:23:53 +0100263
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200264 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100265 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100266 channel->ch_part[part].ch_fd = INVALID_FD;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100267#ifdef FEAT_GUI_X11
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100268 channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100269#endif
270#ifdef FEAT_GUI_GTK
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100271 channel->ch_part[part].ch_inputHandler = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100272#endif
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100273 channel->ch_part[part].ch_timeout = 2000;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100274 }
Bram Moolenaare0874f82016-01-24 20:36:41 +0100275
Bram Moolenaar77073442016-02-13 23:23:53 +0100276 if (first_channel != NULL)
277 {
278 first_channel->ch_prev = channel;
279 channel->ch_next = first_channel;
280 }
281 first_channel = channel;
282
283 channel->ch_refcount = 1;
284 return channel;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100285}
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100286
Bram Moolenaarb9c31e72016-09-29 15:18:57 +0200287 int
288has_any_channel(void)
289{
290 return first_channel != NULL;
291}
292
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100293/*
Bram Moolenaard6051b52016-02-28 15:49:03 +0100294 * Called when the refcount of a channel is zero.
Bram Moolenaar46c85432016-02-26 11:17:46 +0100295 * Return TRUE if "channel" has a callback and the associated job wasn't
296 * killed.
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100297 */
298 static int
Bram Moolenaar46c85432016-02-26 11:17:46 +0100299channel_still_useful(channel_T *channel)
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100300{
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100301 int has_sock_msg;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100302 int has_out_msg;
303 int has_err_msg;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100304
305 /* If the job was killed the channel is not expected to work anymore. */
Bram Moolenaar46c85432016-02-26 11:17:46 +0100306 if (channel->ch_job_killed && channel->ch_job == NULL)
307 return FALSE;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100308
309 /* If there is a close callback it may still need to be invoked. */
310 if (channel->ch_close_cb != NULL)
311 return TRUE;
312
Bram Moolenaar5d96e3a2016-05-08 21:47:01 +0200313 /* If reading from or a buffer it's still useful. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200314 if (channel->ch_part[PART_IN].ch_bufref.br_buf != NULL)
Bram Moolenaar5d96e3a2016-05-08 21:47:01 +0200315 return TRUE;
316
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100317 /* If there is no callback then nobody can get readahead. If the fd is
318 * closed and there is no readahead then the callback won't be called. */
319 has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD
320 || channel->ch_part[PART_SOCK].ch_head.rq_next != NULL
321 || channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100322 has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD
323 || channel->ch_part[PART_OUT].ch_head.rq_next != NULL
324 || channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL;
325 has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
326 || channel->ch_part[PART_ERR].ch_head.rq_next != NULL
327 || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100328 return (channel->ch_callback != NULL && (has_sock_msg
Bram Moolenaar509ce2a2016-03-11 22:52:15 +0100329 || has_out_msg || has_err_msg))
Bram Moolenaar5d96e3a2016-05-08 21:47:01 +0200330 || ((channel->ch_part[PART_OUT].ch_callback != NULL
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200331 || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
332 && has_out_msg)
Bram Moolenaar5d96e3a2016-05-08 21:47:01 +0200333 || ((channel->ch_part[PART_ERR].ch_callback != NULL
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200334 || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
335 && has_err_msg);
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100336}
337
338/*
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200339 * Close a channel and free all its resources.
340 */
341 static void
342channel_free_contents(channel_T *channel)
343{
344 channel_close(channel, TRUE);
345 channel_clear(channel);
346 ch_log(channel, "Freeing channel");
347}
348
349 static void
350channel_free_channel(channel_T *channel)
351{
352 if (channel->ch_next != NULL)
353 channel->ch_next->ch_prev = channel->ch_prev;
354 if (channel->ch_prev == NULL)
355 first_channel = channel->ch_next;
356 else
357 channel->ch_prev->ch_next = channel->ch_next;
358 vim_free(channel);
359}
360
361 static void
362channel_free(channel_T *channel)
363{
364 if (!in_free_unref_items)
365 {
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200366 if (safe_to_invoke_callback == 0)
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200367 channel->ch_to_be_freed = TRUE;
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200368 else
369 {
370 channel_free_contents(channel);
371 channel_free_channel(channel);
372 }
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200373 }
374}
375
376/*
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100377 * Close a channel and free all its resources if there is no further action
Bram Moolenaar46c85432016-02-26 11:17:46 +0100378 * possible, there is no callback to be invoked or the associated job was
379 * killed.
Bram Moolenaar70765942016-02-28 19:28:59 +0100380 * Return TRUE if the channel was freed.
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100381 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100382 static int
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100383channel_may_free(channel_T *channel)
384{
Bram Moolenaar46c85432016-02-26 11:17:46 +0100385 if (!channel_still_useful(channel))
Bram Moolenaar70765942016-02-28 19:28:59 +0100386 {
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100387 channel_free(channel);
Bram Moolenaar70765942016-02-28 19:28:59 +0100388 return TRUE;
389 }
390 return FALSE;
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100391}
392
393/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100394 * Decrement the reference count on "channel" and maybe free it when it goes
395 * down to zero. Don't free it if there is a pending action.
396 * Returns TRUE when the channel is no longer referenced.
397 */
398 int
399channel_unref(channel_T *channel)
400{
401 if (channel != NULL && --channel->ch_refcount <= 0)
402 return channel_may_free(channel);
403 return FALSE;
404}
405
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200406 int
407free_unused_channels_contents(int copyID, int mask)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100408{
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200409 int did_free = FALSE;
410 channel_T *ch;
411
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200412 /* This is invoked from the garbage collector, which only runs at a safe
413 * point. */
414 ++safe_to_invoke_callback;
415
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200416 for (ch = first_channel; ch != NULL; ch = ch->ch_next)
Bram Moolenaar674127e2016-04-26 20:30:07 +0200417 if (!channel_still_useful(ch)
418 && (ch->ch_copyID & mask) != (copyID & mask))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200419 {
420 /* Free the channel and ordinary items it contains, but don't
421 * recurse into Lists, Dictionaries etc. */
422 channel_free_contents(ch);
423 did_free = TRUE;
424 }
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200425
426 --safe_to_invoke_callback;
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200427 return did_free;
428}
429
430 void
431free_unused_channels(int copyID, int mask)
432{
433 channel_T *ch;
434 channel_T *ch_next;
435
436 for (ch = first_channel; ch != NULL; ch = ch_next)
437 {
438 ch_next = ch->ch_next;
Bram Moolenaar674127e2016-04-26 20:30:07 +0200439 if (!channel_still_useful(ch)
440 && (ch->ch_copyID & mask) != (copyID & mask))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200441 {
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +0200442 /* Free the channel struct itself. */
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200443 channel_free_channel(ch);
444 }
445 }
Bram Moolenaare0874f82016-01-24 20:36:41 +0100446}
447
Bram Moolenaard04a0202016-01-26 23:30:18 +0100448#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar77073442016-02-13 23:23:53 +0100449
450#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
451 static void
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100452channel_read_fd(int fd)
Bram Moolenaar77073442016-02-13 23:23:53 +0100453{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100454 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200455 ch_part_T part;
Bram Moolenaar77073442016-02-13 23:23:53 +0100456
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100457 channel = channel_fd2channel(fd, &part);
Bram Moolenaar77073442016-02-13 23:23:53 +0100458 if (channel == NULL)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200459 ch_error(NULL, "Channel for fd %d not found", fd);
Bram Moolenaar77073442016-02-13 23:23:53 +0100460 else
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200461 channel_read(channel, part, "channel_read_fd");
Bram Moolenaar77073442016-02-13 23:23:53 +0100462}
463#endif
464
Bram Moolenaare0874f82016-01-24 20:36:41 +0100465/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100466 * Read a command from netbeans.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100467 */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100468#ifdef FEAT_GUI_X11
469 static void
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200470messageFromServer(XtPointer clientData,
471 int *unused1 UNUSED,
472 XtInputId *unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100473{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100474 channel_read_fd((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100475}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100476#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100477
Bram Moolenaard04a0202016-01-26 23:30:18 +0100478#ifdef FEAT_GUI_GTK
Bram Moolenaar98921892016-02-23 17:14:37 +0100479# if GTK_CHECK_VERSION(3,0,0)
480 static gboolean
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200481messageFromServer(GIOChannel *unused1 UNUSED,
482 GIOCondition unused2 UNUSED,
483 gpointer clientData)
Bram Moolenaar98921892016-02-23 17:14:37 +0100484{
485 channel_read_fd(GPOINTER_TO_INT(clientData));
486 return TRUE; /* Return FALSE instead in case the event source is to
487 * be removed after this function returns. */
488}
489# else
Bram Moolenaard04a0202016-01-26 23:30:18 +0100490 static void
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200491messageFromServer(gpointer clientData,
492 gint unused1 UNUSED,
493 GdkInputCondition unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100494{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100495 channel_read_fd((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100496}
Bram Moolenaar98921892016-02-23 17:14:37 +0100497# endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100498#endif
499
500 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200501channel_gui_register_one(channel_T *channel, ch_part_T part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100502{
Bram Moolenaarde279892016-03-11 22:19:44 +0100503 if (!CH_HAS_GUI)
504 return;
505
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200506 /* gets stuck in handling events for a not connected channel */
507 if (channel->ch_keep_open)
508 return;
509
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100510# ifdef FEAT_GUI_X11
511 /* Tell notifier we are interested in being called
512 * when there is input on the editor connection socket. */
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100513 if (channel->ch_part[part].ch_inputHandler == (XtInputId)NULL)
514 channel->ch_part[part].ch_inputHandler = XtAppAddInput(
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100515 (XtAppContext)app_context,
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100516 channel->ch_part[part].ch_fd,
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100517 (XtPointer)(XtInputReadMask + XtInputExceptMask),
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200518 messageFromServer,
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100519 (XtPointer)(long)channel->ch_part[part].ch_fd);
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100520# else
521# ifdef FEAT_GUI_GTK
522 /* Tell gdk we are interested in being called when there
523 * is input on the editor connection socket. */
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100524 if (channel->ch_part[part].ch_inputHandler == 0)
Bram Moolenaar98921892016-02-23 17:14:37 +0100525# if GTK_CHECK_VERSION(3,0,0)
526 {
527 GIOChannel *chnnl = g_io_channel_unix_new(
528 (gint)channel->ch_part[part].ch_fd);
529
530 channel->ch_part[part].ch_inputHandler = g_io_add_watch(
531 chnnl,
532 G_IO_IN|G_IO_HUP|G_IO_ERR|G_IO_PRI,
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200533 messageFromServer,
Bram Moolenaar98921892016-02-23 17:14:37 +0100534 GINT_TO_POINTER(channel->ch_part[part].ch_fd));
535
536 g_io_channel_unref(chnnl);
537 }
538# else
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100539 channel->ch_part[part].ch_inputHandler = gdk_input_add(
540 (gint)channel->ch_part[part].ch_fd,
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100541 (GdkInputCondition)
542 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200543 messageFromServer,
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100544 (gpointer)(long)channel->ch_part[part].ch_fd);
Bram Moolenaar98921892016-02-23 17:14:37 +0100545# endif
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100546# endif
547# endif
548}
549
Bram Moolenaarde279892016-03-11 22:19:44 +0100550 static void
Bram Moolenaar77073442016-02-13 23:23:53 +0100551channel_gui_register(channel_T *channel)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100552{
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100553 if (channel->CH_SOCK_FD != INVALID_FD)
554 channel_gui_register_one(channel, PART_SOCK);
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200555 if (channel->CH_OUT_FD != INVALID_FD
556 && channel->CH_OUT_FD != channel->CH_SOCK_FD)
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100557 channel_gui_register_one(channel, PART_OUT);
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200558 if (channel->CH_ERR_FD != INVALID_FD
559 && channel->CH_ERR_FD != channel->CH_SOCK_FD
560 && channel->CH_ERR_FD != channel->CH_OUT_FD)
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100561 channel_gui_register_one(channel, PART_ERR);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100562}
563
564/*
565 * Register any of our file descriptors with the GUI event handling system.
566 * Called when the GUI has started.
567 */
568 void
569channel_gui_register_all(void)
570{
Bram Moolenaar77073442016-02-13 23:23:53 +0100571 channel_T *channel;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100572
Bram Moolenaar77073442016-02-13 23:23:53 +0100573 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100574 channel_gui_register(channel);
575}
576
577 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200578channel_gui_unregister_one(channel_T *channel, ch_part_T part)
Bram Moolenaarde279892016-03-11 22:19:44 +0100579{
580# ifdef FEAT_GUI_X11
581 if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL)
582 {
583 XtRemoveInput(channel->ch_part[part].ch_inputHandler);
584 channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
585 }
586# else
587# ifdef FEAT_GUI_GTK
588 if (channel->ch_part[part].ch_inputHandler != 0)
589 {
590# if GTK_CHECK_VERSION(3,0,0)
591 g_source_remove(channel->ch_part[part].ch_inputHandler);
592# else
593 gdk_input_remove(channel->ch_part[part].ch_inputHandler);
594# endif
595 channel->ch_part[part].ch_inputHandler = 0;
596 }
597# endif
598# endif
599}
600
601 static void
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100602channel_gui_unregister(channel_T *channel)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100603{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200604 ch_part_T part;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100605
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100606 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaarde279892016-03-11 22:19:44 +0100607 channel_gui_unregister_one(channel, part);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100608}
609
610#endif
611
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100612static char *e_cannot_connect = N_("E902: Cannot connect to port");
613
Bram Moolenaard04a0202016-01-26 23:30:18 +0100614/*
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100615 * Open a socket channel to "hostname":"port".
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100616 * "waittime" is the time in msec to wait for the connection.
617 * When negative wait forever.
Bram Moolenaar77073442016-02-13 23:23:53 +0100618 * Returns the channel for success.
619 * Returns NULL for failure.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100620 */
Bram Moolenaar77073442016-02-13 23:23:53 +0100621 channel_T *
Bram Moolenaar4e221c92016-02-23 13:20:22 +0100622channel_open(
623 char *hostname,
624 int port_in,
625 int waittime,
626 void (*nb_close_cb)(void))
Bram Moolenaard04a0202016-01-26 23:30:18 +0100627{
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100628 int sd = -1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100629 struct sockaddr_in server;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100630 struct hostent *host;
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100631#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100632 u_short port = port_in;
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100633 u_long val = 1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100634#else
635 int port = port_in;
636#endif
Bram Moolenaar77073442016-02-13 23:23:53 +0100637 channel_T *channel;
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100638 int ret;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100639
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100640#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100641 channel_init_winsock();
642#endif
643
Bram Moolenaar77073442016-02-13 23:23:53 +0100644 channel = add_channel();
645 if (channel == NULL)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100646 {
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100647 ch_error(NULL, "Cannot allocate channel.");
Bram Moolenaar77073442016-02-13 23:23:53 +0100648 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100649 }
650
651 /* Get the server internet address and put into addr structure */
652 /* fill in the socket address structure and connect to server */
653 vim_memset((char *)&server, 0, sizeof(server));
654 server.sin_family = AF_INET;
655 server.sin_port = htons(port);
656 if ((host = gethostbyname(hostname)) == NULL)
657 {
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100658 ch_error(channel, "in gethostbyname() in channel_open()");
Bram Moolenaar5b302912016-08-24 22:11:55 +0200659 PERROR(_("E901: gethostbyname() in channel_open()"));
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100660 channel_free(channel);
Bram Moolenaar77073442016-02-13 23:23:53 +0100661 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100662 }
Bram Moolenaar7173b472017-01-14 17:04:38 +0100663 {
664 char *p;
665
666 /* When using host->h_addr directly ubsan warns for it to not be
667 * aligned. First copy the pointer to aviod that. */
668 memcpy(&p, &host->h_addr, sizeof(p));
669 memcpy((char *)&server.sin_addr, p, host->h_length);
670 }
Bram Moolenaard04a0202016-01-26 23:30:18 +0100671
Bram Moolenaar254e00d2016-02-19 23:23:12 +0100672 /* On Mac and Solaris a zero timeout almost never works. At least wait
673 * one millisecond. Let's do it for all systems, because we don't know why
674 * this is needed. */
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100675 if (waittime == 0)
676 waittime = 1;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100677
678 /*
679 * For Unix we need to call connect() again after connect() failed.
680 * On Win32 one time is sufficient.
681 */
682 while (TRUE)
683 {
Bram Moolenaar562ca712016-03-09 21:50:05 +0100684 long elapsed_msec = 0;
685 int waitnow;
Bram Moolenaar045a2842016-03-08 22:33:07 +0100686
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100687 if (sd >= 0)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100688 sock_close(sd);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100689 sd = socket(AF_INET, SOCK_STREAM, 0);
690 if (sd == -1)
691 {
692 ch_error(channel, "in socket() in channel_open().");
Bram Moolenaar5b302912016-08-24 22:11:55 +0200693 PERROR(_("E898: socket() in channel_open()"));
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100694 channel_free(channel);
Bram Moolenaar77073442016-02-13 23:23:53 +0100695 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100696 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100697
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100698 if (waittime >= 0)
699 {
700 /* Make connect() non-blocking. */
701 if (
702#ifdef _WIN32
703 ioctlsocket(sd, FIONBIO, &val) < 0
704#else
705 fcntl(sd, F_SETFL, O_NONBLOCK) < 0
706#endif
707 )
708 {
709 SOCK_ERRNO;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200710 ch_error(channel,
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100711 "channel_open: Connect failed with errno %d", errno);
712 sock_close(sd);
713 channel_free(channel);
714 return NULL;
715 }
716 }
717
718 /* Try connecting to the server. */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200719 ch_log(channel, "Connecting to %s port %d", hostname, port);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100720 ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
721
Bram Moolenaar045a2842016-03-08 22:33:07 +0100722 if (ret == 0)
723 /* The connection could be established. */
724 break;
725
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100726 SOCK_ERRNO;
Bram Moolenaar045a2842016-03-08 22:33:07 +0100727 if (waittime < 0 || (errno != EWOULDBLOCK
728 && errno != ECONNREFUSED
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100729#ifdef EINPROGRESS
Bram Moolenaar045a2842016-03-08 22:33:07 +0100730 && errno != EINPROGRESS
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100731#endif
Bram Moolenaar045a2842016-03-08 22:33:07 +0100732 ))
733 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200734 ch_error(channel,
Bram Moolenaar045a2842016-03-08 22:33:07 +0100735 "channel_open: Connect failed with errno %d", errno);
736 PERROR(_(e_cannot_connect));
737 sock_close(sd);
738 channel_free(channel);
739 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100740 }
Bram Moolenaard04a0202016-01-26 23:30:18 +0100741
Bram Moolenaar40e8cb22016-03-10 21:10:58 +0100742 /* Limit the waittime to 50 msec. If it doesn't work within this
743 * time we close the socket and try creating it again. */
744 waitnow = waittime > 50 ? 50 : waittime;
745
Bram Moolenaar045a2842016-03-08 22:33:07 +0100746 /* If connect() didn't finish then try using select() to wait for the
Bram Moolenaar562ca712016-03-09 21:50:05 +0100747 * connection to be made. For Win32 always use select() to wait. */
Bram Moolenaar045a2842016-03-08 22:33:07 +0100748#ifndef WIN32
749 if (errno != ECONNREFUSED)
750#endif
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100751 {
752 struct timeval tv;
Bram Moolenaard42119f2016-02-28 20:51:49 +0100753 fd_set rfds;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100754 fd_set wfds;
Bram Moolenaare081e212016-02-28 22:33:46 +0100755#ifndef WIN32
Bram Moolenaard42119f2016-02-28 20:51:49 +0100756 int so_error = 0;
757 socklen_t so_error_len = sizeof(so_error);
Bram Moolenaar045a2842016-03-08 22:33:07 +0100758 struct timeval start_tv;
759 struct timeval end_tv;
Bram Moolenaare081e212016-02-28 22:33:46 +0100760#endif
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100761 FD_ZERO(&rfds);
762 FD_SET(sd, &rfds);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100763 FD_ZERO(&wfds);
764 FD_SET(sd, &wfds);
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100765
Bram Moolenaar562ca712016-03-09 21:50:05 +0100766 tv.tv_sec = waitnow / 1000;
767 tv.tv_usec = (waitnow % 1000) * 1000;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100768#ifndef WIN32
769 gettimeofday(&start_tv, NULL);
770#endif
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200771 ch_log(channel,
Bram Moolenaar562ca712016-03-09 21:50:05 +0100772 "Waiting for connection (waiting %d msec)...", waitnow);
Bram Moolenaard42119f2016-02-28 20:51:49 +0100773 ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100774
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100775 if (ret < 0)
776 {
777 SOCK_ERRNO;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200778 ch_error(channel,
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100779 "channel_open: Connect failed with errno %d", errno);
780 PERROR(_(e_cannot_connect));
781 sock_close(sd);
782 channel_free(channel);
783 return NULL;
784 }
Bram Moolenaard42119f2016-02-28 20:51:49 +0100785
Bram Moolenaare081e212016-02-28 22:33:46 +0100786#ifdef WIN32
Bram Moolenaar562ca712016-03-09 21:50:05 +0100787 /* On Win32: select() is expected to work and wait for up to
788 * "waitnow" msec for the socket to be open. */
Bram Moolenaar045a2842016-03-08 22:33:07 +0100789 if (FD_ISSET(sd, &wfds))
790 break;
Bram Moolenaar562ca712016-03-09 21:50:05 +0100791 elapsed_msec = waitnow;
792 if (waittime > 1 && elapsed_msec < waittime)
793 {
794 waittime -= elapsed_msec;
795 continue;
796 }
Bram Moolenaare081e212016-02-28 22:33:46 +0100797#else
798 /* On Linux-like systems: See socket(7) for the behavior
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100799 * After putting the socket in non-blocking mode, connect() will
800 * return EINPROGRESS, select() will not wait (as if writing is
801 * possible), need to use getsockopt() to check if the socket is
Bram Moolenaar42bc6dd2016-03-02 20:48:47 +0100802 * actually able to connect.
Bram Moolenaar045a2842016-03-08 22:33:07 +0100803 * We detect a failure to connect when either read and write fds
Bram Moolenaard42119f2016-02-28 20:51:49 +0100804 * are set. Use getsockopt() to find out what kind of failure. */
Bram Moolenaar42bc6dd2016-03-02 20:48:47 +0100805 if (FD_ISSET(sd, &rfds) || FD_ISSET(sd, &wfds))
Bram Moolenaard42119f2016-02-28 20:51:49 +0100806 {
807 ret = getsockopt(sd,
Bram Moolenaar045a2842016-03-08 22:33:07 +0100808 SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
Bram Moolenaard42119f2016-02-28 20:51:49 +0100809 if (ret < 0 || (so_error != 0
810 && so_error != EWOULDBLOCK
811 && so_error != ECONNREFUSED
Bram Moolenaare081e212016-02-28 22:33:46 +0100812# ifdef EINPROGRESS
Bram Moolenaard42119f2016-02-28 20:51:49 +0100813 && so_error != EINPROGRESS
Bram Moolenaare081e212016-02-28 22:33:46 +0100814# endif
Bram Moolenaard42119f2016-02-28 20:51:49 +0100815 ))
816 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200817 ch_error(channel,
Bram Moolenaard42119f2016-02-28 20:51:49 +0100818 "channel_open: Connect failed with errno %d",
819 so_error);
820 PERROR(_(e_cannot_connect));
821 sock_close(sd);
822 channel_free(channel);
823 return NULL;
824 }
825 }
826
Bram Moolenaar045a2842016-03-08 22:33:07 +0100827 if (FD_ISSET(sd, &wfds) && so_error == 0)
828 /* Did not detect an error, connection is established. */
829 break;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100830
Bram Moolenaar045a2842016-03-08 22:33:07 +0100831 gettimeofday(&end_tv, NULL);
832 elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000
833 + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100834#endif
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100835 }
Bram Moolenaar045a2842016-03-08 22:33:07 +0100836
837#ifndef WIN32
838 if (waittime > 1 && elapsed_msec < waittime)
839 {
840 /* The port isn't ready but we also didn't get an error.
841 * This happens when the server didn't open the socket
Bram Moolenaar562ca712016-03-09 21:50:05 +0100842 * yet. Select() may return early, wait until the remaining
843 * "waitnow" and try again. */
844 waitnow -= elapsed_msec;
845 waittime -= elapsed_msec;
846 if (waitnow > 0)
847 {
848 mch_delay((long)waitnow, TRUE);
849 ui_breakcheck();
850 waittime -= waitnow;
851 }
Bram Moolenaar045a2842016-03-08 22:33:07 +0100852 if (!got_int)
853 {
Bram Moolenaar562ca712016-03-09 21:50:05 +0100854 if (waittime <= 0)
855 /* give it one more try */
Bram Moolenaar045a2842016-03-08 22:33:07 +0100856 waittime = 1;
857 continue;
858 }
859 /* we were interrupted, behave as if timed out */
860 }
861#endif
862
863 /* We timed out. */
864 ch_error(channel, "Connection timed out");
865 sock_close(sd);
866 channel_free(channel);
867 return NULL;
Bram Moolenaar7a84dbe2016-02-07 21:29:00 +0100868 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100869
Bram Moolenaar045a2842016-03-08 22:33:07 +0100870 ch_log(channel, "Connection made");
871
Bram Moolenaar7a84dbe2016-02-07 21:29:00 +0100872 if (waittime >= 0)
873 {
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100874#ifdef _WIN32
875 val = 0;
876 ioctlsocket(sd, FIONBIO, &val);
877#else
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +0100878 (void)fcntl(sd, F_SETFL, 0);
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100879#endif
880 }
881
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100882 channel->CH_SOCK_FD = (sock_T)sd;
Bram Moolenaar4e221c92016-02-23 13:20:22 +0100883 channel->ch_nb_close_cb = nb_close_cb;
Bram Moolenaar03602ec2016-03-20 20:57:45 +0100884 channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
885 channel->ch_port = port_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200886 channel->ch_to_be_closed |= (1 << PART_SOCK);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100887
888#ifdef FEAT_GUI
Bram Moolenaarde279892016-03-11 22:19:44 +0100889 channel_gui_register_one(channel, PART_SOCK);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100890#endif
891
Bram Moolenaar77073442016-02-13 23:23:53 +0100892 return channel;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100893}
894
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100895/*
896 * Implements ch_open().
897 */
898 channel_T *
899channel_open_func(typval_T *argvars)
900{
901 char_u *address;
902 char_u *p;
903 char *rest;
904 int port;
905 jobopt_T opt;
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +0200906 channel_T *channel = NULL;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100907
908 address = get_tv_string(&argvars[0]);
909 if (argvars[1].v_type != VAR_UNKNOWN
910 && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
911 {
912 EMSG(_(e_invarg));
913 return NULL;
914 }
915
916 /* parse address */
917 p = vim_strchr(address, ':');
918 if (p == NULL)
919 {
920 EMSG2(_(e_invarg2), address);
921 return NULL;
922 }
923 *p++ = NUL;
924 port = strtol((char *)p, &rest, 10);
925 if (*address == NUL || port <= 0 || *rest != NUL)
926 {
927 p[-1] = ':';
928 EMSG2(_(e_invarg2), address);
929 return NULL;
930 }
931
932 /* parse options */
933 clear_job_options(&opt);
934 opt.jo_mode = MODE_JSON;
935 opt.jo_timeout = 2000;
936 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +0200937 JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +0200938 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100939 if (opt.jo_timeout < 0)
940 {
941 EMSG(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +0200942 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100943 }
944
945 channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
946 if (channel != NULL)
947 {
948 opt.jo_set = JO_ALL;
949 channel_set_options(channel, &opt);
950 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +0200951theend:
952 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100953 return channel;
954}
955
Bram Moolenaarde279892016-03-11 22:19:44 +0100956 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200957ch_close_part(channel_T *channel, ch_part_T part)
Bram Moolenaarde279892016-03-11 22:19:44 +0100958{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200959 sock_T *fd = &channel->ch_part[part].ch_fd;
960
Bram Moolenaarde279892016-03-11 22:19:44 +0100961 if (*fd != INVALID_FD)
962 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200963 if (part == PART_SOCK)
964 sock_close(*fd);
965 else
Bram Moolenaar5a1feb82017-07-22 18:04:08 +0200966 {
967 /* When using a pty the same FD is set on multiple parts, only
968 * close it when the last reference is closed. */
Bram Moolenaar7c9aec42017-08-03 13:51:25 +0200969 if ((part == PART_IN || channel->CH_IN_FD != *fd)
970 && (part == PART_OUT || channel->CH_OUT_FD != *fd)
971 && (part == PART_ERR || channel->CH_ERR_FD != *fd))
Bram Moolenaar5a1feb82017-07-22 18:04:08 +0200972 fd_close(*fd);
973 }
Bram Moolenaarde279892016-03-11 22:19:44 +0100974 *fd = INVALID_FD;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200975
976 channel->ch_to_be_closed &= ~(1 << part);
Bram Moolenaarde279892016-03-11 22:19:44 +0100977 }
978}
979
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100980 void
Bram Moolenaard8070362016-02-15 21:56:54 +0100981channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100982{
Bram Moolenaarde279892016-03-11 22:19:44 +0100983 if (in != INVALID_FD)
984 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200985 ch_close_part(channel, PART_IN);
Bram Moolenaarde279892016-03-11 22:19:44 +0100986 channel->CH_IN_FD = in;
987 }
988 if (out != INVALID_FD)
989 {
990# if defined(FEAT_GUI)
991 channel_gui_unregister_one(channel, PART_OUT);
992# endif
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200993 ch_close_part(channel, PART_OUT);
Bram Moolenaarde279892016-03-11 22:19:44 +0100994 channel->CH_OUT_FD = out;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200995 channel->ch_to_be_closed |= (1 << PART_OUT);
Bram Moolenaarde279892016-03-11 22:19:44 +0100996# if defined(FEAT_GUI)
997 channel_gui_register_one(channel, PART_OUT);
998# endif
999 }
1000 if (err != INVALID_FD)
1001 {
1002# if defined(FEAT_GUI)
1003 channel_gui_unregister_one(channel, PART_ERR);
1004# endif
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001005 ch_close_part(channel, PART_ERR);
Bram Moolenaarde279892016-03-11 22:19:44 +01001006 channel->CH_ERR_FD = err;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001007 channel->ch_to_be_closed |= (1 << PART_ERR);
Bram Moolenaarde279892016-03-11 22:19:44 +01001008# if defined(FEAT_GUI)
1009 channel_gui_register_one(channel, PART_ERR);
1010# endif
1011 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001012}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001013
Bram Moolenaard6051b52016-02-28 15:49:03 +01001014/*
Bram Moolenaar014069a2016-03-03 22:51:40 +01001015 * Sets the job the channel is associated with and associated options.
Bram Moolenaard6051b52016-02-28 15:49:03 +01001016 * This does not keep a refcount, when the job is freed ch_job is cleared.
1017 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001018 void
Bram Moolenaar014069a2016-03-03 22:51:40 +01001019channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001020{
Bram Moolenaar77073442016-02-13 23:23:53 +01001021 channel->ch_job = job;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001022
1023 channel_set_options(channel, options);
1024
1025 if (job->jv_in_buf != NULL)
1026 {
1027 chanpart_T *in_part = &channel->ch_part[PART_IN];
1028
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001029 set_bufref(&in_part->ch_bufref, job->jv_in_buf);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001030 ch_log(channel, "reading from buffer '%s'",
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001031 (char *)in_part->ch_bufref.br_buf->b_ffname);
Bram Moolenaar014069a2016-03-03 22:51:40 +01001032 if (options->jo_set & JO_IN_TOP)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001033 {
1034 if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT))
1035 {
1036 /* Special mode: send last-but-one line when appending a line
1037 * to the buffer. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001038 in_part->ch_bufref.br_buf->b_write_to_channel = TRUE;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001039 in_part->ch_buf_append = TRUE;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001040 in_part->ch_buf_top =
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001041 in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001042 }
1043 else
1044 in_part->ch_buf_top = options->jo_in_top;
1045 }
Bram Moolenaar014069a2016-03-03 22:51:40 +01001046 else
1047 in_part->ch_buf_top = 1;
1048 if (options->jo_set & JO_IN_BOT)
1049 in_part->ch_buf_bot = options->jo_in_bot;
1050 else
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001051 in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001052 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01001053}
1054
1055/*
Bram Moolenaar187db502016-02-27 14:44:26 +01001056 * Find a buffer matching "name" or create a new one.
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001057 * Returns NULL if there is something very wrong (error already reported).
Bram Moolenaar187db502016-02-27 14:44:26 +01001058 */
1059 static buf_T *
Bram Moolenaar169ebb02016-09-07 23:32:23 +02001060find_buffer(char_u *name, int err, int msg)
Bram Moolenaar187db502016-02-27 14:44:26 +01001061{
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01001062 buf_T *buf = NULL;
Bram Moolenaar187db502016-02-27 14:44:26 +01001063 buf_T *save_curbuf = curbuf;
1064
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01001065 if (name != NULL && *name != NUL)
Bram Moolenaarb127cfd2016-05-29 16:24:50 +02001066 {
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01001067 buf = buflist_findname(name);
Bram Moolenaarb127cfd2016-05-29 16:24:50 +02001068 if (buf == NULL)
1069 buf = buflist_findname_exp(name);
1070 }
Bram Moolenaar187db502016-02-27 14:44:26 +01001071 if (buf == NULL)
1072 {
Bram Moolenaare26643e2016-02-27 21:53:02 +01001073 buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
Bram Moolenaarb127cfd2016-05-29 16:24:50 +02001074 NULL, (linenr_T)0, BLN_LISTED | BLN_NEW);
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001075 if (buf == NULL)
1076 return NULL;
Bram Moolenaar187db502016-02-27 14:44:26 +01001077 buf_copy_options(buf, BCO_ENTER);
Bram Moolenaara4f6ca72016-03-20 17:28:35 +01001078 curbuf = buf;
Bram Moolenaar187db502016-02-27 14:44:26 +01001079#ifdef FEAT_QUICKFIX
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001080 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
1081 set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
Bram Moolenaar187db502016-02-27 14:44:26 +01001082#endif
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001083 if (curbuf->b_ml.ml_mfp == NULL)
1084 ml_open(curbuf);
Bram Moolenaar169ebb02016-09-07 23:32:23 +02001085 if (msg)
1086 ml_replace(1, (char_u *)(err ? "Reading from channel error..."
Bram Moolenaar6ff02c92016-03-08 20:12:44 +01001087 : "Reading from channel output..."), TRUE);
Bram Moolenaar187db502016-02-27 14:44:26 +01001088 changed_bytes(1, 0);
1089 curbuf = save_curbuf;
1090 }
1091
1092 return buf;
1093}
1094
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001095 static void
1096set_callback(
1097 char_u **cbp,
1098 partial_T **pp,
1099 char_u *callback,
1100 partial_T *partial)
1101{
1102 free_callback(*cbp, *pp);
1103 if (callback != NULL && *callback != NUL)
Bram Moolenaar5ef2e762016-07-15 21:29:35 +02001104 {
1105 if (partial != NULL)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001106 *cbp = partial_name(partial);
Bram Moolenaar5ef2e762016-07-15 21:29:35 +02001107 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001108 {
Bram Moolenaar5ef2e762016-07-15 21:29:35 +02001109 *cbp = vim_strsave(callback);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001110 func_ref(*cbp);
1111 }
Bram Moolenaar5ef2e762016-07-15 21:29:35 +02001112 }
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001113 else
1114 *cbp = NULL;
1115 *pp = partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001116 if (partial != NULL)
1117 ++partial->pt_refcount;
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001118}
1119
Bram Moolenaar187db502016-02-27 14:44:26 +01001120/*
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001121 * Set various properties from an "opt" argument.
Bram Moolenaar910b8aa2016-02-16 21:03:07 +01001122 */
1123 void
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001124channel_set_options(channel_T *channel, jobopt_T *opt)
Bram Moolenaar910b8aa2016-02-16 21:03:07 +01001125{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001126 ch_part_T part;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001127
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001128 if (opt->jo_set & JO_MODE)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001129 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001130 channel->ch_part[part].ch_mode = opt->jo_mode;
1131 if (opt->jo_set & JO_IN_MODE)
1132 channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode;
1133 if (opt->jo_set & JO_OUT_MODE)
1134 channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode;
1135 if (opt->jo_set & JO_ERR_MODE)
1136 channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode;
Bram Moolenaar910b8aa2016-02-16 21:03:07 +01001137
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001138 if (opt->jo_set & JO_TIMEOUT)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001139 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001140 channel->ch_part[part].ch_timeout = opt->jo_timeout;
1141 if (opt->jo_set & JO_OUT_TIMEOUT)
1142 channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout;
1143 if (opt->jo_set & JO_ERR_TIMEOUT)
1144 channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001145 if (opt->jo_set & JO_BLOCK_WRITE)
1146 channel->ch_part[PART_IN].ch_block_write = 1;
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001147
1148 if (opt->jo_set & JO_CALLBACK)
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001149 set_callback(&channel->ch_callback, &channel->ch_partial,
1150 opt->jo_callback, opt->jo_partial);
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001151 if (opt->jo_set & JO_OUT_CALLBACK)
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001152 set_callback(&channel->ch_part[PART_OUT].ch_callback,
1153 &channel->ch_part[PART_OUT].ch_partial,
1154 opt->jo_out_cb, opt->jo_out_partial);
Bram Moolenaarb6b52522016-02-20 23:30:07 +01001155 if (opt->jo_set & JO_ERR_CALLBACK)
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001156 set_callback(&channel->ch_part[PART_ERR].ch_callback,
1157 &channel->ch_part[PART_ERR].ch_partial,
1158 opt->jo_err_cb, opt->jo_err_partial);
Bram Moolenaar4e221c92016-02-23 13:20:22 +01001159 if (opt->jo_set & JO_CLOSE_CALLBACK)
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001160 set_callback(&channel->ch_close_cb, &channel->ch_close_partial,
1161 opt->jo_close_cb, opt->jo_close_partial);
Bram Moolenaar958dc692016-12-01 15:34:12 +01001162 channel->ch_drop_never = opt->jo_drop_never;
Bram Moolenaar187db502016-02-27 14:44:26 +01001163
1164 if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
1165 {
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001166 buf_T *buf;
1167
Bram Moolenaarcc7f8be2016-02-29 22:55:56 +01001168 /* writing output to a buffer. Default mode is NL. */
1169 if (!(opt->jo_set & JO_OUT_MODE))
1170 channel->ch_part[PART_OUT].ch_mode = MODE_NL;
Bram Moolenaar29fd0382016-03-09 23:14:07 +01001171 if (opt->jo_set & JO_OUT_BUF)
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001172 {
1173 buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
1174 if (buf == NULL)
1175 EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
1176 }
Bram Moolenaar29fd0382016-03-09 23:14:07 +01001177 else
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001178 {
Bram Moolenaar169ebb02016-09-07 23:32:23 +02001179 int msg = TRUE;
1180
1181 if (opt->jo_set2 & JO2_OUT_MSG)
1182 msg = opt->jo_message[PART_OUT];
1183 buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE, msg);
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001184 }
1185 if (buf != NULL)
1186 {
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02001187 if (opt->jo_set & JO_OUT_MODIFIABLE)
1188 channel->ch_part[PART_OUT].ch_nomodifiable =
1189 !opt->jo_modifiable[PART_OUT];
1190
1191 if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable)
1192 {
1193 EMSG(_(e_modifiable));
1194 }
1195 else
1196 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001197 ch_log(channel, "writing out to buffer '%s'",
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001198 (char *)buf->b_ffname);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001199 set_bufref(&channel->ch_part[PART_OUT].ch_bufref, buf);
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02001200 }
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001201 }
Bram Moolenaar187db502016-02-27 14:44:26 +01001202 }
Bram Moolenaar6ff02c92016-03-08 20:12:44 +01001203
1204 if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
1205 || (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
1206 && opt->jo_io[PART_OUT] == JIO_BUFFER)))
1207 {
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001208 buf_T *buf;
1209
Bram Moolenaar6ff02c92016-03-08 20:12:44 +01001210 /* writing err to a buffer. Default mode is NL. */
1211 if (!(opt->jo_set & JO_ERR_MODE))
1212 channel->ch_part[PART_ERR].ch_mode = MODE_NL;
1213 if (opt->jo_io[PART_ERR] == JIO_OUT)
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001214 buf = channel->ch_part[PART_OUT].ch_bufref.br_buf;
Bram Moolenaar29fd0382016-03-09 23:14:07 +01001215 else if (opt->jo_set & JO_ERR_BUF)
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001216 {
1217 buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
1218 if (buf == NULL)
1219 EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
1220 }
Bram Moolenaar6ff02c92016-03-08 20:12:44 +01001221 else
Bram Moolenaar169ebb02016-09-07 23:32:23 +02001222 {
1223 int msg = TRUE;
1224
1225 if (opt->jo_set2 & JO2_ERR_MSG)
1226 msg = opt->jo_message[PART_ERR];
1227 buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE, msg);
1228 }
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001229 if (buf != NULL)
1230 {
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02001231 if (opt->jo_set & JO_ERR_MODIFIABLE)
1232 channel->ch_part[PART_ERR].ch_nomodifiable =
1233 !opt->jo_modifiable[PART_ERR];
1234 if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable)
1235 {
1236 EMSG(_(e_modifiable));
1237 }
1238 else
1239 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001240 ch_log(channel, "writing err to buffer '%s'",
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001241 (char *)buf->b_ffname);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001242 set_bufref(&channel->ch_part[PART_ERR].ch_bufref, buf);
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02001243 }
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001244 }
Bram Moolenaar6ff02c92016-03-08 20:12:44 +01001245 }
Bram Moolenaar03602ec2016-03-20 20:57:45 +01001246
1247 channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
1248 channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR];
1249 channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN];
Bram Moolenaar910b8aa2016-02-16 21:03:07 +01001250}
1251
1252/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001253 * Set the callback for "channel"/"part" for the response with "id".
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001254 */
1255 void
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001256channel_set_req_callback(
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001257 channel_T *channel,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001258 ch_part_T part,
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001259 char_u *callback,
1260 partial_T *partial,
1261 int id)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001262{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001263 cbq_T *head = &channel->ch_part[part].ch_cb_head;
Bram Moolenaara07fec92016-02-05 21:04:08 +01001264 cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
1265
1266 if (item != NULL)
1267 {
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001268 item->cq_partial = partial;
1269 if (partial != NULL)
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02001270 {
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001271 ++partial->pt_refcount;
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02001272 item->cq_callback = callback;
1273 }
1274 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001275 {
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02001276 item->cq_callback = vim_strsave(callback);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001277 func_ref(item->cq_callback);
1278 }
Bram Moolenaar77073442016-02-13 23:23:53 +01001279 item->cq_seq_nr = id;
1280 item->cq_prev = head->cq_prev;
1281 head->cq_prev = item;
1282 item->cq_next = NULL;
1283 if (item->cq_prev == NULL)
1284 head->cq_next = item;
1285 else
1286 item->cq_prev->cq_next = item;
Bram Moolenaara07fec92016-02-05 21:04:08 +01001287 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001288}
1289
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001290 static void
1291write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
1292{
1293 char_u *line = ml_get_buf(buf, lnum, FALSE);
Bram Moolenaar367aabd2016-03-08 17:13:06 +01001294 int len = (int)STRLEN(line);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001295 char_u *p;
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001296 int i;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001297
Bram Moolenaar655da312016-05-28 22:22:34 +02001298 /* Need to make a copy to be able to append a NL. */
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001299 if ((p = alloc(len + 2)) == NULL)
1300 return;
Bram Moolenaaradb78a72016-06-27 21:10:31 +02001301 memcpy((char *)p, (char *)line, len);
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001302
Bram Moolenaaref68e4f2017-09-02 16:28:36 +02001303 if (channel->ch_write_text_mode)
1304 p[len] = CAR;
1305 else
1306 {
1307 for (i = 0; i < len; ++i)
1308 if (p[i] == NL)
1309 p[i] = NUL;
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001310
Bram Moolenaaref68e4f2017-09-02 16:28:36 +02001311 p[len] = NL;
1312 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001313 p[len + 1] = NUL;
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01001314 channel_send(channel, PART_IN, p, len + 1, "write_buf_line");
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001315 vim_free(p);
1316}
1317
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001318/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001319 * Return TRUE if "channel" can be written to.
1320 * Returns FALSE if the input is closed or the write would block.
1321 */
1322 static int
1323can_write_buf_line(channel_T *channel)
1324{
1325 chanpart_T *in_part = &channel->ch_part[PART_IN];
1326
1327 if (in_part->ch_fd == INVALID_FD)
1328 return FALSE; /* pipe was closed */
1329
1330 /* for testing: block every other attempt to write */
1331 if (in_part->ch_block_write == 1)
1332 in_part->ch_block_write = -1;
1333 else if (in_part->ch_block_write == -1)
1334 in_part->ch_block_write = 1;
1335
1336 /* TODO: Win32 implementation, probably using WaitForMultipleObjects() */
1337#ifndef WIN32
1338 {
1339# if defined(HAVE_SELECT)
1340 struct timeval tval;
1341 fd_set wfds;
1342 int ret;
1343
1344 FD_ZERO(&wfds);
1345 FD_SET((int)in_part->ch_fd, &wfds);
1346 tval.tv_sec = 0;
1347 tval.tv_usec = 0;
1348 for (;;)
1349 {
1350 ret = select((int)in_part->ch_fd + 1, NULL, &wfds, NULL, &tval);
1351# ifdef EINTR
1352 SOCK_ERRNO;
1353 if (ret == -1 && errno == EINTR)
1354 continue;
1355# endif
1356 if (ret <= 0 || in_part->ch_block_write == 1)
1357 {
1358 if (ret > 0)
1359 ch_log(channel, "FAKED Input not ready for writing");
1360 else
1361 ch_log(channel, "Input not ready for writing");
1362 return FALSE;
1363 }
1364 break;
1365 }
1366# else
1367 struct pollfd fds;
1368
1369 fds.fd = in_part->ch_fd;
1370 fds.events = POLLOUT;
1371 if (poll(&fds, 1, 0) <= 0)
1372 {
1373 ch_log(channel, "Input not ready for writing");
1374 return FALSE;
1375 }
1376 if (in_part->ch_block_write == 1)
1377 {
1378 ch_log(channel, "FAKED Input not ready for writing");
1379 return FALSE;
1380 }
1381# endif
1382 }
1383#endif
1384 return TRUE;
1385}
1386
1387/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001388 * Write any buffer lines to the input channel.
Bram Moolenaar014069a2016-03-03 22:51:40 +01001389 */
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001390 static void
Bram Moolenaar014069a2016-03-03 22:51:40 +01001391channel_write_in(channel_T *channel)
1392{
1393 chanpart_T *in_part = &channel->ch_part[PART_IN];
1394 linenr_T lnum;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001395 buf_T *buf = in_part->ch_bufref.br_buf;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001396 int written = 0;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001397
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001398 if (buf == NULL || in_part->ch_buf_append)
1399 return; /* no buffer or using appending */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001400 if (!bufref_valid(&in_part->ch_bufref) || buf->b_ml.ml_mfp == NULL)
Bram Moolenaar014069a2016-03-03 22:51:40 +01001401 {
1402 /* buffer was wiped out or unloaded */
Bram Moolenaarc4da1132017-07-15 19:39:43 +02001403 ch_log(channel, "input buffer has been wiped out");
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001404 in_part->ch_bufref.br_buf = NULL;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001405 return;
1406 }
Bram Moolenaar014069a2016-03-03 22:51:40 +01001407
1408 for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot
1409 && lnum <= buf->b_ml.ml_line_count; ++lnum)
1410 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001411 if (!can_write_buf_line(channel))
1412 break;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001413 write_buf_line(buf, lnum, channel);
1414 ++written;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001415 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001416
1417 if (written == 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001418 ch_log(channel, "written line %d to channel", (int)lnum - 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001419 else if (written > 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001420 ch_log(channel, "written %d lines to channel", written);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001421
Bram Moolenaar014069a2016-03-03 22:51:40 +01001422 in_part->ch_buf_top = lnum;
Bram Moolenaard8b55492016-09-01 14:35:22 +02001423 if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001424 {
Bram Moolenaar3346cc42017-09-02 14:54:21 +02001425#if defined(WIN32) && defined(FEAT_TERMINAL)
1426 /* Send CTRL-D or "eof_chars" to close stdin on Windows. A console
1427 * application doesn't treat closing stdin like UNIX. */
1428 if (channel->ch_job != NULL)
1429 term_send_eof(channel);
1430#endif
1431
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001432 /* Writing is done, no longer need the buffer. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001433 in_part->ch_bufref.br_buf = NULL;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001434 ch_log(channel, "Finished writing all lines to channel");
Bram Moolenaard8b55492016-09-01 14:35:22 +02001435
1436 /* Close the pipe/socket, so that the other side gets EOF. */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001437 ch_close_part(channel, PART_IN);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001438 }
1439 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001440 ch_log(channel, "Still %d more lines to write",
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001441 buf->b_ml.ml_line_count - lnum + 1);
1442}
1443
1444/*
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02001445 * Handle buffer "buf" being freed, remove it from any channels.
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001446 */
1447 void
1448channel_buffer_free(buf_T *buf)
1449{
1450 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001451 ch_part_T part;
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001452
1453 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001454 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001455 {
1456 chanpart_T *ch_part = &channel->ch_part[part];
1457
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001458 if (ch_part->ch_bufref.br_buf == buf)
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001459 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001460 ch_log(channel, "%s buffer has been wiped out",
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001461 part_names[part]);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001462 ch_part->ch_bufref.br_buf = NULL;
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001463 }
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001464 }
1465}
1466
1467/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001468 * Write any lines waiting to be written to "channel".
1469 */
1470 static void
1471channel_write_input(channel_T *channel)
1472{
1473 chanpart_T *in_part = &channel->ch_part[PART_IN];
1474
1475 if (in_part->ch_writeque.wq_next != NULL)
1476 channel_send(channel, PART_IN, (char_u *)"", 0, "channel_write_input");
1477 else if (in_part->ch_bufref.br_buf != NULL)
1478 {
1479 if (in_part->ch_buf_append)
1480 channel_write_new_lines(in_part->ch_bufref.br_buf);
1481 else
1482 channel_write_in(channel);
1483 }
1484}
1485
1486/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001487 * Write any lines waiting to be written to a channel.
1488 */
1489 void
Bram Moolenaarcf089462016-06-12 21:18:43 +02001490channel_write_any_lines(void)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001491{
1492 channel_T *channel;
1493
1494 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001495 channel_write_input(channel);
Bram Moolenaar014069a2016-03-03 22:51:40 +01001496}
1497
1498/*
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001499 * Write appended lines above the last one in "buf" to the channel.
1500 */
1501 void
1502channel_write_new_lines(buf_T *buf)
1503{
1504 channel_T *channel;
1505 int found_one = FALSE;
1506
1507 /* There could be more than one channel for the buffer, loop over all of
1508 * them. */
1509 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
1510 {
1511 chanpart_T *in_part = &channel->ch_part[PART_IN];
1512 linenr_T lnum;
1513 int written = 0;
1514
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001515 if (in_part->ch_bufref.br_buf == buf && in_part->ch_buf_append)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001516 {
1517 if (in_part->ch_fd == INVALID_FD)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001518 continue; /* pipe was closed */
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001519 found_one = TRUE;
1520 for (lnum = in_part->ch_buf_bot; lnum < buf->b_ml.ml_line_count;
1521 ++lnum)
1522 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001523 if (!can_write_buf_line(channel))
1524 break;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001525 write_buf_line(buf, lnum, channel);
1526 ++written;
1527 }
1528
1529 if (written == 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001530 ch_log(channel, "written line %d to channel", (int)lnum - 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001531 else if (written > 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001532 ch_log(channel, "written %d lines to channel", written);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001533 if (lnum < buf->b_ml.ml_line_count)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001534 ch_log(channel, "Still %d more lines to write",
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001535 buf->b_ml.ml_line_count - lnum);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001536
1537 in_part->ch_buf_bot = lnum;
1538 }
1539 }
1540 if (!found_one)
1541 buf->b_write_to_channel = FALSE;
1542}
1543
1544/*
Bram Moolenaar77073442016-02-13 23:23:53 +01001545 * Invoke the "callback" on channel "channel".
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02001546 * This does not redraw but sets channel_need_redraw;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001547 */
1548 static void
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001549invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
1550 typval_T *argv)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001551{
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001552 typval_T rettv;
1553 int dummy;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001554
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02001555 if (safe_to_invoke_callback == 0)
Bram Moolenaarde330112017-01-08 20:50:52 +01001556 IEMSG("INTERNAL: Invoking callback when it is not safe");
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02001557
Bram Moolenaar77073442016-02-13 23:23:53 +01001558 argv[0].v_type = VAR_CHANNEL;
1559 argv[0].vval.v_channel = channel;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001560
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001561 call_func(callback, (int)STRLEN(callback), &rettv, 2, argv, NULL,
1562 0L, 0L, &dummy, TRUE, partial, NULL);
Bram Moolenaaree1cffc2016-02-21 19:14:41 +01001563 clear_tv(&rettv);
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02001564 channel_need_redraw = TRUE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01001565}
1566
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01001567/*
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001568 * Return the first node from "channel"/"part" without removing it.
1569 * Returns NULL if there is nothing.
1570 */
1571 readq_T *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001572channel_peek(channel_T *channel, ch_part_T part)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001573{
1574 readq_T *head = &channel->ch_part[part].ch_head;
1575
1576 return head->rq_next;
1577}
1578
1579/*
1580 * Return a pointer to the first NL in "node".
1581 * Skips over NUL characters.
1582 * Returns NULL if there is no NL.
1583 */
1584 char_u *
1585channel_first_nl(readq_T *node)
1586{
1587 char_u *buffer = node->rq_buffer;
1588 long_u i;
1589
1590 for (i = 0; i < node->rq_buflen; ++i)
1591 if (buffer[i] == NL)
1592 return buffer + i;
1593 return NULL;
1594}
1595
1596/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001597 * Return the first buffer from channel "channel"/"part" and remove it.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001598 * The caller must free it.
1599 * Returns NULL if there is nothing.
1600 */
1601 char_u *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001602channel_get(channel_T *channel, ch_part_T part)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001603{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001604 readq_T *head = &channel->ch_part[part].ch_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01001605 readq_T *node = head->rq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001606 char_u *p;
1607
Bram Moolenaar77073442016-02-13 23:23:53 +01001608 if (node == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001609 return NULL;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001610 /* dispose of the node but keep the buffer */
Bram Moolenaar77073442016-02-13 23:23:53 +01001611 p = node->rq_buffer;
1612 head->rq_next = node->rq_next;
1613 if (node->rq_next == NULL)
1614 head->rq_prev = NULL;
1615 else
1616 node->rq_next->rq_prev = NULL;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001617 vim_free(node);
1618 return p;
1619}
1620
1621/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001622 * Returns the whole buffer contents concatenated for "channel"/"part".
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001623 * Replaces NUL bytes with NL.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001624 */
1625 static char_u *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001626channel_get_all(channel_T *channel, ch_part_T part)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001627{
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001628 readq_T *head = &channel->ch_part[part].ch_head;
1629 readq_T *node = head->rq_next;
Bram Moolenaaradb78a72016-06-27 21:10:31 +02001630 long_u len = 0;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001631 char_u *res;
1632 char_u *p;
1633
1634 /* If there is only one buffer just get that one. */
1635 if (head->rq_next == NULL || head->rq_next->rq_next == NULL)
1636 return channel_get(channel, part);
1637
1638 /* Concatenate everything into one buffer. */
1639 for (node = head->rq_next; node != NULL; node = node->rq_next)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001640 len += node->rq_buflen;
Bram Moolenaaradb78a72016-06-27 21:10:31 +02001641 res = lalloc(len + 1, TRUE);
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001642 if (res == NULL)
1643 return NULL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001644 p = res;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001645 for (node = head->rq_next; node != NULL; node = node->rq_next)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001646 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001647 mch_memmove(p, node->rq_buffer, node->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001648 p += node->rq_buflen;
1649 }
1650 *p = NUL;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001651
1652 /* Free all buffers */
1653 do
1654 {
1655 p = channel_get(channel, part);
1656 vim_free(p);
1657 } while (p != NULL);
1658
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001659 /* turn all NUL into NL */
1660 while (len > 0)
1661 {
1662 --len;
1663 if (res[len] == NUL)
1664 res[len] = NL;
1665 }
1666
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001667 return res;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001668}
1669
1670/*
Bram Moolenaarcf089462016-06-12 21:18:43 +02001671 * Consume "len" bytes from the head of "node".
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001672 * Caller must check these bytes are available.
1673 */
1674 void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001675channel_consume(channel_T *channel, ch_part_T part, int len)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001676{
1677 readq_T *head = &channel->ch_part[part].ch_head;
1678 readq_T *node = head->rq_next;
1679 char_u *buf = node->rq_buffer;
1680
1681 mch_memmove(buf, buf + len, node->rq_buflen - len);
1682 node->rq_buflen -= len;
1683}
1684
1685/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001686 * Collapses the first and second buffer for "channel"/"part".
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001687 * Returns FAIL if that is not possible.
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001688 * When "want_nl" is TRUE collapse more buffers until a NL is found.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001689 */
1690 int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001691channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001692{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001693 readq_T *head = &channel->ch_part[part].ch_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01001694 readq_T *node = head->rq_next;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001695 readq_T *last_node;
1696 readq_T *n;
1697 char_u *newbuf;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001698 char_u *p;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001699 long_u len;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001700
Bram Moolenaar77073442016-02-13 23:23:53 +01001701 if (node == NULL || node->rq_next == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001702 return FAIL;
1703
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001704 last_node = node->rq_next;
1705 len = node->rq_buflen + last_node->rq_buflen + 1;
1706 if (want_nl)
1707 while (last_node->rq_next != NULL
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001708 && channel_first_nl(last_node) == NULL)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001709 {
1710 last_node = last_node->rq_next;
1711 len += last_node->rq_buflen;
1712 }
1713
1714 p = newbuf = alloc(len);
1715 if (newbuf == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001716 return FAIL; /* out of memory */
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001717 mch_memmove(p, node->rq_buffer, node->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001718 p += node->rq_buflen;
Bram Moolenaar77073442016-02-13 23:23:53 +01001719 vim_free(node->rq_buffer);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001720 node->rq_buffer = newbuf;
1721 for (n = node; n != last_node; )
1722 {
1723 n = n->rq_next;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001724 mch_memmove(p, n->rq_buffer, n->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001725 p += n->rq_buflen;
1726 vim_free(n->rq_buffer);
1727 }
Bram Moolenaarbbe8d912016-06-05 16:10:57 +02001728 node->rq_buflen = (long_u)(p - newbuf);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001729
1730 /* dispose of the collapsed nodes and their buffers */
1731 for (n = node->rq_next; n != last_node; )
1732 {
1733 n = n->rq_next;
1734 vim_free(n->rq_prev);
1735 }
1736 node->rq_next = last_node->rq_next;
1737 if (last_node->rq_next == NULL)
1738 head->rq_prev = node;
1739 else
1740 last_node->rq_next->rq_prev = node;
1741 vim_free(last_node);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001742 return OK;
1743}
1744
1745/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001746 * Store "buf[len]" on "channel"/"part".
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001747 * When "prepend" is TRUE put in front, otherwise append at the end.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001748 * Returns OK or FAIL.
1749 */
1750 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001751channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001752 int prepend, char *lead)
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001753{
1754 readq_T *node;
1755 readq_T *head = &channel->ch_part[part].ch_head;
1756 char_u *p;
1757 int i;
1758
1759 node = (readq_T *)alloc(sizeof(readq_T));
1760 if (node == NULL)
1761 return FAIL; /* out of memory */
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001762 /* A NUL is added at the end, because netbeans code expects that.
1763 * Otherwise a NUL may appear inside the text. */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001764 node->rq_buffer = alloc(len + 1);
1765 if (node->rq_buffer == NULL)
1766 {
1767 vim_free(node);
1768 return FAIL; /* out of memory */
1769 }
1770
1771 if (channel->ch_part[part].ch_mode == MODE_NL)
1772 {
1773 /* Drop any CR before a NL. */
1774 p = node->rq_buffer;
1775 for (i = 0; i < len; ++i)
1776 if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
1777 *p++ = buf[i];
1778 *p = NUL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001779 node->rq_buflen = (long_u)(p - node->rq_buffer);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001780 }
1781 else
1782 {
1783 mch_memmove(node->rq_buffer, buf, len);
1784 node->rq_buffer[len] = NUL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001785 node->rq_buflen = (long_u)len;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001786 }
1787
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001788 if (prepend)
1789 {
1790 /* preend node to the head of the queue */
1791 node->rq_next = head->rq_next;
1792 node->rq_prev = NULL;
1793 if (head->rq_next == NULL)
1794 head->rq_prev = node;
1795 else
1796 head->rq_next->rq_prev = node;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001797 head->rq_next = node;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001798 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001799 else
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001800 {
1801 /* append node to the tail of the queue */
1802 node->rq_next = NULL;
1803 node->rq_prev = head->rq_prev;
1804 if (head->rq_prev == NULL)
1805 head->rq_next = node;
1806 else
1807 head->rq_prev->rq_next = node;
1808 head->rq_prev = node;
1809 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001810
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001811 if (log_fd != NULL && lead != NULL)
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001812 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001813 ch_log_lead(lead, channel);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001814 fprintf(log_fd, "'");
1815 if (fwrite(buf, len, 1, log_fd) != 1)
1816 return FAIL;
1817 fprintf(log_fd, "'\n");
1818 }
1819 return OK;
1820}
1821
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001822/*
1823 * Try to fill the buffer of "reader".
1824 * Returns FALSE when nothing was added.
1825 */
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001826 static int
1827channel_fill(js_read_T *reader)
1828{
1829 channel_T *channel = (channel_T *)reader->js_cookie;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001830 ch_part_T part = reader->js_cookie_arg;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001831 char_u *next = channel_get(channel, part);
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001832 int keeplen;
1833 int addlen;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001834 char_u *p;
1835
1836 if (next == NULL)
1837 return FALSE;
1838
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001839 keeplen = reader->js_end - reader->js_buf;
1840 if (keeplen > 0)
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001841 {
1842 /* Prepend unused text. */
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001843 addlen = (int)STRLEN(next);
1844 p = alloc(keeplen + addlen + 1);
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001845 if (p == NULL)
1846 {
1847 vim_free(next);
1848 return FALSE;
1849 }
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001850 mch_memmove(p, reader->js_buf, keeplen);
1851 mch_memmove(p + keeplen, next, addlen + 1);
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001852 vim_free(next);
1853 next = p;
1854 }
1855
1856 vim_free(reader->js_buf);
1857 reader->js_buf = next;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001858 return TRUE;
1859}
1860
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001861/*
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001862 * Use the read buffer of "channel"/"part" and parse a JSON message that is
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001863 * complete. The messages are added to the queue.
Bram Moolenaard7ece102016-02-02 23:23:02 +01001864 * Return TRUE if there is more to read.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001865 */
Bram Moolenaard7ece102016-02-02 23:23:02 +01001866 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001867channel_parse_json(channel_T *channel, ch_part_T part)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001868{
1869 js_read_T reader;
1870 typval_T listtv;
1871 jsonq_T *item;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001872 chanpart_T *chanpart = &channel->ch_part[part];
1873 jsonq_T *head = &chanpart->ch_json_head;
1874 int status;
Bram Moolenaard7ece102016-02-02 23:23:02 +01001875 int ret;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001876
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001877 if (channel_peek(channel, part) == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01001878 return FALSE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001879
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001880 reader.js_buf = channel_get(channel, part);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001881 reader.js_used = 0;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001882 reader.js_fill = channel_fill;
Bram Moolenaar77073442016-02-13 23:23:53 +01001883 reader.js_cookie = channel;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001884 reader.js_cookie_arg = part;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001885
1886 /* When a message is incomplete we wait for a short while for more to
1887 * arrive. After the delay drop the input, otherwise a truncated string
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001888 * or list will make us hang.
1889 * Do not generate error messages, they will be written in a channel log. */
1890 ++emsg_silent;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001891 status = json_decode(&reader, &listtv,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02001892 chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001893 --emsg_silent;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001894 if (status == OK)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001895 {
Bram Moolenaar6076fe12016-02-05 22:49:56 +01001896 /* Only accept the response when it is a list with at least two
1897 * items. */
1898 if (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2)
Bram Moolenaard7ece102016-02-02 23:23:02 +01001899 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001900 if (listtv.v_type != VAR_LIST)
1901 ch_error(channel, "Did not receive a list, discarding");
1902 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001903 ch_error(channel, "Expected list with two items, got %d",
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001904 listtv.vval.v_list->lv_len);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001905 clear_tv(&listtv);
Bram Moolenaard7ece102016-02-02 23:23:02 +01001906 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001907 else
1908 {
Bram Moolenaard7ece102016-02-02 23:23:02 +01001909 item = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
1910 if (item == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001911 clear_tv(&listtv);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001912 else
1913 {
Bram Moolenaar958dc692016-12-01 15:34:12 +01001914 item->jq_no_callback = FALSE;
Bram Moolenaar77073442016-02-13 23:23:53 +01001915 item->jq_value = alloc_tv();
1916 if (item->jq_value == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01001917 {
1918 vim_free(item);
1919 clear_tv(&listtv);
1920 }
1921 else
1922 {
Bram Moolenaar77073442016-02-13 23:23:53 +01001923 *item->jq_value = listtv;
1924 item->jq_prev = head->jq_prev;
1925 head->jq_prev = item;
1926 item->jq_next = NULL;
1927 if (item->jq_prev == NULL)
1928 head->jq_next = item;
1929 else
1930 item->jq_prev->jq_next = item;
Bram Moolenaard7ece102016-02-02 23:23:02 +01001931 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001932 }
1933 }
1934 }
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01001935
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001936 if (status == OK)
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001937 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001938 else if (status == MAYBE)
Bram Moolenaard7ece102016-02-02 23:23:02 +01001939 {
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001940 size_t buflen = STRLEN(reader.js_buf);
1941
1942 if (chanpart->ch_wait_len < buflen)
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01001943 {
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001944 /* First time encountering incomplete message or after receiving
1945 * more (but still incomplete): set a deadline of 100 msec. */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001946 ch_log(channel,
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001947 "Incomplete message (%d bytes) - wait 100 msec for more",
Bram Moolenaarb113c3a2017-02-28 21:26:17 +01001948 (int)buflen);
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001949 reader.js_used = 0;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001950 chanpart->ch_wait_len = buflen;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001951#ifdef WIN32
1952 chanpart->ch_deadline = GetTickCount() + 100L;
1953#else
1954 gettimeofday(&chanpart->ch_deadline, NULL);
1955 chanpart->ch_deadline.tv_usec += 100 * 1000;
1956 if (chanpart->ch_deadline.tv_usec > 1000 * 1000)
1957 {
1958 chanpart->ch_deadline.tv_usec -= 1000 * 1000;
1959 ++chanpart->ch_deadline.tv_sec;
1960 }
1961#endif
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01001962 }
1963 else
1964 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001965 int timeout;
1966#ifdef WIN32
1967 timeout = GetTickCount() > chanpart->ch_deadline;
1968#else
1969 {
1970 struct timeval now_tv;
1971
1972 gettimeofday(&now_tv, NULL);
1973 timeout = now_tv.tv_sec > chanpart->ch_deadline.tv_sec
1974 || (now_tv.tv_sec == chanpart->ch_deadline.tv_sec
1975 && now_tv.tv_usec > chanpart->ch_deadline.tv_usec);
1976 }
1977#endif
1978 if (timeout)
1979 {
1980 status = FAIL;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001981 chanpart->ch_wait_len = 0;
1982 ch_log(channel, "timed out");
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001983 }
1984 else
1985 {
1986 reader.js_used = 0;
1987 ch_log(channel, "still waiting on incomplete message");
1988 }
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01001989 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01001990 }
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001991
1992 if (status == FAIL)
1993 {
1994 ch_error(channel, "Decoding failed - discarding input");
1995 ret = FALSE;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01001996 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001997 }
1998 else if (reader.js_buf[reader.js_used] != NUL)
1999 {
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002000 /* Put the unread part back into the channel. */
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002001 channel_save(channel, part, reader.js_buf + reader.js_used,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002002 (int)(reader.js_end - reader.js_buf) - reader.js_used,
2003 TRUE, NULL);
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002004 ret = status == MAYBE ? FALSE: TRUE;
2005 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01002006 else
2007 ret = FALSE;
2008
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002009 vim_free(reader.js_buf);
Bram Moolenaard7ece102016-02-02 23:23:02 +01002010 return ret;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002011}
2012
2013/*
Bram Moolenaard46ae142016-02-16 13:33:52 +01002014 * Remove "node" from the queue that it is in. Does not free it.
Bram Moolenaara07fec92016-02-05 21:04:08 +01002015 */
2016 static void
Bram Moolenaar77073442016-02-13 23:23:53 +01002017remove_cb_node(cbq_T *head, cbq_T *node)
Bram Moolenaara07fec92016-02-05 21:04:08 +01002018{
Bram Moolenaar77073442016-02-13 23:23:53 +01002019 if (node->cq_prev == NULL)
2020 head->cq_next = node->cq_next;
2021 else
2022 node->cq_prev->cq_next = node->cq_next;
2023 if (node->cq_next == NULL)
2024 head->cq_prev = node->cq_prev;
2025 else
2026 node->cq_next->cq_prev = node->cq_prev;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002027}
2028
2029/*
2030 * Remove "node" from the queue that it is in and free it.
Bram Moolenaar77073442016-02-13 23:23:53 +01002031 * Caller should have freed or used node->jq_value.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002032 */
2033 static void
Bram Moolenaar77073442016-02-13 23:23:53 +01002034remove_json_node(jsonq_T *head, jsonq_T *node)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002035{
Bram Moolenaar77073442016-02-13 23:23:53 +01002036 if (node->jq_prev == NULL)
2037 head->jq_next = node->jq_next;
2038 else
2039 node->jq_prev->jq_next = node->jq_next;
2040 if (node->jq_next == NULL)
2041 head->jq_prev = node->jq_prev;
2042 else
2043 node->jq_next->jq_prev = node->jq_prev;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002044 vim_free(node);
2045}
2046
2047/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002048 * Get a message from the JSON queue for channel "channel".
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002049 * When "id" is positive it must match the first number in the list.
Bram Moolenaare56bf152016-02-08 23:23:42 +01002050 * When "id" is zero or negative jut get the first message. But not the one
2051 * with id ch_block_id.
Bram Moolenaar958dc692016-12-01 15:34:12 +01002052 * When "without_callback" is TRUE also get messages that were pushed back.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002053 * Return OK when found and return the value in "rettv".
2054 * Return FAIL otherwise.
2055 */
2056 static int
Bram Moolenaar958dc692016-12-01 15:34:12 +01002057channel_get_json(
2058 channel_T *channel,
2059 ch_part_T part,
2060 int id,
2061 int without_callback,
2062 typval_T **rettv)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002063{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002064 jsonq_T *head = &channel->ch_part[part].ch_json_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01002065 jsonq_T *item = head->jq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002066
Bram Moolenaar77073442016-02-13 23:23:53 +01002067 while (item != NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002068 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002069 list_T *l = item->jq_value->vval.v_list;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002070 typval_T *tv = &l->lv_first->li_tv;
2071
Bram Moolenaar958dc692016-12-01 15:34:12 +01002072 if ((without_callback || !item->jq_no_callback)
2073 && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
Bram Moolenaare56bf152016-02-08 23:23:42 +01002074 || (id <= 0 && (tv->v_type != VAR_NUMBER
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002075 || tv->vval.v_number == 0
Bram Moolenaar958dc692016-12-01 15:34:12 +01002076 || tv->vval.v_number != channel->ch_part[part].ch_block_id))))
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002077 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002078 *rettv = item->jq_value;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002079 if (tv->v_type == VAR_NUMBER)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002080 ch_log(channel, "Getting JSON message %d", tv->vval.v_number);
Bram Moolenaar77073442016-02-13 23:23:53 +01002081 remove_json_node(head, item);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002082 return OK;
2083 }
Bram Moolenaar77073442016-02-13 23:23:53 +01002084 item = item->jq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002085 }
2086 return FAIL;
2087}
2088
Bram Moolenaar958dc692016-12-01 15:34:12 +01002089/*
2090 * Put back "rettv" into the JSON queue, there was no callback for it.
2091 * Takes over the values in "rettv".
2092 */
2093 static void
2094channel_push_json(channel_T *channel, ch_part_T part, typval_T *rettv)
2095{
2096 jsonq_T *head = &channel->ch_part[part].ch_json_head;
2097 jsonq_T *item = head->jq_next;
2098 jsonq_T *newitem;
2099
2100 if (head->jq_prev != NULL && head->jq_prev->jq_no_callback)
2101 /* last item was pushed back, append to the end */
2102 item = NULL;
2103 else while (item != NULL && item->jq_no_callback)
2104 /* append after the last item that was pushed back */
2105 item = item->jq_next;
2106
2107 newitem = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
2108 if (newitem == NULL)
2109 clear_tv(rettv);
2110 else
2111 {
2112 newitem->jq_value = alloc_tv();
2113 if (newitem->jq_value == NULL)
2114 {
2115 vim_free(newitem);
2116 clear_tv(rettv);
2117 }
2118 else
2119 {
2120 newitem->jq_no_callback = FALSE;
2121 *newitem->jq_value = *rettv;
2122 if (item == NULL)
2123 {
2124 /* append to the end */
2125 newitem->jq_prev = head->jq_prev;
2126 head->jq_prev = newitem;
2127 newitem->jq_next = NULL;
2128 if (newitem->jq_prev == NULL)
2129 head->jq_next = newitem;
2130 else
2131 newitem->jq_prev->jq_next = newitem;
2132 }
2133 else
2134 {
2135 /* append after "item" */
2136 newitem->jq_prev = item;
2137 newitem->jq_next = item->jq_next;
2138 item->jq_next = newitem;
2139 if (newitem->jq_next == NULL)
2140 head->jq_prev = newitem;
2141 else
2142 newitem->jq_next->jq_prev = newitem;
2143 }
2144 }
2145 }
2146}
2147
Bram Moolenaarece61b02016-02-20 21:39:05 +01002148#define CH_JSON_MAX_ARGS 4
2149
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002150/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002151 * Execute a command received over "channel"/"part"
Bram Moolenaarece61b02016-02-20 21:39:05 +01002152 * "argv[0]" is the command string.
2153 * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing.
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002154 */
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002155 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002156channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002157{
Bram Moolenaarece61b02016-02-20 21:39:05 +01002158 char_u *cmd = argv[0].vval.v_string;
2159 char_u *arg;
2160 int options = channel->ch_part[part].ch_mode == MODE_JS ? JSON_JS : 0;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002161
Bram Moolenaarece61b02016-02-20 21:39:05 +01002162 if (argv[1].v_type != VAR_STRING)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002163 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002164 ch_error(channel, "received command with non-string argument");
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002165 if (p_verbose > 2)
Bram Moolenaar5b302912016-08-24 22:11:55 +02002166 EMSG(_("E903: received command with non-string argument"));
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002167 return;
2168 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002169 arg = argv[1].vval.v_string;
Bram Moolenaar14ad6112016-02-01 21:47:13 +01002170 if (arg == NULL)
2171 arg = (char_u *)"";
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002172
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002173 if (STRCMP(cmd, "ex") == 0)
2174 {
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002175 int save_called_emsg = called_emsg;
2176
2177 called_emsg = FALSE;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002178 ch_log(channel, "Executing ex command '%s'", (char *)arg);
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002179 ++emsg_silent;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002180 do_cmdline_cmd(arg);
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002181 --emsg_silent;
2182 if (called_emsg)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002183 ch_log(channel, "Ex command error: '%s'",
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002184 (char *)get_vim_var_str(VV_ERRMSG));
2185 called_emsg = save_called_emsg;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002186 }
2187 else if (STRCMP(cmd, "normal") == 0)
2188 {
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002189 exarg_T ea;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002190
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002191 ch_log(channel, "Executing normal command '%s'", (char *)arg);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002192 ea.arg = arg;
2193 ea.addr_count = 0;
2194 ea.forceit = TRUE; /* no mapping */
2195 ex_normal(&ea);
2196 }
2197 else if (STRCMP(cmd, "redraw") == 0)
2198 {
2199 exarg_T ea;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002200
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002201 ch_log(channel, "redraw");
Bram Moolenaar14ad6112016-02-01 21:47:13 +01002202 ea.forceit = *arg != NUL;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002203 ex_redraw(&ea);
2204 showruler(FALSE);
2205 setcursor();
2206 out_flush();
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002207#ifdef FEAT_GUI
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002208 if (gui.in_use)
2209 {
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002210 gui_update_cursor(TRUE, FALSE);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002211 gui_mch_flush();
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002212 }
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002213#endif
2214 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002215 else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002216 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002217 int is_call = cmd[0] == 'c';
2218 int id_idx = is_call ? 3 : 2;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002219
Bram Moolenaarece61b02016-02-20 21:39:05 +01002220 if (argv[id_idx].v_type != VAR_UNKNOWN
2221 && argv[id_idx].v_type != VAR_NUMBER)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002222 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002223 ch_error(channel, "last argument for expr/call must be a number");
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002224 if (p_verbose > 2)
Bram Moolenaar5b302912016-08-24 22:11:55 +02002225 EMSG(_("E904: last argument for expr/call must be a number"));
Bram Moolenaarece61b02016-02-20 21:39:05 +01002226 }
2227 else if (is_call && argv[2].v_type != VAR_LIST)
2228 {
2229 ch_error(channel, "third argument for call must be a list");
2230 if (p_verbose > 2)
Bram Moolenaar5b302912016-08-24 22:11:55 +02002231 EMSG(_("E904: third argument for call must be a list"));
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002232 }
2233 else
2234 {
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002235 typval_T *tv = NULL;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002236 typval_T res_tv;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002237 typval_T err_tv;
Bram Moolenaar55fab432016-02-07 16:53:13 +01002238 char_u *json = NULL;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002239
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +01002240 /* Don't pollute the display with errors. */
2241 ++emsg_skip;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002242 if (!is_call)
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002243 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002244 ch_log(channel, "Evaluating expression '%s'", (char *)arg);
Bram Moolenaarece61b02016-02-20 21:39:05 +01002245 tv = eval_expr(arg, NULL);
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002246 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002247 else
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002248 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002249 ch_log(channel, "Calling '%s'", (char *)arg);
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002250 if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK)
2251 tv = &res_tv;
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002252 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002253
2254 if (argv[id_idx].v_type == VAR_NUMBER)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002255 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002256 int id = argv[id_idx].vval.v_number;
2257
Bram Moolenaar55fab432016-02-07 16:53:13 +01002258 if (tv != NULL)
Bram Moolenaarf1f07922016-08-26 17:58:53 +02002259 json = json_encode_nr_expr(id, tv, options | JSON_NL);
Bram Moolenaar55fab432016-02-07 16:53:13 +01002260 if (tv == NULL || (json != NULL && *json == NUL))
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002261 {
Bram Moolenaar55fab432016-02-07 16:53:13 +01002262 /* If evaluation failed or the result can't be encoded
2263 * then return the string "ERROR". */
Bram Moolenaar77073442016-02-13 23:23:53 +01002264 vim_free(json);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002265 err_tv.v_type = VAR_STRING;
2266 err_tv.vval.v_string = (char_u *)"ERROR";
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002267 json = json_encode_nr_expr(id, &err_tv, options | JSON_NL);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002268 }
Bram Moolenaar55fab432016-02-07 16:53:13 +01002269 if (json != NULL)
2270 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002271 channel_send(channel,
2272 part == PART_SOCK ? PART_SOCK : PART_IN,
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02002273 json, (int)STRLEN(json), (char *)cmd);
Bram Moolenaar55fab432016-02-07 16:53:13 +01002274 vim_free(json);
2275 }
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002276 }
Bram Moolenaar55fab432016-02-07 16:53:13 +01002277 --emsg_skip;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002278 if (tv == &res_tv)
2279 clear_tv(tv);
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002280 else
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +01002281 free_tv(tv);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002282 }
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002283 }
2284 else if (p_verbose > 2)
Bram Moolenaarece61b02016-02-20 21:39:05 +01002285 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002286 ch_error(channel, "Received unknown command: %s", (char *)cmd);
Bram Moolenaar5b302912016-08-24 22:11:55 +02002287 EMSG2(_("E905: received unknown command: %s"), cmd);
Bram Moolenaarece61b02016-02-20 21:39:05 +01002288 }
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002289}
2290
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02002291/*
2292 * Invoke the callback at "cbhead".
2293 * Does not redraw but sets channel_need_redraw.
2294 */
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002295 static void
2296invoke_one_time_callback(
2297 channel_T *channel,
2298 cbq_T *cbhead,
2299 cbq_T *item,
2300 typval_T *argv)
2301{
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002302 ch_log(channel, "Invoking one-time callback %s",
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002303 (char *)item->cq_callback);
2304 /* Remove the item from the list first, if the callback
2305 * invokes ch_close() the list will be cleared. */
2306 remove_cb_node(cbhead, item);
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002307 invoke_callback(channel, item->cq_callback, item->cq_partial, argv);
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02002308 free_callback(item->cq_callback, item->cq_partial);
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002309 vim_free(item);
2310}
2311
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002312 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002313append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002314{
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002315 bufref_T save_curbuf = {NULL, 0, 0};
2316 win_T *save_curwin = NULL;
2317 tabpage_T *save_curtab = NULL;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002318 linenr_T lnum = buffer->b_ml.ml_line_count;
2319 int save_write_to = buffer->b_write_to_channel;
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002320 chanpart_T *ch_part = &channel->ch_part[part];
2321 int save_p_ma = buffer->b_p_ma;
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002322 int empty = (buffer->b_ml.ml_flags & ML_EMPTY) ? 1 : 0;
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002323
2324 if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
2325 {
2326 if (!ch_part->ch_nomod_error)
2327 {
2328 ch_error(channel, "Buffer is not modifiable, cannot append");
2329 ch_part->ch_nomod_error = TRUE;
2330 }
2331 return;
2332 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002333
2334 /* If the buffer is also used as input insert above the last
2335 * line. Don't write these lines. */
2336 if (save_write_to)
2337 {
2338 --lnum;
2339 buffer->b_write_to_channel = FALSE;
2340 }
2341
2342 /* Append to the buffer */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002343 ch_log(channel, "appending line %d to buffer", (int)lnum + 1 - empty);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002344
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002345 buffer->b_p_ma = TRUE;
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002346
2347 /* Save curbuf/curwin/curtab and make "buffer" the current buffer. */
2348 switch_to_win_for_buf(buffer, &save_curwin, &save_curtab, &save_curbuf);
2349
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002350 u_sync(TRUE);
2351 /* ignore undo failure, undo is not very useful here */
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002352 ignored = u_save(lnum - empty, lnum + 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002353
Bram Moolenaar169ebb02016-09-07 23:32:23 +02002354 if (empty)
2355 {
2356 /* The buffer is empty, replace the first (dummy) line. */
2357 ml_replace(lnum, msg, TRUE);
2358 lnum = 0;
2359 }
2360 else
2361 ml_append(lnum, msg, 0, FALSE);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002362 appended_lines_mark(lnum, 1L);
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002363
2364 /* Restore curbuf/curwin/curtab */
2365 restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
2366
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002367 if (ch_part->ch_nomodifiable)
2368 buffer->b_p_ma = FALSE;
2369 else
2370 buffer->b_p_ma = save_p_ma;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002371
2372 if (buffer->b_nwindows > 0)
2373 {
2374 win_T *wp;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002375
2376 FOR_ALL_WINDOWS(wp)
2377 {
2378 if (wp->w_buffer == buffer
2379 && (save_write_to
2380 ? wp->w_cursor.lnum == lnum + 1
2381 : (wp->w_cursor.lnum == lnum
2382 && wp->w_cursor.col == 0)))
2383 {
2384 ++wp->w_cursor.lnum;
2385 save_curwin = curwin;
2386 curwin = wp;
2387 curbuf = curwin->w_buffer;
2388 scroll_cursor_bot(0, FALSE);
2389 curwin = save_curwin;
2390 curbuf = curwin->w_buffer;
2391 }
2392 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +02002393 redraw_buf_and_status_later(buffer, VALID);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002394 channel_need_redraw = TRUE;
2395 }
2396
2397 if (save_write_to)
2398 {
2399 channel_T *ch;
2400
2401 /* Find channels reading from this buffer and adjust their
2402 * next-to-read line number. */
2403 buffer->b_write_to_channel = TRUE;
2404 for (ch = first_channel; ch != NULL; ch = ch->ch_next)
2405 {
2406 chanpart_T *in_part = &ch->ch_part[PART_IN];
2407
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002408 if (in_part->ch_bufref.br_buf == buffer)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002409 in_part->ch_buf_bot = buffer->b_ml.ml_line_count;
2410 }
2411 }
2412}
2413
Bram Moolenaar437905c2016-04-26 19:01:05 +02002414 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002415drop_messages(channel_T *channel, ch_part_T part)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002416{
2417 char_u *msg;
2418
2419 while ((msg = channel_get(channel, part)) != NULL)
2420 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002421 ch_log(channel, "Dropping message '%s'", (char *)msg);
Bram Moolenaar437905c2016-04-26 19:01:05 +02002422 vim_free(msg);
2423 }
2424}
2425
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002426/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002427 * Invoke a callback for "channel"/"part" if needed.
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02002428 * This does not redraw but sets channel_need_redraw when redraw is needed.
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002429 * Return TRUE when a message was handled, there might be another one.
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002430 */
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002431 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002432may_invoke_callback(channel_T *channel, ch_part_T part)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002433{
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002434 char_u *msg = NULL;
2435 typval_T *listtv = NULL;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002436 typval_T argv[CH_JSON_MAX_ARGS];
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002437 int seq_nr = -1;
Bram Moolenaarec68a992016-10-03 21:37:41 +02002438 chanpart_T *ch_part = &channel->ch_part[part];
2439 ch_mode_T ch_mode = ch_part->ch_mode;
2440 cbq_T *cbhead = &ch_part->ch_cb_head;
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002441 cbq_T *cbitem;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002442 char_u *callback = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002443 partial_T *partial = NULL;
Bram Moolenaar187db502016-02-27 14:44:26 +01002444 buf_T *buffer = NULL;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002445 char_u *p;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002446
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002447 if (channel->ch_nb_close_cb != NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002448 /* this channel is handled elsewhere (netbeans) */
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002449 return FALSE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002450
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002451 /* Use a message-specific callback, part callback or channel callback */
2452 for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
2453 if (cbitem->cq_seq_nr == 0)
2454 break;
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002455 if (cbitem != NULL)
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002456 {
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002457 callback = cbitem->cq_callback;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002458 partial = cbitem->cq_partial;
2459 }
Bram Moolenaarec68a992016-10-03 21:37:41 +02002460 else if (ch_part->ch_callback != NULL)
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002461 {
Bram Moolenaarec68a992016-10-03 21:37:41 +02002462 callback = ch_part->ch_callback;
2463 partial = ch_part->ch_partial;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002464 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002465 else
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002466 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002467 callback = channel->ch_callback;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002468 partial = channel->ch_partial;
2469 }
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002470
Bram Moolenaarec68a992016-10-03 21:37:41 +02002471 buffer = ch_part->ch_bufref.br_buf;
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002472 if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
2473 || buffer->b_ml.ml_mfp == NULL))
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002474 {
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002475 /* buffer was wiped out or unloaded */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002476 ch_log(channel, "%s buffer has been wiped out", part_names[part]);
Bram Moolenaarec68a992016-10-03 21:37:41 +02002477 ch_part->ch_bufref.br_buf = NULL;
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002478 buffer = NULL;
2479 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002480
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002481 if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002482 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002483 listitem_T *item;
2484 int argc = 0;
2485
Bram Moolenaard7ece102016-02-02 23:23:02 +01002486 /* Get any json message in the queue. */
Bram Moolenaar958dc692016-12-01 15:34:12 +01002487 if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002488 {
Bram Moolenaard7ece102016-02-02 23:23:02 +01002489 /* Parse readahead, return when there is still no message. */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002490 channel_parse_json(channel, part);
Bram Moolenaar958dc692016-12-01 15:34:12 +01002491 if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002492 return FALSE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002493 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002494
Bram Moolenaarece61b02016-02-20 21:39:05 +01002495 for (item = listtv->vval.v_list->lv_first;
2496 item != NULL && argc < CH_JSON_MAX_ARGS;
2497 item = item->li_next)
2498 argv[argc++] = item->li_tv;
2499 while (argc < CH_JSON_MAX_ARGS)
2500 argv[argc++].v_type = VAR_UNKNOWN;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002501
Bram Moolenaarece61b02016-02-20 21:39:05 +01002502 if (argv[0].v_type == VAR_STRING)
2503 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002504 /* ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg] */
Bram Moolenaarece61b02016-02-20 21:39:05 +01002505 channel_exe_cmd(channel, part, argv);
Bram Moolenaar77073442016-02-13 23:23:53 +01002506 free_tv(listtv);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002507 return TRUE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002508 }
2509
Bram Moolenaarece61b02016-02-20 21:39:05 +01002510 if (argv[0].v_type != VAR_NUMBER)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002511 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002512 ch_error(channel,
Bram Moolenaar81661fb2016-02-18 22:23:34 +01002513 "Dropping message with invalid sequence number type");
Bram Moolenaar77073442016-02-13 23:23:53 +01002514 free_tv(listtv);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002515 return FALSE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002516 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002517 seq_nr = argv[0].vval.v_number;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002518 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002519 else if (channel_peek(channel, part) == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002520 {
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002521 /* nothing to read on RAW or NL channel */
Bram Moolenaard7ece102016-02-02 23:23:02 +01002522 return FALSE;
2523 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002524 else
2525 {
Bram Moolenaar187db502016-02-27 14:44:26 +01002526 /* If there is no callback or buffer drop the message. */
2527 if (callback == NULL && buffer == NULL)
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002528 {
Bram Moolenaar437905c2016-04-26 19:01:05 +02002529 /* If there is a close callback it may use ch_read() to get the
2530 * messages. */
Bram Moolenaar958dc692016-12-01 15:34:12 +01002531 if (channel->ch_close_cb == NULL && !channel->ch_drop_never)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002532 drop_messages(channel, part);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002533 return FALSE;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002534 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002535
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002536 if (ch_mode == MODE_NL)
2537 {
Bram Moolenaarec68a992016-10-03 21:37:41 +02002538 char_u *nl = NULL;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002539 char_u *buf;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002540 readq_T *node;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002541
2542 /* See if we have a message ending in NL in the first buffer. If
2543 * not try to concatenate the first and the second buffer. */
2544 while (TRUE)
2545 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002546 node = channel_peek(channel, part);
2547 nl = channel_first_nl(node);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002548 if (nl != NULL)
2549 break;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002550 if (channel_collapse(channel, part, TRUE) == FAIL)
Bram Moolenaarec68a992016-10-03 21:37:41 +02002551 {
2552 if (ch_part->ch_fd == INVALID_FD && node->rq_buflen > 0)
2553 break;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002554 return FALSE; /* incomplete message */
Bram Moolenaarec68a992016-10-03 21:37:41 +02002555 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002556 }
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002557 buf = node->rq_buffer;
2558
Bram Moolenaarec68a992016-10-03 21:37:41 +02002559 if (nl == NULL)
2560 {
2561 /* Flush remaining message that is missing a NL. */
Bram Moolenaar866c6882017-04-07 14:02:01 +02002562 char_u *new_buf;
2563
2564 new_buf = vim_realloc(buf, node->rq_buflen + 1);
2565 if (new_buf == NULL)
2566 /* This might fail over and over again, should the message
2567 * be dropped? */
Bram Moolenaarec68a992016-10-03 21:37:41 +02002568 return FALSE;
Bram Moolenaar866c6882017-04-07 14:02:01 +02002569 buf = new_buf;
Bram Moolenaarec68a992016-10-03 21:37:41 +02002570 node->rq_buffer = buf;
2571 nl = buf + node->rq_buflen++;
2572 *nl = NUL;
2573 }
2574
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002575 /* Convert NUL to NL, the internal representation. */
2576 for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
2577 if (*p == NUL)
2578 *p = NL;
2579
2580 if (nl + 1 == buf + node->rq_buflen)
Bram Moolenaar187db502016-02-27 14:44:26 +01002581 {
2582 /* get the whole buffer, drop the NL */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002583 msg = channel_get(channel, part);
Bram Moolenaar187db502016-02-27 14:44:26 +01002584 *nl = NUL;
2585 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002586 else
2587 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002588 /* Copy the message into allocated memory (excluding the NL)
2589 * and remove it from the buffer (including the NL). */
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002590 msg = vim_strnsave(buf, (int)(nl - buf));
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002591 channel_consume(channel, part, (int)(nl - buf) + 1);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002592 }
2593 }
2594 else
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002595 {
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002596 /* For a raw channel we don't know where the message ends, just
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002597 * get everything we have.
2598 * Convert NUL to NL, the internal representation. */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002599 msg = channel_get_all(channel, part);
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002600 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002601
Bram Moolenaarbf73b912016-03-02 21:16:59 +01002602 if (msg == NULL)
2603 return FALSE; /* out of memory (and avoids Coverity warning) */
2604
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002605 argv[1].v_type = VAR_STRING;
2606 argv[1].vval.v_string = msg;
2607 }
2608
Bram Moolenaara07fec92016-02-05 21:04:08 +01002609 if (seq_nr > 0)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002610 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002611 int done = FALSE;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002612
Bram Moolenaar958dc692016-12-01 15:34:12 +01002613 /* JSON or JS mode: invoke the one-time callback with the matching nr */
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002614 for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002615 if (cbitem->cq_seq_nr == seq_nr)
Bram Moolenaara07fec92016-02-05 21:04:08 +01002616 {
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002617 invoke_one_time_callback(channel, cbhead, cbitem, argv);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002618 done = TRUE;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002619 break;
2620 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002621 if (!done)
Bram Moolenaar958dc692016-12-01 15:34:12 +01002622 {
2623 if (channel->ch_drop_never)
2624 {
2625 /* message must be read with ch_read() */
2626 channel_push_json(channel, part, listtv);
2627 listtv = NULL;
2628 }
2629 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002630 ch_log(channel, "Dropping message %d without callback",
Bram Moolenaar958dc692016-12-01 15:34:12 +01002631 seq_nr);
2632 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002633 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002634 else if (callback != NULL || buffer != NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002635 {
Bram Moolenaar187db502016-02-27 14:44:26 +01002636 if (buffer != NULL)
2637 {
Bram Moolenaarcc7f8be2016-02-29 22:55:56 +01002638 if (msg == NULL)
2639 /* JSON or JS mode: re-encode the message. */
2640 msg = json_encode(listtv, ch_mode);
2641 if (msg != NULL)
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002642 {
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02002643#ifdef FEAT_TERMINAL
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002644 if (buffer->b_term != NULL)
2645 write_to_term(buffer, msg, channel);
2646 else
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02002647#endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002648 append_to_buffer(buffer, msg, channel, part);
2649 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002650 }
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002651
Bram Moolenaar187db502016-02-27 14:44:26 +01002652 if (callback != NULL)
2653 {
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002654 if (cbitem != NULL)
2655 invoke_one_time_callback(channel, cbhead, cbitem, argv);
2656 else
2657 {
2658 /* invoke the channel callback */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002659 ch_log(channel, "Invoking channel callback %s",
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002660 (char *)callback);
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002661 invoke_callback(channel, callback, partial, argv);
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002662 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002663 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002664 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002665 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002666 ch_log(channel, "Dropping message %d", seq_nr);
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002667
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002668 if (listtv != NULL)
Bram Moolenaar77073442016-02-13 23:23:53 +01002669 free_tv(listtv);
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002670 vim_free(msg);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002671
2672 return TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002673}
2674
2675/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002676 * Return TRUE when channel "channel" is open for writing to.
2677 * Also returns FALSE or invalid "channel".
Bram Moolenaard04a0202016-01-26 23:30:18 +01002678 */
2679 int
Bram Moolenaar77073442016-02-13 23:23:53 +01002680channel_can_write_to(channel_T *channel)
Bram Moolenaard04a0202016-01-26 23:30:18 +01002681{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002682 return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01002683 || channel->CH_IN_FD != INVALID_FD);
Bram Moolenaard04a0202016-01-26 23:30:18 +01002684}
2685
2686/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002687 * Return TRUE when channel "channel" is open for reading or writing.
2688 * Also returns FALSE for invalid "channel".
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002689 */
2690 int
Bram Moolenaar77073442016-02-13 23:23:53 +01002691channel_is_open(channel_T *channel)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002692{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002693 return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002694 || channel->CH_IN_FD != INVALID_FD
2695 || channel->CH_OUT_FD != INVALID_FD
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01002696 || channel->CH_ERR_FD != INVALID_FD);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002697}
2698
2699/*
Bram Moolenaar437905c2016-04-26 19:01:05 +02002700 * Return TRUE if "channel" has JSON or other typeahead.
2701 */
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002702 int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002703channel_has_readahead(channel_T *channel, ch_part_T part)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002704{
2705 ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
2706
2707 if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
2708 {
2709 jsonq_T *head = &channel->ch_part[part].ch_json_head;
2710 jsonq_T *item = head->jq_next;
2711
2712 return item != NULL;
2713 }
2714 return channel_peek(channel, part) != NULL;
2715}
2716
2717/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002718 * Return a string indicating the status of the channel.
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002719 * If "req_part" is not negative check that part.
Bram Moolenaar77073442016-02-13 23:23:53 +01002720 */
2721 char *
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002722channel_status(channel_T *channel, int req_part)
Bram Moolenaar77073442016-02-13 23:23:53 +01002723{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002724 ch_part_T part;
Bram Moolenaar437905c2016-04-26 19:01:05 +02002725 int has_readahead = FALSE;
2726
Bram Moolenaar77073442016-02-13 23:23:53 +01002727 if (channel == NULL)
2728 return "fail";
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002729 if (req_part == PART_OUT)
2730 {
2731 if (channel->CH_OUT_FD != INVALID_FD)
2732 return "open";
2733 if (channel_has_readahead(channel, PART_OUT))
Bram Moolenaar437905c2016-04-26 19:01:05 +02002734 has_readahead = TRUE;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002735 }
2736 else if (req_part == PART_ERR)
2737 {
2738 if (channel->CH_ERR_FD != INVALID_FD)
2739 return "open";
2740 if (channel_has_readahead(channel, PART_ERR))
2741 has_readahead = TRUE;
2742 }
2743 else
2744 {
2745 if (channel_is_open(channel))
2746 return "open";
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002747 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002748 if (channel_has_readahead(channel, part))
2749 {
2750 has_readahead = TRUE;
2751 break;
2752 }
2753 }
Bram Moolenaar437905c2016-04-26 19:01:05 +02002754
2755 if (has_readahead)
2756 return "buffered";
Bram Moolenaar77073442016-02-13 23:23:53 +01002757 return "closed";
2758}
2759
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002760 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002761channel_part_info(channel_T *channel, dict_T *dict, char *name, ch_part_T part)
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002762{
2763 chanpart_T *chanpart = &channel->ch_part[part];
Bram Moolenaar925ccfd2016-03-28 22:38:02 +02002764 char namebuf[20]; /* longest is "sock_timeout" */
Bram Moolenaar3f3fbd32016-03-21 12:36:28 +01002765 size_t tail;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002766 char *status;
Bram Moolenaar573e4452016-03-21 22:35:10 +01002767 char *s = "";
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002768
Bram Moolenaar925ccfd2016-03-28 22:38:02 +02002769 vim_strncpy((char_u *)namebuf, (char_u *)name, 4);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002770 STRCAT(namebuf, "_");
2771 tail = STRLEN(namebuf);
2772
2773 STRCPY(namebuf + tail, "status");
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002774 if (chanpart->ch_fd != INVALID_FD)
2775 status = "open";
2776 else if (channel_has_readahead(channel, part))
2777 status = "buffered";
2778 else
2779 status = "closed";
2780 dict_add_nr_str(dict, namebuf, 0, (char_u *)status);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002781
2782 STRCPY(namebuf + tail, "mode");
2783 switch (chanpart->ch_mode)
2784 {
2785 case MODE_NL: s = "NL"; break;
2786 case MODE_RAW: s = "RAW"; break;
2787 case MODE_JSON: s = "JSON"; break;
2788 case MODE_JS: s = "JS"; break;
2789 }
2790 dict_add_nr_str(dict, namebuf, 0, (char_u *)s);
2791
2792 STRCPY(namebuf + tail, "io");
2793 if (part == PART_SOCK)
2794 s = "socket";
2795 else switch (chanpart->ch_io)
2796 {
2797 case JIO_NULL: s = "null"; break;
2798 case JIO_PIPE: s = "pipe"; break;
2799 case JIO_FILE: s = "file"; break;
2800 case JIO_BUFFER: s = "buffer"; break;
2801 case JIO_OUT: s = "out"; break;
2802 }
2803 dict_add_nr_str(dict, namebuf, 0, (char_u *)s);
2804
2805 STRCPY(namebuf + tail, "timeout");
2806 dict_add_nr_str(dict, namebuf, chanpart->ch_timeout, NULL);
2807}
2808
2809 void
2810channel_info(channel_T *channel, dict_T *dict)
2811{
2812 dict_add_nr_str(dict, "id", channel->ch_id, NULL);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002813 dict_add_nr_str(dict, "status", 0, (char_u *)channel_status(channel, -1));
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002814
2815 if (channel->ch_hostname != NULL)
2816 {
2817 dict_add_nr_str(dict, "hostname", 0, (char_u *)channel->ch_hostname);
2818 dict_add_nr_str(dict, "port", channel->ch_port, NULL);
2819 channel_part_info(channel, dict, "sock", PART_SOCK);
2820 }
2821 else
2822 {
2823 channel_part_info(channel, dict, "out", PART_OUT);
2824 channel_part_info(channel, dict, "err", PART_ERR);
2825 channel_part_info(channel, dict, "in", PART_IN);
2826 }
2827}
2828
Bram Moolenaar77073442016-02-13 23:23:53 +01002829/*
2830 * Close channel "channel".
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +01002831 * Trigger the close callback if "invoke_close_cb" is TRUE.
Bram Moolenaar187db502016-02-27 14:44:26 +01002832 * Does not clear the buffers.
Bram Moolenaard04a0202016-01-26 23:30:18 +01002833 */
2834 void
Bram Moolenaar8b374212016-02-24 20:43:06 +01002835channel_close(channel_T *channel, int invoke_close_cb)
Bram Moolenaard04a0202016-01-26 23:30:18 +01002836{
Bram Moolenaar81661fb2016-02-18 22:23:34 +01002837 ch_log(channel, "Closing channel");
Bram Moolenaard04a0202016-01-26 23:30:18 +01002838
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01002839#ifdef FEAT_GUI
2840 channel_gui_unregister(channel);
2841#endif
2842
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002843 ch_close_part(channel, PART_SOCK);
2844 ch_close_part(channel, PART_IN);
2845 ch_close_part(channel, PART_OUT);
2846 ch_close_part(channel, PART_ERR);
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01002847
Bram Moolenaara9f02812017-08-05 17:40:38 +02002848 if (invoke_close_cb)
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002849 {
Bram Moolenaara9f02812017-08-05 17:40:38 +02002850 ch_part_T part;
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002851
Bram Moolenaara9f02812017-08-05 17:40:38 +02002852 /* Invoke callbacks and flush buffers before the close callback. */
2853 if (channel->ch_close_cb != NULL)
2854 ch_log(channel,
2855 "Invoking callbacks and flushing buffers before closing");
2856 for (part = PART_SOCK; part < PART_IN; ++part)
2857 {
2858 if (channel->ch_close_cb != NULL
2859 || channel->ch_part[part].ch_bufref.br_buf != NULL)
2860 {
2861 /* Increment the refcount to avoid the channel being freed
2862 * halfway. */
2863 ++channel->ch_refcount;
2864 if (channel->ch_close_cb == NULL)
2865 ch_log(channel, "flushing %s buffers before closing",
2866 part_names[part]);
2867 while (may_invoke_callback(channel, part))
2868 ;
2869 --channel->ch_refcount;
2870 }
2871 }
Bram Moolenaarb2658a12016-04-26 17:16:24 +02002872
Bram Moolenaara9f02812017-08-05 17:40:38 +02002873 if (channel->ch_close_cb != NULL)
2874 {
2875 typval_T argv[1];
2876 typval_T rettv;
2877 int dummy;
2878
2879 /* Increment the refcount to avoid the channel being freed
2880 * halfway. */
2881 ++channel->ch_refcount;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002882 ch_log(channel, "Invoking close callback %s",
Bram Moolenaarb2658a12016-04-26 17:16:24 +02002883 (char *)channel->ch_close_cb);
2884 argv[0].v_type = VAR_CHANNEL;
2885 argv[0].vval.v_channel = channel;
2886 call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02002887 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002888 channel->ch_close_partial, NULL);
Bram Moolenaarb2658a12016-04-26 17:16:24 +02002889 clear_tv(&rettv);
Bram Moolenaarcefe4f92016-05-04 21:49:19 +02002890 channel_need_redraw = TRUE;
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002891
Bram Moolenaara9f02812017-08-05 17:40:38 +02002892 /* the callback is only called once */
2893 free_callback(channel->ch_close_cb, channel->ch_close_partial);
2894 channel->ch_close_cb = NULL;
2895 channel->ch_close_partial = NULL;
Bram Moolenaar437905c2016-04-26 19:01:05 +02002896
Bram Moolenaara9f02812017-08-05 17:40:38 +02002897 --channel->ch_refcount;
Bram Moolenaar28ae5772016-05-28 14:16:10 +02002898
Bram Moolenaara9f02812017-08-05 17:40:38 +02002899 if (channel_need_redraw)
2900 {
2901 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02002902 redraw_after_callback(TRUE);
Bram Moolenaara9f02812017-08-05 17:40:38 +02002903 }
Bram Moolenaarcefe4f92016-05-04 21:49:19 +02002904
Bram Moolenaara9f02812017-08-05 17:40:38 +02002905 if (!channel->ch_drop_never)
2906 /* any remaining messages are useless now */
2907 for (part = PART_SOCK; part < PART_IN; ++part)
2908 drop_messages(channel, part);
2909 }
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002910 }
2911
2912 channel->ch_nb_close_cb = NULL;
Bram Moolenaard85f2712017-07-28 21:51:57 +02002913
2914#ifdef FEAT_TERMINAL
2915 term_channel_closed(channel);
2916#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +01002917}
2918
Bram Moolenaard04a0202016-01-26 23:30:18 +01002919/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002920 * Close the "in" part channel "channel".
2921 */
2922 void
2923channel_close_in(channel_T *channel)
2924{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002925 ch_close_part(channel, PART_IN);
Bram Moolenaar0874a832016-09-01 15:11:51 +02002926}
2927
2928/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002929 * Clear the read buffer on "channel"/"part".
Bram Moolenaard04a0202016-01-26 23:30:18 +01002930 */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002931 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002932channel_clear_one(channel_T *channel, ch_part_T part)
Bram Moolenaard04a0202016-01-26 23:30:18 +01002933{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002934 jsonq_T *json_head = &channel->ch_part[part].ch_json_head;
2935 cbq_T *cb_head = &channel->ch_part[part].ch_cb_head;
Bram Moolenaard04a0202016-01-26 23:30:18 +01002936
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002937 while (channel_peek(channel, part) != NULL)
2938 vim_free(channel_get(channel, part));
Bram Moolenaar77073442016-02-13 23:23:53 +01002939
2940 while (cb_head->cq_next != NULL)
Bram Moolenaard46ae142016-02-16 13:33:52 +01002941 {
2942 cbq_T *node = cb_head->cq_next;
2943
2944 remove_cb_node(cb_head, node);
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02002945 free_callback(node->cq_callback, node->cq_partial);
Bram Moolenaard46ae142016-02-16 13:33:52 +01002946 vim_free(node);
2947 }
Bram Moolenaar77073442016-02-13 23:23:53 +01002948
2949 while (json_head->jq_next != NULL)
Bram Moolenaard04a0202016-01-26 23:30:18 +01002950 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002951 free_tv(json_head->jq_next->jq_value);
2952 remove_json_node(json_head, json_head->jq_next);
Bram Moolenaard04a0202016-01-26 23:30:18 +01002953 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01002954
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02002955 free_callback(channel->ch_part[part].ch_callback,
2956 channel->ch_part[part].ch_partial);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002957 channel->ch_part[part].ch_callback = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002958 channel->ch_part[part].ch_partial = NULL;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002959}
2960
2961/*
2962 * Clear all the read buffers on "channel".
2963 */
2964 void
2965channel_clear(channel_T *channel)
2966{
Bram Moolenaard6051b52016-02-28 15:49:03 +01002967 ch_log(channel, "Clearing channel");
Bram Moolenaar03602ec2016-03-20 20:57:45 +01002968 vim_free(channel->ch_hostname);
2969 channel->ch_hostname = NULL;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002970 channel_clear_one(channel, PART_SOCK);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002971 channel_clear_one(channel, PART_OUT);
2972 channel_clear_one(channel, PART_ERR);
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02002973 /* there is no callback or queue for PART_IN */
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02002974 free_callback(channel->ch_callback, channel->ch_partial);
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01002975 channel->ch_callback = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002976 channel->ch_partial = NULL;
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02002977 free_callback(channel->ch_close_cb, channel->ch_close_partial);
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002978 channel->ch_close_cb = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01002979 channel->ch_close_partial = NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +01002980}
2981
Bram Moolenaar77073442016-02-13 23:23:53 +01002982#if defined(EXITFREE) || defined(PROTO)
2983 void
2984channel_free_all(void)
2985{
2986 channel_T *channel;
2987
Bram Moolenaard6051b52016-02-28 15:49:03 +01002988 ch_log(NULL, "channel_free_all()");
Bram Moolenaar77073442016-02-13 23:23:53 +01002989 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
2990 channel_clear(channel);
2991}
2992#endif
2993
2994
Bram Moolenaar715d2852016-04-30 17:06:31 +02002995/* Sent when the netbeans channel is found closed when reading. */
Bram Moolenaareed284a2016-02-22 23:13:33 +01002996#define DETACH_MSG_RAW "DETACH\n"
Bram Moolenaard04a0202016-01-26 23:30:18 +01002997
2998/* Buffer size for reading incoming messages. */
2999#define MAXMSGSIZE 4096
3000
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003001#if defined(HAVE_SELECT)
3002/*
3003 * Add write fds where we are waiting for writing to be possible.
3004 */
3005 static int
3006channel_fill_wfds(int maxfd_arg, fd_set *wfds)
3007{
3008 int maxfd = maxfd_arg;
3009 channel_T *ch;
3010
3011 for (ch = first_channel; ch != NULL; ch = ch->ch_next)
3012 {
3013 chanpart_T *in_part = &ch->ch_part[PART_IN];
3014
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003015 if (in_part->ch_fd != INVALID_FD
3016 && (in_part->ch_bufref.br_buf != NULL
3017 || in_part->ch_writeque.wq_next != NULL))
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003018 {
3019 FD_SET((int)in_part->ch_fd, wfds);
3020 if ((int)in_part->ch_fd >= maxfd)
3021 maxfd = (int)in_part->ch_fd + 1;
3022 }
3023 }
3024 return maxfd;
3025}
3026#else
3027/*
3028 * Add write fds where we are waiting for writing to be possible.
3029 */
3030 static int
3031channel_fill_poll_write(int nfd_in, struct pollfd *fds)
3032{
3033 int nfd = nfd_in;
3034 channel_T *ch;
3035
3036 for (ch = first_channel; ch != NULL; ch = ch->ch_next)
3037 {
3038 chanpart_T *in_part = &ch->ch_part[PART_IN];
3039
Bram Moolenaar683b7962017-08-19 15:51:59 +02003040 if (in_part->ch_fd != INVALID_FD
3041 && (in_part->ch_bufref.br_buf != NULL
3042 || in_part->ch_writeque.wq_next != NULL))
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003043 {
3044 in_part->ch_poll_idx = nfd;
3045 fds[nfd].fd = in_part->ch_fd;
3046 fds[nfd].events = POLLOUT;
3047 ++nfd;
3048 }
3049 else
3050 in_part->ch_poll_idx = -1;
3051 }
3052 return nfd;
3053}
3054#endif
3055
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003056typedef enum {
3057 CW_READY,
3058 CW_NOT_READY,
3059 CW_ERROR
3060} channel_wait_result;
3061
Bram Moolenaard04a0202016-01-26 23:30:18 +01003062/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003063 * Check for reading from "fd" with "timeout" msec.
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003064 * Return CW_READY when there is something to read.
3065 * Return CW_NOT_READY when there is nothing to read.
3066 * Return CW_ERROR when there is an error.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003067 */
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003068 static channel_wait_result
Bram Moolenaard8070362016-02-15 21:56:54 +01003069channel_wait(channel_T *channel, sock_T fd, int timeout)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003070{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003071 if (timeout > 0)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003072 ch_log(channel, "Waiting for up to %d msec", timeout);
Bram Moolenaard8070362016-02-15 21:56:54 +01003073
Bram Moolenaard8070362016-02-15 21:56:54 +01003074# ifdef WIN32
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003075 if (fd != channel->CH_SOCK_FD)
Bram Moolenaard8070362016-02-15 21:56:54 +01003076 {
3077 DWORD nread;
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003078 int sleep_time;
Bram Moolenaard8070362016-02-15 21:56:54 +01003079 DWORD deadline = GetTickCount() + timeout;
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003080 int delay = 1;
Bram Moolenaard8070362016-02-15 21:56:54 +01003081
3082 /* reading from a pipe, not a socket */
3083 while (TRUE)
3084 {
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003085 int r = PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL);
3086
3087 if (r && nread > 0)
3088 return CW_READY;
3089 if (r == 0)
3090 return CW_ERROR;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003091
3092 /* perhaps write some buffer lines */
3093 channel_write_any_lines();
3094
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003095 sleep_time = deadline - GetTickCount();
3096 if (sleep_time <= 0)
Bram Moolenaard8070362016-02-15 21:56:54 +01003097 break;
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003098 /* Wait for a little while. Very short at first, up to 10 msec
3099 * after looping a few times. */
3100 if (sleep_time > delay)
3101 sleep_time = delay;
3102 Sleep(sleep_time);
3103 delay = delay * 2;
3104 if (delay > 10)
3105 delay = 10;
Bram Moolenaard8070362016-02-15 21:56:54 +01003106 }
Bram Moolenaard8070362016-02-15 21:56:54 +01003107 }
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003108 else
Bram Moolenaard8070362016-02-15 21:56:54 +01003109#endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003110 {
Bram Moolenaar9186a272016-02-23 19:34:01 +01003111#if defined(HAVE_SELECT)
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003112 struct timeval tval;
3113 fd_set rfds;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003114 fd_set wfds;
3115 int ret;
3116 int maxfd;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003117
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003118 tval.tv_sec = timeout / 1000;
3119 tval.tv_usec = (timeout % 1000) * 1000;
3120 for (;;)
3121 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003122 FD_ZERO(&rfds);
3123 FD_SET((int)fd, &rfds);
3124
3125 /* Write lines to a pipe when a pipe can be written to. Need to
3126 * set this every time, some buffers may be done. */
3127 maxfd = (int)fd + 1;
3128 FD_ZERO(&wfds);
3129 maxfd = channel_fill_wfds(maxfd, &wfds);
3130
3131 ret = select(maxfd, &rfds, &wfds, NULL, &tval);
Bram Moolenaar9186a272016-02-23 19:34:01 +01003132# ifdef EINTR
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003133 SOCK_ERRNO;
3134 if (ret == -1 && errno == EINTR)
3135 continue;
Bram Moolenaar9186a272016-02-23 19:34:01 +01003136# endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003137 if (ret > 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003138 {
3139 if (FD_ISSET(fd, &rfds))
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003140 return CW_READY;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003141 channel_write_any_lines();
3142 continue;
3143 }
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003144 break;
3145 }
Bram Moolenaar9186a272016-02-23 19:34:01 +01003146#else
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003147 for (;;)
3148 {
3149 struct pollfd fds[MAX_OPEN_CHANNELS + 1];
3150 int nfd = 1;
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003151
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003152 fds[0].fd = fd;
3153 fds[0].events = POLLIN;
3154 nfd = channel_fill_poll_write(nfd, fds);
3155 if (poll(fds, nfd, timeout) > 0)
3156 {
3157 if (fds[0].revents & POLLIN)
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003158 return CW_READY;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003159 channel_write_any_lines();
3160 continue;
3161 }
3162 break;
3163 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003164#endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003165 }
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003166 return CW_NOT_READY;
3167}
3168
3169 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003170ch_close_part_on_error(
3171 channel_T *channel, ch_part_T part, int is_err, char *func)
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003172{
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003173 char msg[] = "%s(): Read %s from ch_part[%d], closing";
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003174
3175 if (is_err)
3176 /* Do not call emsg(), most likely the other end just exited. */
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003177 ch_error(channel, msg, func, "error", part);
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003178 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003179 ch_log(channel, msg, func, "EOF", part);
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003180
3181 /* Queue a "DETACH" netbeans message in the command queue in order to
3182 * terminate the netbeans session later. Do not end the session here
3183 * directly as we may be running in the context of a call to
3184 * netbeans_parse_messages():
3185 * netbeans_parse_messages
3186 * -> autocmd triggered while processing the netbeans cmd
3187 * -> ui_breakcheck
3188 * -> gui event loop or select loop
3189 * -> channel_read()
Bram Moolenaar715d2852016-04-30 17:06:31 +02003190 * Only send "DETACH" for a netbeans channel.
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003191 */
Bram Moolenaar715d2852016-04-30 17:06:31 +02003192 if (channel->ch_nb_close_cb != NULL)
Bram Moolenaar8ddef482016-10-09 15:43:25 +02003193 channel_save(channel, PART_SOCK, (char_u *)DETACH_MSG_RAW,
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003194 (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
3195
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003196 /* When reading is not possible close this part of the channel. Don't
3197 * close the channel yet, there may be something to read on another part. */
3198 ch_close_part(channel, part);
Bram Moolenaarbf981ee2016-05-28 13:20:31 +02003199
3200#ifdef FEAT_GUI
3201 /* Stop listening to GUI events right away. */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003202 channel_gui_unregister_one(channel, part);
Bram Moolenaarbf981ee2016-05-28 13:20:31 +02003203#endif
Bram Moolenaarcf7ff702016-05-09 17:20:14 +02003204}
3205
3206 static void
3207channel_close_now(channel_T *channel)
3208{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003209 ch_log(channel, "Closing channel because all readable fds are closed");
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003210 if (channel->ch_nb_close_cb != NULL)
3211 (*channel->ch_nb_close_cb)();
Bram Moolenaar958dc692016-12-01 15:34:12 +01003212 channel_close(channel, TRUE);
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003213}
3214
3215/*
Bram Moolenaar77073442016-02-13 23:23:53 +01003216 * Read from channel "channel" for as long as there is something to read.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003217 * "part" is PART_SOCK, PART_OUT or PART_ERR.
Bram Moolenaar655da312016-05-28 22:22:34 +02003218 * The data is put in the read queue. No callbacks are invoked here.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003219 */
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003220 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003221channel_read(channel_T *channel, ch_part_T part, char *func)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003222{
3223 static char_u *buf = NULL;
3224 int len = 0;
3225 int readlen = 0;
Bram Moolenaard8070362016-02-15 21:56:54 +01003226 sock_T fd;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003227 int use_socket = FALSE;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003228
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003229 fd = channel->ch_part[part].ch_fd;
3230 if (fd == INVALID_FD)
3231 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003232 ch_error(channel, "channel_read() called while %s part is closed",
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003233 part_names[part]);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003234 return;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003235 }
3236 use_socket = fd == channel->CH_SOCK_FD;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003237
3238 /* Allocate a buffer to read into. */
3239 if (buf == NULL)
3240 {
3241 buf = alloc(MAXMSGSIZE);
3242 if (buf == NULL)
3243 return; /* out of memory! */
3244 }
3245
3246 /* Keep on reading for as long as there is something to read.
3247 * Use select() or poll() to avoid blocking on a message that is exactly
3248 * MAXMSGSIZE long. */
3249 for (;;)
3250 {
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003251 if (channel_wait(channel, fd, 0) != CW_READY)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003252 break;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003253 if (use_socket)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003254 len = sock_read(fd, (char *)buf, MAXMSGSIZE);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003255 else
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003256 len = fd_read(fd, (char *)buf, MAXMSGSIZE);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003257 if (len <= 0)
3258 break; /* error or nothing more to read */
3259
3260 /* Store the read message in the queue. */
Bram Moolenaar46c00a62016-03-28 14:11:42 +02003261 channel_save(channel, part, buf, len, FALSE, "RECV ");
Bram Moolenaard04a0202016-01-26 23:30:18 +01003262 readlen += len;
3263 if (len < MAXMSGSIZE)
3264 break; /* did read everything that's available */
3265 }
3266
Bram Moolenaar4cafa6d2016-02-26 11:52:39 +01003267 /* Reading a disconnection (readlen == 0), or an error. */
Bram Moolenaarbd73ae12016-02-22 22:19:22 +01003268 if (readlen <= 0)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003269 {
3270 if (!channel->ch_keep_open)
3271 ch_close_part_on_error(channel, part, (len < 0), func);
3272 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01003273#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003274 else if (CH_HAS_GUI && gtk_main_level() > 0)
3275 /* signal the main loop that there is something to read */
Bram Moolenaard04a0202016-01-26 23:30:18 +01003276 gtk_main_quit();
3277#endif
3278}
3279
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003280/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003281 * Read from RAW or NL "channel"/"part". Blocks until there is something to
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003282 * read or the timeout expires.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003283 * Returns what was read in allocated memory.
3284 * Returns NULL in case of error or timeout.
3285 */
3286 char_u *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003287channel_read_block(channel_T *channel, ch_part_T part, int timeout)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003288{
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003289 char_u *buf;
3290 char_u *msg;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003291 ch_mode_T mode = channel->ch_part[part].ch_mode;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003292 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003293 char_u *nl;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003294 readq_T *node;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003295
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003296 ch_log(channel, "Blocking %s read, timeout: %d msec",
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003297 mode == MODE_RAW ? "RAW" : "NL", timeout);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003298
3299 while (TRUE)
3300 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003301 node = channel_peek(channel, part);
3302 if (node != NULL)
3303 {
3304 if (mode == MODE_RAW || (mode == MODE_NL
3305 && channel_first_nl(node) != NULL))
3306 /* got a complete message */
3307 break;
3308 if (channel_collapse(channel, part, mode == MODE_NL) == OK)
3309 continue;
3310 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003311
Bram Moolenaar4d919d72016-02-05 22:36:41 +01003312 /* Wait for up to the channel timeout. */
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003313 if (fd == INVALID_FD)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003314 return NULL;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003315 if (channel_wait(channel, fd, timeout) != CW_READY)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003316 {
3317 ch_log(channel, "Timed out");
3318 return NULL;
3319 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003320 channel_read(channel, part, "channel_read_block");
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003321 }
3322
Bram Moolenaarb113c3a2017-02-28 21:26:17 +01003323 /* We have a complete message now. */
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003324 if (mode == MODE_RAW)
3325 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003326 msg = channel_get_all(channel, part);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003327 }
3328 else
3329 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003330 char_u *p;
3331
3332 buf = node->rq_buffer;
3333 nl = channel_first_nl(node);
3334
3335 /* Convert NUL to NL, the internal representation. */
3336 for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
3337 if (*p == NUL)
3338 *p = NL;
3339
3340 if (nl + 1 == buf + node->rq_buflen)
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003341 {
3342 /* get the whole buffer */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003343 msg = channel_get(channel, part);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003344 *nl = NUL;
3345 }
3346 else
3347 {
3348 /* Copy the message into allocated memory and remove it from the
3349 * buffer. */
3350 msg = vim_strnsave(buf, (int)(nl - buf));
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003351 channel_consume(channel, part, (int)(nl - buf) + 1);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003352 }
3353 }
3354 if (log_fd != NULL)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003355 ch_log(channel, "Returning %d bytes", (int)STRLEN(msg));
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003356 return msg;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003357}
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003358
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003359/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003360 * Read one JSON message with ID "id" from "channel"/"part" and store the
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003361 * result in "rettv".
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01003362 * When "id" is -1 accept any message;
Bram Moolenaar4d919d72016-02-05 22:36:41 +01003363 * Blocks until the message is received or the timeout is reached.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003364 */
Bram Moolenaar958dc692016-12-01 15:34:12 +01003365 static int
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01003366channel_read_json_block(
Bram Moolenaard6051b52016-02-28 15:49:03 +01003367 channel_T *channel,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003368 ch_part_T part,
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003369 int timeout_arg,
Bram Moolenaard6051b52016-02-28 15:49:03 +01003370 int id,
3371 typval_T **rettv)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003372{
Bram Moolenaare56bf152016-02-08 23:23:42 +01003373 int more;
Bram Moolenaard8070362016-02-15 21:56:54 +01003374 sock_T fd;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003375 int timeout;
3376 chanpart_T *chanpart = &channel->ch_part[part];
Bram Moolenaard7ece102016-02-02 23:23:02 +01003377
Bram Moolenaar81661fb2016-02-18 22:23:34 +01003378 ch_log(channel, "Reading JSON");
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01003379 if (id != -1)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003380 chanpart->ch_block_id = id;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003381 for (;;)
3382 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003383 more = channel_parse_json(channel, part);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003384
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02003385 /* search for message "id" */
Bram Moolenaar958dc692016-12-01 15:34:12 +01003386 if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
Bram Moolenaare56bf152016-02-08 23:23:42 +01003387 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003388 chanpart->ch_block_id = 0;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003389 return OK;
Bram Moolenaare56bf152016-02-08 23:23:42 +01003390 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003391
Bram Moolenaard7ece102016-02-02 23:23:02 +01003392 if (!more)
3393 {
3394 /* Handle any other messages in the queue. If done some more
3395 * messages may have arrived. */
3396 if (channel_parse_messages())
3397 continue;
3398
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003399 /* Wait for up to the timeout. If there was an incomplete message
3400 * use the deadline for that. */
3401 timeout = timeout_arg;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01003402 if (chanpart->ch_wait_len > 0)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003403 {
3404#ifdef WIN32
3405 timeout = chanpart->ch_deadline - GetTickCount() + 1;
3406#else
3407 {
3408 struct timeval now_tv;
3409
3410 gettimeofday(&now_tv, NULL);
3411 timeout = (chanpart->ch_deadline.tv_sec
3412 - now_tv.tv_sec) * 1000
3413 + (chanpart->ch_deadline.tv_usec
3414 - now_tv.tv_usec) / 1000
3415 + 1;
3416 }
3417#endif
3418 if (timeout < 0)
3419 {
3420 /* Something went wrong, channel_parse_json() didn't
3421 * discard message. Cancel waiting. */
Bram Moolenaar88989cc2017-02-06 21:56:09 +01003422 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003423 timeout = timeout_arg;
3424 }
3425 else if (timeout > timeout_arg)
3426 timeout = timeout_arg;
3427 }
3428 fd = chanpart->ch_fd;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003429 if (fd == INVALID_FD
3430 || channel_wait(channel, fd, timeout) != CW_READY)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003431 {
3432 if (timeout == timeout_arg)
3433 {
3434 if (fd != INVALID_FD)
3435 ch_log(channel, "Timed out");
3436 break;
3437 }
3438 }
3439 else
3440 channel_read(channel, part, "channel_read_json_block");
Bram Moolenaard7ece102016-02-02 23:23:02 +01003441 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003442 }
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003443 chanpart->ch_block_id = 0;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003444 return FAIL;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003445}
3446
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003447/*
3448 * Common for ch_read() and ch_readraw().
3449 */
3450 void
3451common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
3452{
3453 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003454 ch_part_T part = PART_COUNT;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003455 jobopt_T opt;
3456 int mode;
3457 int timeout;
3458 int id = -1;
3459 typval_T *listtv = NULL;
3460
3461 /* return an empty string by default */
3462 rettv->v_type = VAR_STRING;
3463 rettv->vval.v_string = NULL;
3464
3465 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02003466 if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID, 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003467 == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003468 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003469
Bram Moolenaar437905c2016-04-26 19:01:05 +02003470 if (opt.jo_set & JO_PART)
3471 part = opt.jo_part;
3472 channel = get_channel_arg(&argvars[0], TRUE, TRUE, part);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003473 if (channel != NULL)
3474 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003475 if (part == PART_COUNT)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003476 part = channel_part_read(channel);
3477 mode = channel_get_mode(channel, part);
3478 timeout = channel_get_timeout(channel, part);
3479 if (opt.jo_set & JO_TIMEOUT)
3480 timeout = opt.jo_timeout;
3481
3482 if (raw || mode == MODE_RAW || mode == MODE_NL)
3483 rettv->vval.v_string = channel_read_block(channel, part, timeout);
3484 else
3485 {
3486 if (opt.jo_set & JO_ID)
3487 id = opt.jo_id;
3488 channel_read_json_block(channel, part, timeout, id, &listtv);
3489 if (listtv != NULL)
3490 {
3491 *rettv = *listtv;
3492 vim_free(listtv);
3493 }
3494 else
3495 {
3496 rettv->v_type = VAR_SPECIAL;
3497 rettv->vval.v_number = VVAL_NONE;
3498 }
3499 }
3500 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003501
3502theend:
3503 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003504}
3505
Bram Moolenaarfffd5562016-02-20 18:44:39 +01003506# if defined(WIN32) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
3507 || defined(PROTO)
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003508/*
Bram Moolenaarfffd5562016-02-20 18:44:39 +01003509 * Lookup the channel from the socket. Set "partp" to the fd index.
Bram Moolenaar77073442016-02-13 23:23:53 +01003510 * Returns NULL when the socket isn't found.
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003511 */
Bram Moolenaar77073442016-02-13 23:23:53 +01003512 channel_T *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003513channel_fd2channel(sock_T fd, ch_part_T *partp)
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003514{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003515 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003516 ch_part_T part;
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003517
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003518 if (fd != INVALID_FD)
Bram Moolenaar77073442016-02-13 23:23:53 +01003519 for (channel = first_channel; channel != NULL;
3520 channel = channel->ch_next)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003521 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003522 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003523 if (channel->ch_part[part].ch_fd == fd)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003524 {
Bram Moolenaarfffd5562016-02-20 18:44:39 +01003525 *partp = part;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003526 return channel;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003527 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003528 }
Bram Moolenaar77073442016-02-13 23:23:53 +01003529 return NULL;
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003530}
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003531# endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003532
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003533# if defined(WIN32) || defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003534/*
3535 * Check the channels for anything that is ready to be read.
3536 * The data is put in the read queue.
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003537 * if "only_keep_open" is TRUE only check channels where ch_keep_open is set.
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003538 */
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003539 void
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003540channel_handle_events(int only_keep_open)
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003541{
3542 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003543 ch_part_T part;
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003544 sock_T fd;
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003545
3546 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
3547 {
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003548 if (only_keep_open && !channel->ch_keep_open)
3549 continue;
3550
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003551 /* check the socket and pipes */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003552 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003553 {
3554 fd = channel->ch_part[part].ch_fd;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003555 if (fd != INVALID_FD)
3556 {
3557 int r = channel_wait(channel, fd, 0);
3558
3559 if (r == CW_READY)
3560 channel_read(channel, part, "channel_handle_events");
3561 else if (r == CW_ERROR)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003562 ch_close_part_on_error(channel, part, TRUE,
3563 "channel_handle_events");
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003564 }
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003565 }
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003566 }
3567}
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003568# endif
3569
Bram Moolenaar4ab79682017-08-27 14:50:47 +02003570# if defined(FEAT_GUI) || defined(PROTO)
3571/*
3572 * Return TRUE when there is any channel with a keep_open flag.
3573 */
3574 int
3575channel_any_keep_open()
3576{
3577 channel_T *channel;
3578
3579 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
3580 if (channel->ch_keep_open)
3581 return TRUE;
3582 return FALSE;
3583}
3584# endif
3585
Bram Moolenaard04a0202016-01-26 23:30:18 +01003586/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003587 * Set "channel"/"part" to non-blocking.
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02003588 * Only works for sockets and pipes.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003589 */
3590 void
3591channel_set_nonblock(channel_T *channel, ch_part_T part)
3592{
3593 chanpart_T *ch_part = &channel->ch_part[part];
3594 int fd = ch_part->ch_fd;
3595
3596 if (fd != INVALID_FD)
3597 {
3598#ifdef _WIN32
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02003599 u_long val = 1;
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003600
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02003601 ioctlsocket(fd, FIONBIO, &val);
3602#else
Bram Moolenaardc926dd2017-08-19 21:26:44 +02003603 (void)fcntl(fd, F_SETFL, O_NONBLOCK);
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003604#endif
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003605 ch_part->ch_nonblocking = TRUE;
3606 }
3607}
3608
3609/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003610 * Write "buf" (NUL terminated string) to "channel"/"part".
Bram Moolenaard04a0202016-01-26 23:30:18 +01003611 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003612 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003613 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003614 int
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01003615channel_send(
3616 channel_T *channel,
3617 ch_part_T part,
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003618 char_u *buf_arg,
3619 int len_arg,
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01003620 char *fun)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003621{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003622 int res;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003623 sock_T fd;
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003624 chanpart_T *ch_part = &channel->ch_part[part];
3625 int did_use_queue = FALSE;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003626
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003627 fd = ch_part->ch_fd;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003628 if (fd == INVALID_FD)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003629 {
3630 if (!channel->ch_error && fun != NULL)
3631 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003632 ch_error(channel, "%s(): write while not connected", fun);
Bram Moolenaar5b302912016-08-24 22:11:55 +02003633 EMSG2(_("E630: %s(): write while not connected"), fun);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003634 }
3635 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003636 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003637 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003638
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003639 if (log_fd != NULL)
3640 {
Bram Moolenaar77073442016-02-13 23:23:53 +01003641 ch_log_lead("SEND ", channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003642 fprintf(log_fd, "'");
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003643 ignored = (int)fwrite(buf_arg, len_arg, 1, log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003644 fprintf(log_fd, "'\n");
3645 fflush(log_fd);
Bram Moolenaard0b65022016-03-06 21:50:33 +01003646 did_log_msg = TRUE;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003647 }
3648
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003649 for (;;)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003650 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003651 writeq_T *wq = &ch_part->ch_writeque;
3652 char_u *buf;
3653 int len;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003654
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003655 if (wq->wq_next != NULL)
3656 {
3657 /* first write what was queued */
3658 buf = wq->wq_next->wq_ga.ga_data;
3659 len = wq->wq_next->wq_ga.ga_len;
3660 did_use_queue = TRUE;
3661 }
3662 else
3663 {
3664 if (len_arg == 0)
3665 /* nothing to write, called from channel_select_check() */
3666 return OK;
3667 buf = buf_arg;
3668 len = len_arg;
3669 }
3670
3671 if (part == PART_SOCK)
3672 res = sock_write(fd, (char *)buf, len);
3673 else
3674 res = fd_write(fd, (char *)buf, len);
3675 if (res < 0 && (errno == EWOULDBLOCK
3676#ifdef EAGAIN
3677 || errno == EAGAIN
3678#endif
3679 ))
3680 res = 0; /* nothing got written */
3681
3682 if (res >= 0 && ch_part->ch_nonblocking)
3683 {
3684 writeq_T *entry = wq->wq_next;
3685
3686 if (did_use_queue)
3687 ch_log(channel, "Sent %d bytes now", res);
3688 if (res == len)
3689 {
3690 /* Wrote all the buf[len] bytes. */
3691 if (entry != NULL)
3692 {
3693 /* Remove the entry from the write queue. */
3694 ga_clear(&entry->wq_ga);
3695 wq->wq_next = entry->wq_next;
3696 if (wq->wq_next == NULL)
3697 wq->wq_prev = NULL;
3698 else
3699 wq->wq_next->wq_prev = NULL;
3700 continue;
3701 }
3702 if (did_use_queue)
3703 ch_log(channel, "Write queue empty");
3704 }
3705 else
3706 {
3707 /* Wrote only buf[res] bytes, can't write more now. */
3708 if (entry != NULL)
3709 {
3710 if (res > 0)
3711 {
3712 /* Remove the bytes that were written. */
3713 mch_memmove(entry->wq_ga.ga_data,
3714 (char *)entry->wq_ga.ga_data + res,
3715 len - res);
3716 entry->wq_ga.ga_len -= res;
3717 }
3718 buf = buf_arg;
3719 len = len_arg;
3720 }
3721 else
3722 {
3723 buf += res;
3724 len -= res;
3725 }
3726 ch_log(channel, "Adding %d bytes to the write queue", len);
3727
3728 /* Append the not written bytes of the argument to the write
3729 * buffer. Limit entries to 4000 bytes. */
3730 if (wq->wq_prev != NULL
3731 && wq->wq_prev->wq_ga.ga_len + len < 4000)
3732 {
3733 writeq_T *last = wq->wq_prev;
3734
3735 /* append to the last entry */
3736 if (ga_grow(&last->wq_ga, len) == OK)
3737 {
3738 mch_memmove((char *)last->wq_ga.ga_data
3739 + last->wq_ga.ga_len,
3740 buf, len);
3741 last->wq_ga.ga_len += len;
3742 }
3743 }
3744 else
3745 {
3746 writeq_T *last = (writeq_T *)alloc((int)sizeof(writeq_T));
3747
3748 if (last != NULL)
3749 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003750 last->wq_prev = wq->wq_prev;
3751 last->wq_next = NULL;
3752 if (wq->wq_prev == NULL)
3753 wq->wq_next = last;
3754 else
3755 wq->wq_prev->wq_next = last;
3756 wq->wq_prev = last;
3757 ga_init2(&last->wq_ga, 1, 1000);
3758 if (ga_grow(&last->wq_ga, len) == OK)
3759 {
3760 mch_memmove(last->wq_ga.ga_data, buf, len);
3761 last->wq_ga.ga_len = len;
3762 }
3763 }
3764 }
3765 }
3766 }
3767 else if (res != len)
3768 {
3769 if (!channel->ch_error && fun != NULL)
3770 {
3771 ch_error(channel, "%s(): write failed", fun);
3772 EMSG2(_("E631: %s(): write failed"), fun);
3773 }
3774 channel->ch_error = TRUE;
3775 return FAIL;
3776 }
3777
3778 channel->ch_error = FALSE;
3779 return OK;
3780 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01003781}
3782
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003783/*
3784 * Common for "ch_sendexpr()" and "ch_sendraw()".
3785 * Returns the channel if the caller should read the response.
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02003786 * Sets "part_read" to the read fd.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003787 * Otherwise returns NULL.
3788 */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003789 static channel_T *
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003790send_common(
3791 typval_T *argvars,
3792 char_u *text,
3793 int id,
3794 int eval,
3795 jobopt_T *opt,
3796 char *fun,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003797 ch_part_T *part_read)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003798{
3799 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003800 ch_part_T part_send;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003801
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003802 clear_job_options(opt);
Bram Moolenaar437905c2016-04-26 19:01:05 +02003803 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003804 if (channel == NULL)
3805 return NULL;
3806 part_send = channel_part_send(channel);
3807 *part_read = channel_part_read(channel);
3808
Bram Moolenaar08d384f2017-08-11 21:51:23 +02003809 if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT, 0) == FAIL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003810 return NULL;
3811
3812 /* Set the callback. An empty callback means no callback and not reading
3813 * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
3814 * allowed. */
3815 if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
3816 {
3817 if (eval)
3818 {
3819 EMSG2(_("E917: Cannot use a callback with %s()"), fun);
3820 return NULL;
3821 }
Bram Moolenaar6fc82272016-08-28 19:26:43 +02003822 channel_set_req_callback(channel, *part_read,
Bram Moolenaar1735bc92016-03-14 23:05:14 +01003823 opt->jo_callback, opt->jo_partial, id);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003824 }
3825
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02003826 if (channel_send(channel, part_send, text, (int)STRLEN(text), fun) == OK
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003827 && opt->jo_callback == NULL)
3828 return channel;
3829 return NULL;
3830}
3831
3832/*
3833 * common for "ch_evalexpr()" and "ch_sendexpr()"
3834 */
3835 void
3836ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
3837{
3838 char_u *text;
3839 typval_T *listtv;
3840 channel_T *channel;
3841 int id;
3842 ch_mode_T ch_mode;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003843 ch_part_T part_send;
3844 ch_part_T part_read;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003845 jobopt_T opt;
3846 int timeout;
3847
3848 /* return an empty string by default */
3849 rettv->v_type = VAR_STRING;
3850 rettv->vval.v_string = NULL;
3851
Bram Moolenaar437905c2016-04-26 19:01:05 +02003852 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003853 if (channel == NULL)
3854 return;
3855 part_send = channel_part_send(channel);
3856
3857 ch_mode = channel_get_mode(channel, part_send);
3858 if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
3859 {
3860 EMSG(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
3861 return;
3862 }
3863
Bram Moolenaare9d6a292016-03-20 19:31:33 +01003864 id = ++channel->ch_last_msg_id;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003865 text = json_encode_nr_expr(id, &argvars[1],
Bram Moolenaarf1f07922016-08-26 17:58:53 +02003866 (ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003867 if (text == NULL)
3868 return;
3869
3870 channel = send_common(argvars, text, id, eval, &opt,
3871 eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
3872 vim_free(text);
3873 if (channel != NULL && eval)
3874 {
3875 if (opt.jo_set & JO_TIMEOUT)
3876 timeout = opt.jo_timeout;
3877 else
3878 timeout = channel_get_timeout(channel, part_read);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003879 if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
3880 == OK)
3881 {
3882 list_T *list = listtv->vval.v_list;
3883
3884 /* Move the item from the list and then change the type to
3885 * avoid the value being freed. */
3886 *rettv = list->lv_last->li_tv;
3887 list->lv_last->li_tv.v_type = VAR_NUMBER;
3888 free_tv(listtv);
3889 }
3890 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003891 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003892}
3893
3894/*
3895 * common for "ch_evalraw()" and "ch_sendraw()"
3896 */
3897 void
3898ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
3899{
3900 char_u buf[NUMBUFLEN];
3901 char_u *text;
3902 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003903 ch_part_T part_read;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003904 jobopt_T opt;
3905 int timeout;
3906
3907 /* return an empty string by default */
3908 rettv->v_type = VAR_STRING;
3909 rettv->vval.v_string = NULL;
3910
3911 text = get_tv_string_buf(&argvars[1], buf);
3912 channel = send_common(argvars, text, 0, eval, &opt,
3913 eval ? "ch_evalraw" : "ch_sendraw", &part_read);
3914 if (channel != NULL && eval)
3915 {
3916 if (opt.jo_set & JO_TIMEOUT)
3917 timeout = opt.jo_timeout;
3918 else
3919 timeout = channel_get_timeout(channel, part_read);
3920 rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
3921 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003922 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003923}
3924
Bram Moolenaard04a0202016-01-26 23:30:18 +01003925# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +01003926/*
3927 * Add open channels to the poll struct.
3928 * Return the adjusted struct index.
3929 * The type of "fds" is hidden to avoid problems with the function proto.
3930 */
3931 int
3932channel_poll_setup(int nfd_in, void *fds_in)
3933{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003934 int nfd = nfd_in;
3935 channel_T *channel;
3936 struct pollfd *fds = fds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003937 ch_part_T part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01003938
Bram Moolenaar77073442016-02-13 23:23:53 +01003939 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003940 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003941 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003942 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003943 chanpart_T *ch_part = &channel->ch_part[part];
3944
3945 if (ch_part->ch_fd != INVALID_FD)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003946 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003947 ch_part->ch_poll_idx = nfd;
3948 fds[nfd].fd = ch_part->ch_fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003949 fds[nfd].events = POLLIN;
3950 nfd++;
3951 }
3952 else
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003953 channel->ch_part[part].ch_poll_idx = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003954 }
3955 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01003956
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003957 nfd = channel_fill_poll_write(nfd, fds);
3958
Bram Moolenaare0874f82016-01-24 20:36:41 +01003959 return nfd;
3960}
3961
3962/*
3963 * The type of "fds" is hidden to avoid problems with the function proto.
3964 */
3965 int
3966channel_poll_check(int ret_in, void *fds_in)
3967{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003968 int ret = ret_in;
3969 channel_T *channel;
3970 struct pollfd *fds = fds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003971 ch_part_T part;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003972 int idx;
3973 chanpart_T *in_part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01003974
Bram Moolenaar77073442016-02-13 23:23:53 +01003975 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003976 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003977 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003978 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003979 idx = channel->ch_part[part].ch_poll_idx;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003980
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003981 if (ret > 0 && idx != -1 && (fds[idx].revents & POLLIN))
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003982 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003983 channel_read(channel, part, "channel_poll_check");
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01003984 --ret;
3985 }
3986 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003987
3988 in_part = &channel->ch_part[PART_IN];
3989 idx = in_part->ch_poll_idx;
3990 if (ret > 0 && idx != -1 && (fds[idx].revents & POLLOUT))
3991 {
Bram Moolenaar683b7962017-08-19 15:51:59 +02003992 channel_write_input(channel);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003993 --ret;
3994 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003995 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01003996
3997 return ret;
3998}
Bram Moolenaard04a0202016-01-26 23:30:18 +01003999# endif /* UNIX && !HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01004000
Bram Moolenaared5a78e2016-02-19 21:05:03 +01004001# if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004002/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004003 * The "fd_set" type is hidden to avoid problems with the function proto.
Bram Moolenaare0874f82016-01-24 20:36:41 +01004004 */
4005 int
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004006channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004007{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004008 int maxfd = maxfd_in;
4009 channel_T *channel;
4010 fd_set *rfds = rfds_in;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004011 fd_set *wfds = wfds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004012 ch_part_T part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004013
Bram Moolenaar77073442016-02-13 23:23:53 +01004014 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004015 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004016 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004017 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004018 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004019
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004020 if (fd != INVALID_FD)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004021 {
Bram Moolenaard8070362016-02-15 21:56:54 +01004022 FD_SET((int)fd, rfds);
4023 if (maxfd < (int)fd)
4024 maxfd = (int)fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004025 }
4026 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004027 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004028
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004029 maxfd = channel_fill_wfds(maxfd, wfds);
4030
Bram Moolenaare0874f82016-01-24 20:36:41 +01004031 return maxfd;
4032}
4033
4034/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004035 * The "fd_set" type is hidden to avoid problems with the function proto.
Bram Moolenaare0874f82016-01-24 20:36:41 +01004036 */
4037 int
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004038channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004039{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004040 int ret = ret_in;
4041 channel_T *channel;
4042 fd_set *rfds = rfds_in;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004043 fd_set *wfds = wfds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004044 ch_part_T part;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004045 chanpart_T *in_part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004046
Bram Moolenaar77073442016-02-13 23:23:53 +01004047 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004048 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004049 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004050 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004051 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004052
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004053 if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds))
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004054 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004055 channel_read(channel, part, "channel_select_check");
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004056 --ret;
4057 }
4058 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004059
4060 in_part = &channel->ch_part[PART_IN];
4061 if (ret > 0 && in_part->ch_fd != INVALID_FD
4062 && FD_ISSET(in_part->ch_fd, wfds))
4063 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004064 channel_write_input(channel);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004065 --ret;
4066 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004067 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004068
4069 return ret;
4070}
Bram Moolenaared5a78e2016-02-19 21:05:03 +01004071# endif /* !WIN32 && HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01004072
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004073/*
Bram Moolenaard7ece102016-02-02 23:23:02 +01004074 * Execute queued up commands.
4075 * Invoked from the main loop when it's safe to execute received commands.
4076 * Return TRUE when something was done.
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004077 */
Bram Moolenaard7ece102016-02-02 23:23:02 +01004078 int
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004079channel_parse_messages(void)
4080{
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004081 channel_T *channel = first_channel;
4082 int ret = FALSE;
4083 int r;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004084 ch_part_T part = PART_SOCK;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004085#ifdef ELAPSED_FUNC
4086 ELAPSED_TYPE start_tv;
4087
4088 ELAPSED_INIT(start_tv);
4089#endif
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004090
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004091 ++safe_to_invoke_callback;
4092
Bram Moolenaard0b65022016-03-06 21:50:33 +01004093 /* Only do this message when another message was given, otherwise we get
4094 * lots of them. */
4095 if (did_log_msg)
4096 {
4097 ch_log(NULL, "looking for messages on channels");
4098 did_log_msg = FALSE;
4099 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004100 while (channel != NULL)
4101 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004102 if (channel->ch_to_be_closed == 0)
Bram Moolenaarcf7ff702016-05-09 17:20:14 +02004103 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004104 channel->ch_to_be_closed = (1 << PART_COUNT);
Bram Moolenaarcf7ff702016-05-09 17:20:14 +02004105 channel_close_now(channel);
4106 /* channel may have been freed, start over */
4107 channel = first_channel;
4108 continue;
4109 }
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004110 if (channel->ch_to_be_freed)
4111 {
4112 channel_free(channel);
4113 /* channel has been freed, start over */
4114 channel = first_channel;
4115 continue;
4116 }
Bram Moolenaar46c85432016-02-26 11:17:46 +01004117 if (channel->ch_refcount == 0 && !channel_still_useful(channel))
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +01004118 {
4119 /* channel is no longer useful, free it */
4120 channel_free(channel);
4121 channel = first_channel;
4122 part = PART_SOCK;
4123 continue;
4124 }
Bram Moolenaar187db502016-02-27 14:44:26 +01004125 if (channel->ch_part[part].ch_fd != INVALID_FD
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004126 || channel_has_readahead(channel, part))
Bram Moolenaard7ece102016-02-02 23:23:02 +01004127 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004128 /* Increase the refcount, in case the handler causes the channel
4129 * to be unreferenced or closed. */
4130 ++channel->ch_refcount;
4131 r = may_invoke_callback(channel, part);
4132 if (r == OK)
4133 ret = TRUE;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004134 if (channel_unref(channel) || (r == OK
4135#ifdef ELAPSED_FUNC
4136 /* Limit the time we loop here to 100 msec, otherwise
4137 * Vim becomes unresponsive when the callback takes
4138 * more than a bit of time. */
4139 && ELAPSED_FUNC(start_tv) < 100L
4140#endif
4141 ))
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004142 {
4143 /* channel was freed or something was done, start over */
4144 channel = first_channel;
4145 part = PART_SOCK;
4146 continue;
4147 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01004148 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004149 if (part < PART_ERR)
4150 ++part;
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004151 else
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004152 {
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004153 channel = channel->ch_next;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004154 part = PART_SOCK;
4155 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004156 }
Bram Moolenaar187db502016-02-27 14:44:26 +01004157
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02004158 if (channel_need_redraw)
Bram Moolenaar187db502016-02-27 14:44:26 +01004159 {
4160 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02004161 redraw_after_callback(TRUE);
Bram Moolenaar187db502016-02-27 14:44:26 +01004162 }
4163
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004164 --safe_to_invoke_callback;
4165
Bram Moolenaard7ece102016-02-02 23:23:02 +01004166 return ret;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004167}
4168
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01004169/*
Bram Moolenaar8a8199e2016-11-26 15:13:33 +01004170 * Return TRUE if any channel has readahead. That means we should not block on
4171 * waiting for input.
4172 */
4173 int
4174channel_any_readahead(void)
4175{
4176 channel_T *channel = first_channel;
4177 ch_part_T part = PART_SOCK;
4178
4179 while (channel != NULL)
4180 {
4181 if (channel_has_readahead(channel, part))
4182 return TRUE;
4183 if (part < PART_ERR)
4184 ++part;
4185 else
4186 {
4187 channel = channel->ch_next;
4188 part = PART_SOCK;
4189 }
4190 }
4191 return FALSE;
4192}
4193
4194/*
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01004195 * Mark references to lists used in channels.
4196 */
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004197 int
4198set_ref_in_channel(int copyID)
4199{
Bram Moolenaar77073442016-02-13 23:23:53 +01004200 int abort = FALSE;
4201 channel_T *channel;
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004202 typval_T tv;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004203
Bram Moolenaar77073442016-02-13 23:23:53 +01004204 for (channel = first_channel; channel != NULL; channel = channel->ch_next)
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004205 if (channel_still_useful(channel))
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004206 {
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004207 tv.v_type = VAR_CHANNEL;
4208 tv.vval.v_channel = channel;
4209 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004210 }
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004211 return abort;
4212}
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004213
4214/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004215 * Return the "part" to write to for "channel".
4216 */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004217 ch_part_T
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004218channel_part_send(channel_T *channel)
4219{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004220 if (channel->CH_SOCK_FD == INVALID_FD)
4221 return PART_IN;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004222 return PART_SOCK;
4223}
4224
4225/*
4226 * Return the default "part" to read from for "channel".
4227 */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004228 ch_part_T
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004229channel_part_read(channel_T *channel)
4230{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004231 if (channel->CH_SOCK_FD == INVALID_FD)
4232 return PART_OUT;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004233 return PART_SOCK;
4234}
4235
4236/*
4237 * Return the mode of "channel"/"part"
Bram Moolenaar77073442016-02-13 23:23:53 +01004238 * If "channel" is invalid returns MODE_JSON.
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004239 */
4240 ch_mode_T
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004241channel_get_mode(channel_T *channel, ch_part_T part)
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004242{
Bram Moolenaar77073442016-02-13 23:23:53 +01004243 if (channel == NULL)
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004244 return MODE_JSON;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004245 return channel->ch_part[part].ch_mode;
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004246}
4247
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01004248/*
4249 * Return the timeout of "channel"/"part"
4250 */
4251 int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004252channel_get_timeout(channel_T *channel, ch_part_T part)
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01004253{
4254 return channel->ch_part[part].ch_timeout;
4255}
4256
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004257 static int
4258handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
4259{
4260 char_u *val = get_tv_string(item);
4261
4262 opt->jo_set |= jo;
4263 if (STRCMP(val, "nl") == 0)
4264 *modep = MODE_NL;
4265 else if (STRCMP(val, "raw") == 0)
4266 *modep = MODE_RAW;
4267 else if (STRCMP(val, "js") == 0)
4268 *modep = MODE_JS;
4269 else if (STRCMP(val, "json") == 0)
4270 *modep = MODE_JSON;
4271 else
4272 {
4273 EMSG2(_(e_invarg2), val);
4274 return FAIL;
4275 }
4276 return OK;
4277}
4278
4279 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004280handle_io(typval_T *item, ch_part_T part, jobopt_T *opt)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004281{
4282 char_u *val = get_tv_string(item);
4283
4284 opt->jo_set |= JO_OUT_IO << (part - PART_OUT);
4285 if (STRCMP(val, "null") == 0)
4286 opt->jo_io[part] = JIO_NULL;
4287 else if (STRCMP(val, "pipe") == 0)
4288 opt->jo_io[part] = JIO_PIPE;
4289 else if (STRCMP(val, "file") == 0)
4290 opt->jo_io[part] = JIO_FILE;
4291 else if (STRCMP(val, "buffer") == 0)
4292 opt->jo_io[part] = JIO_BUFFER;
4293 else if (STRCMP(val, "out") == 0 && part == PART_ERR)
4294 opt->jo_io[part] = JIO_OUT;
4295 else
4296 {
4297 EMSG2(_(e_invarg2), val);
4298 return FAIL;
4299 }
4300 return OK;
4301}
4302
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004303/*
4304 * Clear a jobopt_T before using it.
4305 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004306 void
4307clear_job_options(jobopt_T *opt)
4308{
4309 vim_memset(opt, 0, sizeof(jobopt_T));
4310}
4311
4312/*
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004313 * Free any members of a jobopt_T.
4314 */
4315 void
4316free_job_options(jobopt_T *opt)
4317{
4318 if (opt->jo_partial != NULL)
4319 partial_unref(opt->jo_partial);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004320 else if (opt->jo_callback != NULL)
4321 func_unref(opt->jo_callback);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004322 if (opt->jo_out_partial != NULL)
4323 partial_unref(opt->jo_out_partial);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004324 else if (opt->jo_out_cb != NULL)
4325 func_unref(opt->jo_out_cb);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004326 if (opt->jo_err_partial != NULL)
4327 partial_unref(opt->jo_err_partial);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004328 else if (opt->jo_err_cb != NULL)
4329 func_unref(opt->jo_err_cb);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004330 if (opt->jo_close_partial != NULL)
4331 partial_unref(opt->jo_close_partial);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004332 else if (opt->jo_close_cb != NULL)
4333 func_unref(opt->jo_close_cb);
Bram Moolenaaref3abc62016-05-29 16:44:26 +02004334 if (opt->jo_exit_partial != NULL)
4335 partial_unref(opt->jo_exit_partial);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004336 else if (opt->jo_exit_cb != NULL)
4337 func_unref(opt->jo_exit_cb);
Bram Moolenaar05aafed2017-08-11 19:12:11 +02004338 if (opt->jo_env != NULL)
4339 dict_unref(opt->jo_env);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004340}
4341
4342/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004343 * Get the PART_ number from the first character of an option name.
4344 */
4345 static int
4346part_from_char(int c)
4347{
4348 return c == 'i' ? PART_IN : c == 'o' ? PART_OUT: PART_ERR;
4349}
4350
4351/*
4352 * Get the option entries from the dict in "tv", parse them and put the result
4353 * in "opt".
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004354 * Only accept JO_ options in "supported" and JO2_ options in "supported2".
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004355 * If an option value is invalid return FAIL.
4356 */
4357 int
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004358get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004359{
4360 typval_T *item;
4361 char_u *val;
4362 dict_T *dict;
4363 int todo;
4364 hashitem_T *hi;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004365 ch_part_T part;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004366
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004367 if (tv->v_type == VAR_UNKNOWN)
4368 return OK;
4369 if (tv->v_type != VAR_DICT)
4370 {
4371 EMSG(_(e_invarg));
4372 return FAIL;
4373 }
4374 dict = tv->vval.v_dict;
4375 if (dict == NULL)
4376 return OK;
4377
4378 todo = (int)dict->dv_hashtab.ht_used;
4379 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
4380 if (!HASHITEM_EMPTY(hi))
4381 {
4382 item = &dict_lookup(hi)->di_tv;
4383
4384 if (STRCMP(hi->hi_key, "mode") == 0)
4385 {
4386 if (!(supported & JO_MODE))
4387 break;
4388 if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
4389 return FAIL;
4390 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004391 else if (STRCMP(hi->hi_key, "in_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004392 {
4393 if (!(supported & JO_IN_MODE))
4394 break;
4395 if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
4396 == FAIL)
4397 return FAIL;
4398 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004399 else if (STRCMP(hi->hi_key, "out_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004400 {
4401 if (!(supported & JO_OUT_MODE))
4402 break;
4403 if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
4404 == FAIL)
4405 return FAIL;
4406 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004407 else if (STRCMP(hi->hi_key, "err_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004408 {
4409 if (!(supported & JO_ERR_MODE))
4410 break;
4411 if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
4412 == FAIL)
4413 return FAIL;
4414 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004415 else if (STRCMP(hi->hi_key, "in_io") == 0
4416 || STRCMP(hi->hi_key, "out_io") == 0
4417 || STRCMP(hi->hi_key, "err_io") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004418 {
4419 if (!(supported & JO_OUT_IO))
4420 break;
4421 if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
4422 return FAIL;
4423 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004424 else if (STRCMP(hi->hi_key, "in_name") == 0
4425 || STRCMP(hi->hi_key, "out_name") == 0
4426 || STRCMP(hi->hi_key, "err_name") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004427 {
4428 part = part_from_char(*hi->hi_key);
4429
4430 if (!(supported & JO_OUT_IO))
4431 break;
4432 opt->jo_set |= JO_OUT_NAME << (part - PART_OUT);
4433 opt->jo_io_name[part] =
4434 get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
4435 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004436 else if (STRCMP(hi->hi_key, "pty") == 0)
4437 {
4438 if (!(supported & JO_MODE))
4439 break;
4440 opt->jo_pty = get_tv_number(item);
4441 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004442 else if (STRCMP(hi->hi_key, "in_buf") == 0
4443 || STRCMP(hi->hi_key, "out_buf") == 0
4444 || STRCMP(hi->hi_key, "err_buf") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004445 {
4446 part = part_from_char(*hi->hi_key);
4447
4448 if (!(supported & JO_OUT_IO))
4449 break;
4450 opt->jo_set |= JO_OUT_BUF << (part - PART_OUT);
4451 opt->jo_io_buf[part] = get_tv_number(item);
4452 if (opt->jo_io_buf[part] <= 0)
4453 {
4454 EMSG2(_(e_invarg2), get_tv_string(item));
4455 return FAIL;
4456 }
4457 if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
4458 {
4459 EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[part]);
4460 return FAIL;
4461 }
4462 }
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02004463 else if (STRCMP(hi->hi_key, "out_modifiable") == 0
4464 || STRCMP(hi->hi_key, "err_modifiable") == 0)
4465 {
4466 part = part_from_char(*hi->hi_key);
4467
4468 if (!(supported & JO_OUT_IO))
4469 break;
4470 opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT);
4471 opt->jo_modifiable[part] = get_tv_number(item);
4472 }
Bram Moolenaar169ebb02016-09-07 23:32:23 +02004473 else if (STRCMP(hi->hi_key, "out_msg") == 0
4474 || STRCMP(hi->hi_key, "err_msg") == 0)
4475 {
4476 part = part_from_char(*hi->hi_key);
4477
4478 if (!(supported & JO_OUT_IO))
4479 break;
4480 opt->jo_set2 |= JO2_OUT_MSG << (part - PART_OUT);
4481 opt->jo_message[part] = get_tv_number(item);
4482 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004483 else if (STRCMP(hi->hi_key, "in_top") == 0
4484 || STRCMP(hi->hi_key, "in_bot") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004485 {
4486 linenr_T *lp;
4487
4488 if (!(supported & JO_OUT_IO))
4489 break;
4490 if (hi->hi_key[3] == 't')
4491 {
4492 lp = &opt->jo_in_top;
4493 opt->jo_set |= JO_IN_TOP;
4494 }
4495 else
4496 {
4497 lp = &opt->jo_in_bot;
4498 opt->jo_set |= JO_IN_BOT;
4499 }
4500 *lp = get_tv_number(item);
4501 if (*lp < 0)
4502 {
4503 EMSG2(_(e_invarg2), get_tv_string(item));
4504 return FAIL;
4505 }
4506 }
4507 else if (STRCMP(hi->hi_key, "channel") == 0)
4508 {
4509 if (!(supported & JO_OUT_IO))
4510 break;
4511 opt->jo_set |= JO_CHANNEL;
4512 if (item->v_type != VAR_CHANNEL)
4513 {
4514 EMSG2(_(e_invarg2), "channel");
4515 return FAIL;
4516 }
4517 opt->jo_channel = item->vval.v_channel;
4518 }
4519 else if (STRCMP(hi->hi_key, "callback") == 0)
4520 {
4521 if (!(supported & JO_CALLBACK))
4522 break;
4523 opt->jo_set |= JO_CALLBACK;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01004524 opt->jo_callback = get_callback(item, &opt->jo_partial);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004525 if (opt->jo_callback == NULL)
4526 {
4527 EMSG2(_(e_invarg2), "callback");
4528 return FAIL;
4529 }
4530 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004531 else if (STRCMP(hi->hi_key, "out_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004532 {
4533 if (!(supported & JO_OUT_CALLBACK))
4534 break;
4535 opt->jo_set |= JO_OUT_CALLBACK;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01004536 opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004537 if (opt->jo_out_cb == NULL)
4538 {
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004539 EMSG2(_(e_invarg2), "out_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004540 return FAIL;
4541 }
4542 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004543 else if (STRCMP(hi->hi_key, "err_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004544 {
4545 if (!(supported & JO_ERR_CALLBACK))
4546 break;
4547 opt->jo_set |= JO_ERR_CALLBACK;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01004548 opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004549 if (opt->jo_err_cb == NULL)
4550 {
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004551 EMSG2(_(e_invarg2), "err_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004552 return FAIL;
4553 }
4554 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004555 else if (STRCMP(hi->hi_key, "close_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004556 {
4557 if (!(supported & JO_CLOSE_CALLBACK))
4558 break;
4559 opt->jo_set |= JO_CLOSE_CALLBACK;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01004560 opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004561 if (opt->jo_close_cb == NULL)
4562 {
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004563 EMSG2(_(e_invarg2), "close_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004564 return FAIL;
4565 }
4566 }
Bram Moolenaar958dc692016-12-01 15:34:12 +01004567 else if (STRCMP(hi->hi_key, "drop") == 0)
4568 {
4569 int never = FALSE;
4570 val = get_tv_string(item);
4571
4572 if (STRCMP(val, "never") == 0)
4573 never = TRUE;
4574 else if (STRCMP(val, "auto") != 0)
4575 {
4576 EMSG2(_(e_invarg2), "drop");
4577 return FAIL;
4578 }
4579 opt->jo_drop_never = never;
4580 }
Bram Moolenaaref3abc62016-05-29 16:44:26 +02004581 else if (STRCMP(hi->hi_key, "exit_cb") == 0)
4582 {
4583 if (!(supported & JO_EXIT_CB))
4584 break;
4585 opt->jo_set |= JO_EXIT_CB;
4586 opt->jo_exit_cb = get_callback(item, &opt->jo_exit_partial);
4587 if (opt->jo_exit_cb == NULL)
4588 {
4589 EMSG2(_(e_invarg2), "exit_cb");
4590 return FAIL;
4591 }
4592 }
Bram Moolenaar8456ea82017-08-05 15:02:05 +02004593#ifdef FEAT_TERMINAL
Bram Moolenaar78712a72017-08-05 14:50:12 +02004594 else if (STRCMP(hi->hi_key, "term_name") == 0)
4595 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004596 if (!(supported2 & JO2_TERM_NAME))
Bram Moolenaar78712a72017-08-05 14:50:12 +02004597 break;
4598 opt->jo_set2 |= JO2_TERM_NAME;
4599 opt->jo_term_name = get_tv_string_chk(item);
4600 if (opt->jo_term_name == NULL)
4601 {
4602 EMSG2(_(e_invarg2), "term_name");
4603 return FAIL;
4604 }
4605 }
Bram Moolenaardd693ce2017-08-10 23:15:19 +02004606 else if (STRCMP(hi->hi_key, "term_finish") == 0)
4607 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004608 if (!(supported2 & JO2_TERM_FINISH))
Bram Moolenaardd693ce2017-08-10 23:15:19 +02004609 break;
4610 val = get_tv_string(item);
4611 if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
4612 {
Bram Moolenaarf1237f12017-08-11 15:45:28 +02004613 EMSG2(_(e_invarg2), val);
Bram Moolenaardd693ce2017-08-10 23:15:19 +02004614 return FAIL;
4615 }
4616 opt->jo_set2 |= JO2_TERM_FINISH;
4617 opt->jo_term_finish = *val;
4618 }
Bram Moolenaar37c45832017-08-12 16:01:04 +02004619 else if (STRCMP(hi->hi_key, "term_opencmd") == 0)
4620 {
4621 char_u *p;
4622
4623 if (!(supported2 & JO2_TERM_OPENCMD))
4624 break;
4625 opt->jo_set2 |= JO2_TERM_OPENCMD;
4626 p = opt->jo_term_opencmd = get_tv_string_chk(item);
4627 if (p != NULL)
4628 {
4629 /* Must have %d and no other %. */
4630 p = vim_strchr(p, '%');
4631 if (p != NULL && (p[1] != 'd'
4632 || vim_strchr(p + 2, '%') != NULL))
4633 p = NULL;
4634 }
4635 if (p == NULL)
4636 {
4637 EMSG2(_(e_invarg2), "term_opencmd");
4638 return FAIL;
4639 }
4640 }
Bram Moolenaar3346cc42017-09-02 14:54:21 +02004641 else if (STRCMP(hi->hi_key, "eof_chars") == 0)
4642 {
4643# ifdef WIN3264
4644 char_u *p;
4645
4646 if (!(supported2 & JO2_EOF_CHARS))
4647 break;
4648 opt->jo_set2 |= JO2_EOF_CHARS;
4649 p = opt->jo_eof_chars = get_tv_string_chk(item);
4650 if (p == NULL)
4651 {
4652 EMSG2(_(e_invarg2), "term_opencmd");
4653 return FAIL;
4654 }
4655# endif
4656 }
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004657 else if (STRCMP(hi->hi_key, "term_rows") == 0)
4658 {
4659 if (!(supported2 & JO2_TERM_ROWS))
4660 break;
4661 opt->jo_set |= JO2_TERM_ROWS;
4662 opt->jo_term_rows = get_tv_number(item);
4663 }
4664 else if (STRCMP(hi->hi_key, "term_cols") == 0)
4665 {
4666 if (!(supported2 & JO2_TERM_COLS))
4667 break;
4668 opt->jo_set |= JO2_TERM_COLS;
4669 opt->jo_term_cols = get_tv_number(item);
4670 }
4671 else if (STRCMP(hi->hi_key, "vertical") == 0)
4672 {
4673 if (!(supported2 & JO2_VERTICAL))
4674 break;
4675 opt->jo_set |= JO2_VERTICAL;
4676 opt->jo_vertical = get_tv_number(item);
4677 }
Bram Moolenaarda43b612017-08-11 22:27:50 +02004678 else if (STRCMP(hi->hi_key, "curwin") == 0)
4679 {
4680 if (!(supported2 & JO2_CURWIN))
4681 break;
4682 opt->jo_set |= JO2_CURWIN;
4683 opt->jo_curwin = get_tv_number(item);
4684 }
Bram Moolenaar8cad9302017-08-12 14:32:32 +02004685 else if (STRCMP(hi->hi_key, "hidden") == 0)
4686 {
4687 if (!(supported2 & JO2_HIDDEN))
4688 break;
4689 opt->jo_set |= JO2_HIDDEN;
4690 opt->jo_hidden = get_tv_number(item);
4691 }
Bram Moolenaar8456ea82017-08-05 15:02:05 +02004692#endif
Bram Moolenaar05aafed2017-08-11 19:12:11 +02004693 else if (STRCMP(hi->hi_key, "env") == 0)
4694 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004695 if (!(supported2 & JO2_ENV))
Bram Moolenaar05aafed2017-08-11 19:12:11 +02004696 break;
4697 opt->jo_set |= JO2_ENV;
4698 opt->jo_env = item->vval.v_dict;
4699 ++item->vval.v_dict->dv_refcount;
4700 }
4701 else if (STRCMP(hi->hi_key, "cwd") == 0)
4702 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004703 if (!(supported2 & JO2_CWD))
Bram Moolenaar05aafed2017-08-11 19:12:11 +02004704 break;
4705 opt->jo_cwd = get_tv_string_buf_chk(item, opt->jo_cwd_buf);
4706 if (opt->jo_cwd == NULL || !mch_isdir(opt->jo_cwd))
4707 {
4708 EMSG2(_(e_invarg2), "cwd");
4709 return FAIL;
4710 }
4711 opt->jo_set |= JO2_CWD;
4712 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004713 else if (STRCMP(hi->hi_key, "waittime") == 0)
4714 {
4715 if (!(supported & JO_WAITTIME))
4716 break;
4717 opt->jo_set |= JO_WAITTIME;
4718 opt->jo_waittime = get_tv_number(item);
4719 }
4720 else if (STRCMP(hi->hi_key, "timeout") == 0)
4721 {
4722 if (!(supported & JO_TIMEOUT))
4723 break;
4724 opt->jo_set |= JO_TIMEOUT;
4725 opt->jo_timeout = get_tv_number(item);
4726 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004727 else if (STRCMP(hi->hi_key, "out_timeout") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004728 {
4729 if (!(supported & JO_OUT_TIMEOUT))
4730 break;
4731 opt->jo_set |= JO_OUT_TIMEOUT;
4732 opt->jo_out_timeout = get_tv_number(item);
4733 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004734 else if (STRCMP(hi->hi_key, "err_timeout") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004735 {
4736 if (!(supported & JO_ERR_TIMEOUT))
4737 break;
4738 opt->jo_set |= JO_ERR_TIMEOUT;
4739 opt->jo_err_timeout = get_tv_number(item);
4740 }
4741 else if (STRCMP(hi->hi_key, "part") == 0)
4742 {
4743 if (!(supported & JO_PART))
4744 break;
4745 opt->jo_set |= JO_PART;
4746 val = get_tv_string(item);
4747 if (STRCMP(val, "err") == 0)
4748 opt->jo_part = PART_ERR;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02004749 else if (STRCMP(val, "out") == 0)
4750 opt->jo_part = PART_OUT;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004751 else
4752 {
4753 EMSG2(_(e_invarg2), val);
4754 return FAIL;
4755 }
4756 }
4757 else if (STRCMP(hi->hi_key, "id") == 0)
4758 {
4759 if (!(supported & JO_ID))
4760 break;
4761 opt->jo_set |= JO_ID;
4762 opt->jo_id = get_tv_number(item);
4763 }
4764 else if (STRCMP(hi->hi_key, "stoponexit") == 0)
4765 {
4766 if (!(supported & JO_STOPONEXIT))
4767 break;
4768 opt->jo_set |= JO_STOPONEXIT;
4769 opt->jo_stoponexit = get_tv_string_buf_chk(item,
4770 opt->jo_soe_buf);
4771 if (opt->jo_stoponexit == NULL)
4772 {
4773 EMSG2(_(e_invarg2), "stoponexit");
4774 return FAIL;
4775 }
4776 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004777 else if (STRCMP(hi->hi_key, "block_write") == 0)
4778 {
4779 if (!(supported & JO_BLOCK_WRITE))
4780 break;
4781 opt->jo_set |= JO_BLOCK_WRITE;
4782 opt->jo_block_write = get_tv_number(item);
4783 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004784 else
4785 break;
4786 --todo;
4787 }
4788 if (todo > 0)
4789 {
4790 EMSG2(_(e_invarg2), hi->hi_key);
4791 return FAIL;
4792 }
4793
4794 return OK;
4795}
4796
4797/*
4798 * Get the channel from the argument.
4799 * Returns NULL if the handle is invalid.
Bram Moolenaar437905c2016-04-26 19:01:05 +02004800 * When "check_open" is TRUE check that the channel can be used.
4801 * When "reading" is TRUE "check_open" considers typeahead useful.
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004802 * "part" is used to check typeahead, when PART_COUNT use the default part.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004803 */
4804 channel_T *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004805get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004806{
Bram Moolenaar437905c2016-04-26 19:01:05 +02004807 channel_T *channel = NULL;
4808 int has_readahead = FALSE;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004809
4810 if (tv->v_type == VAR_JOB)
4811 {
4812 if (tv->vval.v_job != NULL)
4813 channel = tv->vval.v_job->jv_channel;
4814 }
4815 else if (tv->v_type == VAR_CHANNEL)
4816 {
4817 channel = tv->vval.v_channel;
4818 }
4819 else
4820 {
4821 EMSG2(_(e_invarg2), get_tv_string(tv));
4822 return NULL;
4823 }
Bram Moolenaar437905c2016-04-26 19:01:05 +02004824 if (channel != NULL && reading)
4825 has_readahead = channel_has_readahead(channel,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004826 part != PART_COUNT ? part : channel_part_read(channel));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004827
Bram Moolenaar437905c2016-04-26 19:01:05 +02004828 if (check_open && (channel == NULL || (!channel_is_open(channel)
4829 && !(reading && has_readahead))))
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004830 {
4831 EMSG(_("E906: not an open channel"));
4832 return NULL;
4833 }
4834 return channel;
4835}
4836
4837static job_T *first_job = NULL;
4838
4839 static void
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02004840job_free_contents(job_T *job)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004841{
4842 ch_log(job->jv_channel, "Freeing job");
4843 if (job->jv_channel != NULL)
4844 {
4845 /* The link from the channel to the job doesn't count as a reference,
4846 * thus don't decrement the refcount of the job. The reference from
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02004847 * the job to the channel does count the reference, decrement it and
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004848 * NULL the reference. We don't set ch_job_killed, unreferencing the
4849 * job doesn't mean it stops running. */
4850 job->jv_channel->ch_job = NULL;
4851 channel_unref(job->jv_channel);
4852 }
4853 mch_clear_job(job);
4854
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004855 vim_free(job->jv_tty_name);
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02004856 vim_free(job->jv_stoponexit);
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02004857 free_callback(job->jv_exit_cb, job->jv_exit_partial);
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02004858}
4859
4860 static void
4861job_free_job(job_T *job)
4862{
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004863 if (job->jv_next != NULL)
4864 job->jv_next->jv_prev = job->jv_prev;
4865 if (job->jv_prev == NULL)
4866 first_job = job->jv_next;
4867 else
4868 job->jv_prev->jv_next = job->jv_next;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004869 vim_free(job);
4870}
4871
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02004872 static void
4873job_free(job_T *job)
4874{
4875 if (!in_free_unref_items)
4876 {
4877 job_free_contents(job);
4878 job_free_job(job);
4879 }
4880}
4881
Bram Moolenaar7df915d2016-11-17 17:25:32 +01004882#if defined(EXITFREE) || defined(PROTO)
4883 void
4884job_free_all(void)
4885{
4886 while (first_job != NULL)
4887 job_free(first_job);
4888}
4889#endif
4890
4891/*
4892 * Return TRUE if we need to check if the process of "job" has ended.
4893 */
4894 static int
4895job_need_end_check(job_T *job)
4896{
4897 return job->jv_status == JOB_STARTED
4898 && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL);
4899}
4900
4901/*
4902 * Return TRUE if the channel of "job" is still useful.
4903 */
4904 static int
4905job_channel_still_useful(job_T *job)
4906{
4907 return job->jv_channel != NULL && channel_still_useful(job->jv_channel);
4908}
4909
4910/*
4911 * Return TRUE if the job should not be freed yet. Do not free the job when
4912 * it has not ended yet and there is a "stoponexit" flag, an exit callback
4913 * or when the associated channel will do something with the job output.
4914 */
4915 static int
4916job_still_useful(job_T *job)
4917{
4918 return job_need_end_check(job) || job_channel_still_useful(job);
4919}
4920
Bram Moolenaardcaa6132017-08-13 17:13:09 +02004921#if !defined(USE_ARGV) || defined(PROTO)
4922/*
4923 * Escape one argument for an external command.
4924 * Returns the escaped string in allocated memory. NULL when out of memory.
4925 */
4926 static char_u *
4927win32_escape_arg(char_u *arg)
4928{
4929 int slen, dlen;
4930 int escaping = 0;
4931 int i;
4932 char_u *s, *d;
4933 char_u *escaped_arg;
4934 int has_spaces = FALSE;
4935
4936 /* First count the number of extra bytes required. */
Bram Moolenaare85928a2017-08-27 13:10:10 +02004937 slen = (int)STRLEN(arg);
Bram Moolenaardcaa6132017-08-13 17:13:09 +02004938 dlen = slen;
4939 for (s = arg; *s != NUL; MB_PTR_ADV(s))
4940 {
4941 if (*s == '"' || *s == '\\')
4942 ++dlen;
4943 if (*s == ' ' || *s == '\t')
4944 has_spaces = TRUE;
4945 }
4946
4947 if (has_spaces)
4948 dlen += 2;
4949
4950 if (dlen == slen)
4951 return vim_strsave(arg);
4952
4953 /* Allocate memory for the result and fill it. */
4954 escaped_arg = alloc(dlen + 1);
4955 if (escaped_arg == NULL)
4956 return NULL;
4957 memset(escaped_arg, 0, dlen+1);
4958
4959 d = escaped_arg;
4960
4961 if (has_spaces)
4962 *d++ = '"';
4963
4964 for (s = arg; *s != NUL;)
4965 {
4966 switch (*s)
4967 {
4968 case '"':
4969 for (i = 0; i < escaping; i++)
4970 *d++ = '\\';
4971 escaping = 0;
4972 *d++ = '\\';
4973 *d++ = *s++;
4974 break;
4975 case '\\':
4976 escaping++;
4977 *d++ = *s++;
4978 break;
4979 default:
4980 escaping = 0;
4981 MB_COPY_CHAR(s, d);
4982 break;
4983 }
4984 }
4985
4986 /* add terminating quote and finish with a NUL */
4987 if (has_spaces)
4988 {
4989 for (i = 0; i < escaping; i++)
4990 *d++ = '\\';
4991 *d++ = '"';
4992 }
4993 *d = NUL;
4994
4995 return escaped_arg;
4996}
4997
4998/*
4999 * Build a command line from a list, taking care of escaping.
5000 * The result is put in gap->ga_data.
5001 * Returns FAIL when out of memory.
5002 */
5003 int
5004win32_build_cmd(list_T *l, garray_T *gap)
5005{
5006 listitem_T *li;
5007 char_u *s;
5008
5009 for (li = l->lv_first; li != NULL; li = li->li_next)
5010 {
5011 s = get_tv_string_chk(&li->li_tv);
5012 if (s == NULL)
5013 return FAIL;
5014 s = win32_escape_arg(s);
5015 if (s == NULL)
5016 return FAIL;
5017 ga_concat(gap, s);
5018 vim_free(s);
5019 if (li->li_next != NULL)
5020 ga_append(gap, ' ');
5021 }
5022 return OK;
5023}
5024#endif
5025
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005026/*
5027 * NOTE: Must call job_cleanup() only once right after the status of "job"
5028 * changed to JOB_ENDED (i.e. after job_status() returned "dead" first or
5029 * mch_detect_ended_job() returned non-NULL).
5030 */
Bram Moolenaar8f84c3a2017-07-22 16:14:44 +02005031 void
Bram Moolenaar97792de2016-10-15 18:36:49 +02005032job_cleanup(job_T *job)
5033{
5034 if (job->jv_status != JOB_ENDED)
5035 return;
5036
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005037 /* Ready to cleanup the job. */
5038 job->jv_status = JOB_FINISHED;
5039
Bram Moolenaar97792de2016-10-15 18:36:49 +02005040 if (job->jv_exit_cb != NULL)
5041 {
5042 typval_T argv[3];
5043 typval_T rettv;
5044 int dummy;
5045
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005046 /* Invoke the exit callback. Make sure the refcount is > 0. */
Bram Moolenaar3c3a80d2017-08-03 17:06:45 +02005047 ch_log(job->jv_channel, "Invoking exit callback %s", job->jv_exit_cb);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005048 ++job->jv_refcount;
5049 argv[0].v_type = VAR_JOB;
5050 argv[0].vval.v_job = job;
5051 argv[1].v_type = VAR_NUMBER;
5052 argv[1].vval.v_number = job->jv_exitval;
5053 call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
5054 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
5055 job->jv_exit_partial, NULL);
5056 clear_tv(&rettv);
5057 --job->jv_refcount;
5058 channel_need_redraw = TRUE;
5059 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005060
5061 /* Do not free the job in case the close callback of the associated channel
5062 * isn't invoked yet and may get information by job_info(). */
5063 if (job->jv_refcount == 0 && !job_channel_still_useful(job))
Bram Moolenaar97792de2016-10-15 18:36:49 +02005064 {
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005065 /* The job was already unreferenced and the associated channel was
5066 * detached, now that it ended it can be freed. Careful: caller must
5067 * not use "job" after this! */
Bram Moolenaar97792de2016-10-15 18:36:49 +02005068 job_free(job);
5069 }
5070}
5071
Bram Moolenaarb8d49052016-05-01 14:22:16 +02005072/*
5073 * Mark references in jobs that are still useful.
5074 */
5075 int
5076set_ref_in_job(int copyID)
5077{
5078 int abort = FALSE;
5079 job_T *job;
5080 typval_T tv;
5081
5082 for (job = first_job; job != NULL; job = job->jv_next)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005083 if (job_still_useful(job))
Bram Moolenaarb8d49052016-05-01 14:22:16 +02005084 {
5085 tv.v_type = VAR_JOB;
5086 tv.vval.v_job = job;
5087 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
5088 }
5089 return abort;
5090}
5091
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005092/*
5093 * Dereference "job". Note that after this "job" may have been freed.
5094 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005095 void
5096job_unref(job_T *job)
5097{
5098 if (job != NULL && --job->jv_refcount <= 0)
5099 {
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005100 /* Do not free the job if there is a channel where the close callback
5101 * may get the job info. */
5102 if (!job_channel_still_useful(job))
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005103 {
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005104 /* Do not free the job when it has not ended yet and there is a
5105 * "stoponexit" flag or an exit callback. */
5106 if (!job_need_end_check(job))
5107 {
5108 job_free(job);
5109 }
5110 else if (job->jv_channel != NULL)
5111 {
5112 /* Do remove the link to the channel, otherwise it hangs
5113 * around until Vim exits. See job_free() for refcount. */
5114 ch_log(job->jv_channel, "detaching channel from job");
5115 job->jv_channel->ch_job = NULL;
5116 channel_unref(job->jv_channel);
5117 job->jv_channel = NULL;
5118 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005119 }
5120 }
5121}
5122
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005123 int
5124free_unused_jobs_contents(int copyID, int mask)
5125{
5126 int did_free = FALSE;
5127 job_T *job;
5128
5129 for (job = first_job; job != NULL; job = job->jv_next)
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +02005130 if ((job->jv_copyID & mask) != (copyID & mask)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005131 && !job_still_useful(job))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005132 {
5133 /* Free the channel and ordinary items it contains, but don't
5134 * recurse into Lists, Dictionaries etc. */
5135 job_free_contents(job);
5136 did_free = TRUE;
Bram Moolenaar36e0f7d2016-05-08 13:21:12 +02005137 }
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005138 return did_free;
5139}
5140
5141 void
5142free_unused_jobs(int copyID, int mask)
5143{
5144 job_T *job;
5145 job_T *job_next;
5146
5147 for (job = first_job; job != NULL; job = job_next)
5148 {
5149 job_next = job->jv_next;
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +02005150 if ((job->jv_copyID & mask) != (copyID & mask)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005151 && !job_still_useful(job))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005152 {
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +02005153 /* Free the job struct itself. */
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005154 job_free_job(job);
5155 }
5156 }
5157}
5158
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005159/*
5160 * Allocate a job. Sets the refcount to one and sets options default.
5161 */
Bram Moolenaar8f84c3a2017-07-22 16:14:44 +02005162 job_T *
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005163job_alloc(void)
5164{
5165 job_T *job;
5166
5167 job = (job_T *)alloc_clear(sizeof(job_T));
5168 if (job != NULL)
5169 {
5170 job->jv_refcount = 1;
5171 job->jv_stoponexit = vim_strsave((char_u *)"term");
5172
5173 if (first_job != NULL)
5174 {
5175 first_job->jv_prev = job;
5176 job->jv_next = first_job;
5177 }
5178 first_job = job;
5179 }
5180 return job;
5181}
5182
5183 void
5184job_set_options(job_T *job, jobopt_T *opt)
5185{
5186 if (opt->jo_set & JO_STOPONEXIT)
5187 {
5188 vim_free(job->jv_stoponexit);
5189 if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
5190 job->jv_stoponexit = NULL;
5191 else
5192 job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
5193 }
5194 if (opt->jo_set & JO_EXIT_CB)
5195 {
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02005196 free_callback(job->jv_exit_cb, job->jv_exit_partial);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005197 if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005198 {
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005199 job->jv_exit_cb = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005200 job->jv_exit_partial = NULL;
5201 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005202 else
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005203 {
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005204 job->jv_exit_partial = opt->jo_exit_partial;
5205 if (job->jv_exit_partial != NULL)
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02005206 {
5207 job->jv_exit_cb = opt->jo_exit_cb;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005208 ++job->jv_exit_partial->pt_refcount;
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02005209 }
5210 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02005211 {
Bram Moolenaar57e69ff2016-07-30 23:05:09 +02005212 job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02005213 func_ref(job->jv_exit_cb);
5214 }
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005215 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005216 }
5217}
5218
5219/*
5220 * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
5221 */
5222 void
Bram Moolenaarcf089462016-06-12 21:18:43 +02005223job_stop_on_exit(void)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005224{
5225 job_T *job;
5226
5227 for (job = first_job; job != NULL; job = job->jv_next)
5228 if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005229 mch_signal_job(job, job->jv_stoponexit);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005230}
5231
5232/*
Bram Moolenaar01688ad2016-10-27 20:00:07 +02005233 * Return TRUE when there is any job that has an exit callback and might exit,
5234 * which means job_check_ended() should be called more often.
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005235 */
5236 int
Bram Moolenaarcf089462016-06-12 21:18:43 +02005237has_pending_job(void)
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005238{
5239 job_T *job;
5240
5241 for (job = first_job; job != NULL; job = job->jv_next)
Bram Moolenaar01688ad2016-10-27 20:00:07 +02005242 /* Only should check if the channel has been closed, if the channel is
5243 * open the job won't exit. */
5244 if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005245 && !job_channel_still_useful(job))
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005246 return TRUE;
5247 return FALSE;
5248}
5249
Bram Moolenaar97792de2016-10-15 18:36:49 +02005250#define MAX_CHECK_ENDED 8
5251
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005252/*
Bram Moolenaar36e0f7d2016-05-08 13:21:12 +02005253 * Called once in a while: check if any jobs that seem useful have ended.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005254 */
5255 void
5256job_check_ended(void)
5257{
Bram Moolenaar97792de2016-10-15 18:36:49 +02005258 int i;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005259
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005260 if (first_job == NULL)
5261 return;
5262
Bram Moolenaar97792de2016-10-15 18:36:49 +02005263 for (i = 0; i < MAX_CHECK_ENDED; ++i)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005264 {
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005265 /* NOTE: mch_detect_ended_job() must only return a job of which the
5266 * status was just set to JOB_ENDED. */
Bram Moolenaar97792de2016-10-15 18:36:49 +02005267 job_T *job = mch_detect_ended_job(first_job);
5268
5269 if (job == NULL)
5270 break;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005271 job_cleanup(job); /* may free "job" */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005272 }
Bram Moolenaar97792de2016-10-15 18:36:49 +02005273
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005274 if (channel_need_redraw)
5275 {
5276 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02005277 redraw_after_callback(TRUE);
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005278 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005279}
5280
5281/*
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02005282 * Create a job and return it. Implements job_start().
5283 * The returned job has a refcount of one.
5284 * Returns NULL when out of memory.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005285 */
5286 job_T *
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02005287job_start(typval_T *argvars, jobopt_T *opt_arg)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005288{
5289 job_T *job;
5290 char_u *cmd = NULL;
5291#if defined(UNIX)
5292# define USE_ARGV
5293 char **argv = NULL;
5294 int argc = 0;
5295#else
5296 garray_T ga;
5297#endif
5298 jobopt_T opt;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02005299 ch_part_T part;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005300
5301 job = job_alloc();
5302 if (job == NULL)
5303 return NULL;
5304
5305 job->jv_status = JOB_FAILED;
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005306#ifndef USE_ARGV
5307 ga_init2(&ga, (int)sizeof(char*), 20);
5308#endif
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005309
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02005310 if (opt_arg != NULL)
5311 opt = *opt_arg;
5312 else
5313 {
5314 /* Default mode is NL. */
5315 clear_job_options(&opt);
5316 opt.jo_mode = MODE_NL;
5317 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar8ed54002017-08-11 22:22:36 +02005318 JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
5319 + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE,
5320 JO2_ENV + JO2_CWD) == FAIL)
Bram Moolenaar3c3a80d2017-08-03 17:06:45 +02005321 goto theend;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02005322 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005323
5324 /* Check that when io is "file" that there is a file name. */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02005325 for (part = PART_OUT; part < PART_COUNT; ++part)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005326 if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
5327 && opt.jo_io[part] == JIO_FILE
5328 && (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
5329 || *opt.jo_io_name[part] == NUL))
5330 {
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005331 EMSG(_("E920: _io file requires _name to be set"));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005332 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005333 }
5334
5335 if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
5336 {
5337 buf_T *buf = NULL;
5338
5339 /* check that we can find the buffer before starting the job */
5340 if (opt.jo_set & JO_IN_BUF)
5341 {
5342 buf = buflist_findnr(opt.jo_io_buf[PART_IN]);
5343 if (buf == NULL)
5344 EMSGN(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]);
5345 }
5346 else if (!(opt.jo_set & JO_IN_NAME))
5347 {
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005348 EMSG(_("E915: in_io buffer requires in_buf or in_name to be set"));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005349 }
5350 else
5351 buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
5352 if (buf == NULL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005353 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005354 if (buf->b_ml.ml_mfp == NULL)
5355 {
5356 char_u numbuf[NUMBUFLEN];
5357 char_u *s;
5358
5359 if (opt.jo_set & JO_IN_BUF)
5360 {
5361 sprintf((char *)numbuf, "%d", opt.jo_io_buf[PART_IN]);
5362 s = numbuf;
5363 }
5364 else
5365 s = opt.jo_io_name[PART_IN];
5366 EMSG2(_("E918: buffer must be loaded: %s"), s);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005367 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005368 }
5369 job->jv_in_buf = buf;
5370 }
5371
5372 job_set_options(job, &opt);
5373
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005374 if (argvars[0].v_type == VAR_STRING)
5375 {
5376 /* Command is a string. */
5377 cmd = argvars[0].vval.v_string;
Bram Moolenaar80385682016-03-27 19:13:35 +02005378 if (cmd == NULL || *cmd == NUL)
5379 {
5380 EMSG(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005381 goto theend;
Bram Moolenaar80385682016-03-27 19:13:35 +02005382 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005383#ifdef USE_ARGV
5384 if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005385 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005386 argv[argc] = NULL;
5387#endif
5388 }
5389 else if (argvars[0].v_type != VAR_LIST
5390 || argvars[0].vval.v_list == NULL
5391 || argvars[0].vval.v_list->lv_len < 1)
5392 {
5393 EMSG(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005394 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005395 }
5396 else
5397 {
5398 list_T *l = argvars[0].vval.v_list;
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005399#ifdef USE_ARGV
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005400 listitem_T *li;
5401 char_u *s;
5402
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005403 /* Pass argv[] to mch_call_shell(). */
5404 argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
5405 if (argv == NULL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005406 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005407 for (li = l->lv_first; li != NULL; li = li->li_next)
5408 {
5409 s = get_tv_string_chk(&li->li_tv);
5410 if (s == NULL)
5411 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005412 argv[argc++] = (char *)s;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005413 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005414 argv[argc] = NULL;
5415#else
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005416 if (win32_build_cmd(l, &ga) == FAIL)
5417 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005418 cmd = ga.ga_data;
5419#endif
5420 }
5421
5422#ifdef USE_ARGV
5423 if (ch_log_active())
5424 {
5425 garray_T ga;
5426 int i;
5427
5428 ga_init2(&ga, (int)sizeof(char), 200);
5429 for (i = 0; i < argc; ++i)
5430 {
5431 if (i > 0)
5432 ga_concat(&ga, (char_u *)" ");
5433 ga_concat(&ga, (char_u *)argv[i]);
5434 }
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02005435 ch_log(NULL, "Starting job: %s", (char *)ga.ga_data);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005436 ga_clear(&ga);
5437 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005438 mch_job_start(argv, job, &opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005439#else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02005440 ch_log(NULL, "Starting job: %s", (char *)cmd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005441 mch_job_start((char *)cmd, job, &opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005442#endif
5443
5444 /* If the channel is reading from a buffer, write lines now. */
5445 if (job->jv_channel != NULL)
5446 channel_write_in(job->jv_channel);
5447
5448theend:
5449#ifdef USE_ARGV
5450 vim_free(argv);
5451#else
5452 vim_free(ga.ga_data);
5453#endif
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02005454 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005455 return job;
5456}
5457
5458/*
5459 * Get the status of "job" and invoke the exit callback when needed.
5460 * The returned string is not allocated.
5461 */
5462 char *
5463job_status(job_T *job)
5464{
5465 char *result;
5466
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005467 if (job->jv_status >= JOB_ENDED)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005468 /* No need to check, dead is dead. */
5469 result = "dead";
5470 else if (job->jv_status == JOB_FAILED)
5471 result = "fail";
5472 else
5473 {
5474 result = mch_job_status(job);
5475 if (job->jv_status == JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005476 job_cleanup(job);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005477 }
5478 return result;
5479}
5480
Bram Moolenaar8950a562016-03-12 15:22:55 +01005481/*
5482 * Implementation of job_info().
5483 */
5484 void
5485job_info(job_T *job, dict_T *dict)
5486{
5487 dictitem_T *item;
5488 varnumber_T nr;
5489
5490 dict_add_nr_str(dict, "status", 0L, (char_u *)job_status(job));
5491
5492 item = dictitem_alloc((char_u *)"channel");
5493 if (item == NULL)
5494 return;
5495 item->di_tv.v_lock = 0;
5496 item->di_tv.v_type = VAR_CHANNEL;
5497 item->di_tv.vval.v_channel = job->jv_channel;
5498 if (job->jv_channel != NULL)
5499 ++job->jv_channel->ch_refcount;
5500 if (dict_add(dict, item) == FAIL)
5501 dictitem_free(item);
5502
5503#ifdef UNIX
5504 nr = job->jv_pid;
5505#else
5506 nr = job->jv_proc_info.dwProcessId;
5507#endif
5508 dict_add_nr_str(dict, "process", nr, NULL);
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02005509 dict_add_nr_str(dict, "tty", 0L,
5510 job->jv_tty_name != NULL ? job->jv_tty_name : (char_u *)"");
Bram Moolenaar8950a562016-03-12 15:22:55 +01005511
5512 dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005513 dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
Bram Moolenaar8950a562016-03-12 15:22:55 +01005514 dict_add_nr_str(dict, "stoponexit", 0L, job->jv_stoponexit);
5515}
5516
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02005517/*
5518 * Send a signal to "job". Implements job_stop().
5519 * When "type" is not NULL use this for the type.
5520 * Otherwise use argvars[1] for the type.
5521 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005522 int
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02005523job_stop(job_T *job, typval_T *argvars, char *type)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005524{
5525 char_u *arg;
5526
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02005527 if (type != NULL)
5528 arg = (char_u *)type;
5529 else if (argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005530 arg = (char_u *)"";
5531 else
5532 {
5533 arg = get_tv_string_chk(&argvars[1]);
5534 if (arg == NULL)
5535 {
5536 EMSG(_(e_invarg));
5537 return 0;
5538 }
5539 }
Bram Moolenaar61a66052017-07-22 18:39:00 +02005540 if (job->jv_status == JOB_FAILED)
5541 {
5542 ch_log(job->jv_channel, "Job failed to start, job_stop() skipped");
5543 return 0;
5544 }
Bram Moolenaar1a9020d2017-04-29 16:24:38 +02005545 if (job->jv_status == JOB_ENDED)
5546 {
5547 ch_log(job->jv_channel, "Job has already ended, job_stop() skipped");
5548 return 0;
5549 }
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02005550 ch_log(job->jv_channel, "Stopping job with '%s'", (char *)arg);
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005551 if (mch_signal_job(job, arg) == FAIL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005552 return 0;
5553
Bram Moolenaar1a9020d2017-04-29 16:24:38 +02005554 /* Assume that only "kill" will kill the job. */
5555 if (job->jv_channel != NULL && STRCMP(arg, "kill") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005556 job->jv_channel->ch_job_killed = TRUE;
5557
5558 /* We don't try freeing the job, obviously the caller still has a
5559 * reference to it. */
5560 return 1;
5561}
5562
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005563#endif /* FEAT_JOB_CHANNEL */