blob: d11b148a89a2bc68df7324a83b4917e7756f7302 [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
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +020013#ifdef WIN32
14// Must include winsock2.h before windows.h since it conflicts with winsock.h
15// (included in windows.h).
16# include <winsock2.h>
17# include <ws2tcpip.h>
18#endif
19
Bram Moolenaare0874f82016-01-24 20:36:41 +010020#include "vim.h"
21
Bram Moolenaar509ce2a2016-03-11 22:52:15 +010022#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +010023
Bram Moolenaarc667da52019-11-30 20:52:27 +010024// TRUE when netbeans is running with a GUI.
Bram Moolenaard04a0202016-01-26 23:30:18 +010025#ifdef FEAT_GUI
26# define CH_HAS_GUI (gui.in_use || gui.starting)
27#endif
28
Bram Moolenaarc667da52019-11-30 20:52:27 +010029// Note: when making changes here also adjust configure.ac.
Bram Moolenaar4f974752019-02-17 17:44:42 +010030#ifdef MSWIN
Bram Moolenaarc667da52019-11-30 20:52:27 +010031// WinSock API is separated from C API, thus we can't use read(), write(),
32// errno...
Bram Moolenaard04a0202016-01-26 23:30:18 +010033# define SOCK_ERRNO errno = WSAGetLastError()
34# undef ECONNREFUSED
35# define ECONNREFUSED WSAECONNREFUSED
Bram Moolenaar4d919d72016-02-05 22:36:41 +010036# undef EWOULDBLOCK
37# define EWOULDBLOCK WSAEWOULDBLOCK
Bram Moolenaard42119f2016-02-28 20:51:49 +010038# undef EINPROGRESS
39# define EINPROGRESS WSAEINPROGRESS
Bram Moolenaard04a0202016-01-26 23:30:18 +010040# ifdef EINTR
41# undef EINTR
42# endif
43# define EINTR WSAEINTR
Bram Moolenaard8070362016-02-15 21:56:54 +010044# define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0)
45# define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0)
46# define sock_close(sd) closesocket((SOCKET)sd)
Bram Moolenaard04a0202016-01-26 23:30:18 +010047#else
48# include <netdb.h>
49# include <netinet/in.h>
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +020050# include <arpa/inet.h>
Bram Moolenaard04a0202016-01-26 23:30:18 +010051# include <sys/socket.h>
52# ifdef HAVE_LIBGEN_H
53# include <libgen.h>
54# endif
55# define SOCK_ERRNO
56# define sock_write(sd, buf, len) write(sd, buf, len)
57# define sock_read(sd, buf, len) read(sd, buf, len)
58# define sock_close(sd) close(sd)
Bram Moolenaar0943a092016-02-16 13:11:17 +010059# define fd_read(fd, buf, len) read(fd, buf, len)
Bram Moolenaard8070362016-02-15 21:56:54 +010060# define fd_write(sd, buf, len) write(sd, buf, len)
61# define fd_close(sd) close(sd)
Bram Moolenaard04a0202016-01-26 23:30:18 +010062#endif
63
Bram Moolenaardc0ccae2016-10-09 17:28:01 +020064static void channel_read(channel_T *channel, ch_part_T part, char *func);
Bram Moolenaar5843f5f2019-08-20 20:13:45 +020065static ch_mode_T channel_get_mode(channel_T *channel, ch_part_T part);
66static int channel_get_timeout(channel_T *channel, ch_part_T part);
67static ch_part_T channel_part_send(channel_T *channel);
68static ch_part_T channel_part_read(channel_T *channel);
69static void free_job_options(jobopt_T *opt);
Bram Moolenaarb2658a12016-04-26 17:16:24 +020070
Bram Moolenaaraeea7212020-04-02 18:50:46 +020071#define FOR_ALL_CHANNELS(ch) \
72 for ((ch) = first_channel; (ch) != NULL; (ch) = (ch)->ch_next)
73
74#define FOR_ALL_JOBS(job) \
75 for ((job) = first_job; (job) != NULL; (job) = (job)->jv_next)
76
Bram Moolenaarc667da52019-11-30 20:52:27 +010077// Whether a redraw is needed for appending a line to a buffer.
Bram Moolenaar187db502016-02-27 14:44:26 +010078static int channel_need_redraw = FALSE;
79
Bram Moolenaarc667da52019-11-30 20:52:27 +010080// Whether we are inside channel_parse_messages() or another situation where it
81// is safe to invoke callbacks.
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +020082static int safe_to_invoke_callback = 0;
Bram Moolenaar187db502016-02-27 14:44:26 +010083
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +020084static char *part_names[] = {"sock", "out", "err", "in"};
85
Bram Moolenaar4f974752019-02-17 17:44:42 +010086#ifdef MSWIN
Bram Moolenaard8070362016-02-15 21:56:54 +010087 static int
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +010088fd_read(sock_T fd, char *buf, size_t len)
Bram Moolenaard8070362016-02-15 21:56:54 +010089{
90 HANDLE h = (HANDLE)fd;
91 DWORD nread;
92
93 if (!ReadFile(h, buf, (DWORD)len, &nread, NULL))
94 return -1;
95 return (int)nread;
96}
97
98 static int
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +010099fd_write(sock_T fd, char *buf, size_t len)
Bram Moolenaard8070362016-02-15 21:56:54 +0100100{
Bram Moolenaar24058382019-01-24 23:11:49 +0100101 size_t todo = len;
Bram Moolenaarb091f302019-01-19 14:37:00 +0100102 HANDLE h = (HANDLE)fd;
Bram Moolenaar24058382019-01-24 23:11:49 +0100103 DWORD nwrite, size, done = 0;
Bram Moolenaarb091f302019-01-19 14:37:00 +0100104 OVERLAPPED ov;
Bram Moolenaard8070362016-02-15 21:56:54 +0100105
Bram Moolenaar24058382019-01-24 23:11:49 +0100106 while (todo > 0)
Bram Moolenaarb091f302019-01-19 14:37:00 +0100107 {
Bram Moolenaar24058382019-01-24 23:11:49 +0100108 if (todo > MAX_NAMED_PIPE_SIZE)
109 size = MAX_NAMED_PIPE_SIZE;
110 else
Bram Moolenaardec01202019-01-28 20:04:24 +0100111 size = (DWORD)todo;
Bram Moolenaar65240682019-02-10 22:23:26 +0100112 // If the pipe overflows while the job does not read the data,
113 // WriteFile() will block forever. This abandons the write.
Bram Moolenaar24058382019-01-24 23:11:49 +0100114 memset(&ov, 0, sizeof(ov));
Bram Moolenaar65240682019-02-10 22:23:26 +0100115 nwrite = 0;
Bram Moolenaar24058382019-01-24 23:11:49 +0100116 if (!WriteFile(h, buf + done, size, &nwrite, &ov))
117 {
118 DWORD err = GetLastError();
Bram Moolenaarb091f302019-01-19 14:37:00 +0100119
Bram Moolenaar24058382019-01-24 23:11:49 +0100120 if (err != ERROR_IO_PENDING)
121 return -1;
122 if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
123 return -1;
124 FlushFileBuffers(h);
125 }
Bram Moolenaar65240682019-02-10 22:23:26 +0100126 else if (nwrite == 0)
127 // WriteFile() returns TRUE but did not write anything. This causes
128 // a hang, so bail out.
129 break;
Bram Moolenaar24058382019-01-24 23:11:49 +0100130 todo -= nwrite;
131 done += nwrite;
Bram Moolenaarb091f302019-01-19 14:37:00 +0100132 }
Bram Moolenaar24058382019-01-24 23:11:49 +0100133 return (int)done;
Bram Moolenaard8070362016-02-15 21:56:54 +0100134}
135
136 static void
137fd_close(sock_T fd)
138{
139 HANDLE h = (HANDLE)fd;
140
141 CloseHandle(h);
142}
143#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100144
Bram Moolenaarc667da52019-11-30 20:52:27 +0100145// Log file opened with ch_logfile().
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100146static FILE *log_fd = NULL;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100147#ifdef FEAT_RELTIME
148static proftime_T log_start;
149#endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100150
151 void
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100152ch_logfile(char_u *fname, char_u *opt)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100153{
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100154 FILE *file = NULL;
155
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100156 if (log_fd != NULL)
Bram Moolenaar2e47cab2019-09-27 23:12:45 +0200157 {
158 if (*fname != NUL)
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200159 ch_log(NULL, "closing this logfile, opening %s", fname);
Bram Moolenaar2e47cab2019-09-27 23:12:45 +0200160 else
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200161 ch_log(NULL, "closing logfile");
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100162 fclose(log_fd);
Bram Moolenaar2e47cab2019-09-27 23:12:45 +0200163 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100164
165 if (*fname != NUL)
166 {
167 file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
168 if (file == NULL)
169 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100170 semsg(_(e_notopen), fname);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100171 return;
172 }
173 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100174 log_fd = file;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100175
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100176 if (log_fd != NULL)
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100177 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100178 fprintf(log_fd, "==== start log session ====\n");
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100179#ifdef FEAT_RELTIME
180 profile_start(&log_start);
181#endif
182 }
183}
184
185 int
Bram Moolenaarcf089462016-06-12 21:18:43 +0200186ch_log_active(void)
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100187{
188 return log_fd != NULL;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100189}
190
191 static void
Bram Moolenaar4b16ee72018-08-09 22:15:34 +0200192ch_log_lead(const char *what, channel_T *ch, ch_part_T part)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100193{
194 if (log_fd != NULL)
195 {
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100196#ifdef FEAT_RELTIME
197 proftime_T log_now;
198
199 profile_start(&log_now);
200 profile_sub(&log_now, &log_start);
201 fprintf(log_fd, "%s ", profile_msg(&log_now));
202#endif
Bram Moolenaar77073442016-02-13 23:23:53 +0100203 if (ch != NULL)
Bram Moolenaar4b16ee72018-08-09 22:15:34 +0200204 {
205 if (part < PART_COUNT)
206 fprintf(log_fd, "%son %d(%s): ",
207 what, ch->ch_id, part_names[part]);
208 else
209 fprintf(log_fd, "%son %d: ", what, ch->ch_id);
210 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100211 else
212 fprintf(log_fd, "%s: ", what);
213 }
214}
215
Bram Moolenaar8caa43d2019-02-20 22:45:06 +0100216#ifndef PROTO // prototype is in proto.h
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100217 void
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200218ch_log(channel_T *ch, const char *fmt, ...)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100219{
220 if (log_fd != NULL)
221 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200222 va_list ap;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100223
Bram Moolenaar4b16ee72018-08-09 22:15:34 +0200224 ch_log_lead("", ch, PART_COUNT);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200225 va_start(ap, fmt);
226 vfprintf(log_fd, fmt, ap);
227 va_end(ap);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100228 fputc('\n', log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100229 fflush(log_fd);
Bram Moolenaar101e9922019-09-25 21:43:11 +0200230 did_repeated_msg = 0;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100231 }
232}
Bram Moolenaar4ac2e8d2018-04-08 12:38:26 +0200233#endif
234
235 static void
236ch_error(channel_T *ch, const char *fmt, ...)
Bram Moolenaare80757c2018-04-10 12:42:44 +0200237#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
238 __attribute__((format(printf, 2, 3)))
Bram Moolenaar4ac2e8d2018-04-08 12:38:26 +0200239#endif
240 ;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100241
242 static void
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200243ch_error(channel_T *ch, const char *fmt, ...)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100244{
245 if (log_fd != NULL)
246 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200247 va_list ap;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100248
Bram Moolenaar4b16ee72018-08-09 22:15:34 +0200249 ch_log_lead("ERR ", ch, PART_COUNT);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200250 va_start(ap, fmt);
251 vfprintf(log_fd, fmt, ap);
252 va_end(ap);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100253 fputc('\n', log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100254 fflush(log_fd);
Bram Moolenaar101e9922019-09-25 21:43:11 +0200255 did_repeated_msg = 0;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100256 }
257}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100258
Bram Moolenaar4f974752019-02-17 17:44:42 +0100259#ifdef MSWIN
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100260# undef PERROR
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100261# define PERROR(msg) (void)semsg("%s: %s", msg, strerror_win32(errno))
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100262
263 static char *
264strerror_win32(int eno)
265{
266 static LPVOID msgbuf = NULL;
267 char_u *ptr;
268
269 if (msgbuf)
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200270 {
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100271 LocalFree(msgbuf);
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200272 msgbuf = NULL;
273 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100274 FormatMessage(
275 FORMAT_MESSAGE_ALLOCATE_BUFFER |
276 FORMAT_MESSAGE_FROM_SYSTEM |
277 FORMAT_MESSAGE_IGNORE_INSERTS,
278 NULL,
279 eno,
280 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
281 (LPTSTR) &msgbuf,
282 0,
283 NULL);
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200284 if (msgbuf != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100285 // chomp \r or \n
Bram Moolenaaraad30bb2016-06-26 17:31:03 +0200286 for (ptr = (char_u *)msgbuf; *ptr; ptr++)
287 switch (*ptr)
288 {
289 case '\r':
290 STRMOVE(ptr, ptr + 1);
291 ptr--;
292 break;
293 case '\n':
294 if (*(ptr + 1) == '\0')
295 *ptr = '\0';
296 else
297 *ptr = ' ';
298 break;
299 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100300 return msgbuf;
301}
302#endif
303
Bram Moolenaar77073442016-02-13 23:23:53 +0100304/*
305 * The list of all allocated channels.
306 */
307static channel_T *first_channel = NULL;
308static int next_ch_id = 0;
309
310/*
311 * Allocate a new channel. The refcount is set to 1.
312 * The channel isn't actually used until it is opened.
313 * Returns NULL if out of memory.
314 */
315 channel_T *
316add_channel(void)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100317{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200318 ch_part_T part;
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200319 channel_T *channel = ALLOC_CLEAR_ONE(channel_T);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100320
Bram Moolenaar77073442016-02-13 23:23:53 +0100321 if (channel == NULL)
322 return NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100323
Bram Moolenaar77073442016-02-13 23:23:53 +0100324 channel->ch_id = next_ch_id++;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100325 ch_log(channel, "Created channel");
Bram Moolenaar77073442016-02-13 23:23:53 +0100326
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200327 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100328 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100329 channel->ch_part[part].ch_fd = INVALID_FD;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100330#ifdef FEAT_GUI_X11
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100331 channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100332#endif
333#ifdef FEAT_GUI_GTK
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100334 channel->ch_part[part].ch_inputHandler = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100335#endif
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100336 channel->ch_part[part].ch_timeout = 2000;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100337 }
Bram Moolenaare0874f82016-01-24 20:36:41 +0100338
Bram Moolenaar77073442016-02-13 23:23:53 +0100339 if (first_channel != NULL)
340 {
341 first_channel->ch_prev = channel;
342 channel->ch_next = first_channel;
343 }
344 first_channel = channel;
345
346 channel->ch_refcount = 1;
347 return channel;
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100348}
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100349
Bram Moolenaarb9c31e72016-09-29 15:18:57 +0200350 int
351has_any_channel(void)
352{
353 return first_channel != NULL;
354}
355
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100356/*
Bram Moolenaard6051b52016-02-28 15:49:03 +0100357 * Called when the refcount of a channel is zero.
Bram Moolenaar46c85432016-02-26 11:17:46 +0100358 * Return TRUE if "channel" has a callback and the associated job wasn't
359 * killed.
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100360 */
361 static int
Bram Moolenaar46c85432016-02-26 11:17:46 +0100362channel_still_useful(channel_T *channel)
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100363{
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100364 int has_sock_msg;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100365 int has_out_msg;
366 int has_err_msg;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100367
Bram Moolenaarc667da52019-11-30 20:52:27 +0100368 // If the job was killed the channel is not expected to work anymore.
Bram Moolenaar46c85432016-02-26 11:17:46 +0100369 if (channel->ch_job_killed && channel->ch_job == NULL)
370 return FALSE;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100371
Bram Moolenaarc667da52019-11-30 20:52:27 +0100372 // If there is a close callback it may still need to be invoked.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200373 if (channel->ch_close_cb.cb_name != NULL)
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100374 return TRUE;
375
Bram Moolenaarc667da52019-11-30 20:52:27 +0100376 // If reading from or a buffer it's still useful.
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200377 if (channel->ch_part[PART_IN].ch_bufref.br_buf != NULL)
Bram Moolenaar5d96e3a2016-05-08 21:47:01 +0200378 return TRUE;
379
Bram Moolenaarc667da52019-11-30 20:52:27 +0100380 // If there is no callback then nobody can get readahead. If the fd is
381 // closed and there is no readahead then the callback won't be called.
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100382 has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD
Bram Moolenaard23a8232018-02-10 18:45:26 +0100383 || channel->ch_part[PART_SOCK].ch_head.rq_next != NULL
384 || channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL;
Bram Moolenaarfdd6ce42016-02-28 22:21:38 +0100385 has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD
386 || channel->ch_part[PART_OUT].ch_head.rq_next != NULL
387 || channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL;
388 has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
389 || channel->ch_part[PART_ERR].ch_head.rq_next != NULL
390 || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200391 return (channel->ch_callback.cb_name != NULL && (has_sock_msg
Bram Moolenaar509ce2a2016-03-11 22:52:15 +0100392 || has_out_msg || has_err_msg))
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200393 || ((channel->ch_part[PART_OUT].ch_callback.cb_name != NULL
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200394 || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
395 && has_out_msg)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200396 || ((channel->ch_part[PART_ERR].ch_callback.cb_name != NULL
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200397 || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
398 && has_err_msg);
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100399}
400
401/*
Bram Moolenaar4e9d4432018-04-24 20:54:07 +0200402 * Return TRUE if "channel" is closeable (i.e. all readable fds are closed).
403 */
404 static int
405channel_can_close(channel_T *channel)
406{
407 return channel->ch_to_be_closed == 0;
408}
409
410/*
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200411 * Close a channel and free all its resources.
Bram Moolenaar71658f72020-03-24 20:35:19 +0100412 * The "channel" pointer remains valid.
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200413 */
414 static void
415channel_free_contents(channel_T *channel)
416{
417 channel_close(channel, TRUE);
418 channel_clear(channel);
419 ch_log(channel, "Freeing channel");
420}
421
Bram Moolenaar71658f72020-03-24 20:35:19 +0100422/*
423 * Unlink "channel" from the list of channels and free it.
424 */
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200425 static void
426channel_free_channel(channel_T *channel)
427{
428 if (channel->ch_next != NULL)
429 channel->ch_next->ch_prev = channel->ch_prev;
430 if (channel->ch_prev == NULL)
431 first_channel = channel->ch_next;
432 else
433 channel->ch_prev->ch_next = channel->ch_next;
434 vim_free(channel);
435}
436
437 static void
438channel_free(channel_T *channel)
439{
440 if (!in_free_unref_items)
441 {
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200442 if (safe_to_invoke_callback == 0)
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200443 channel->ch_to_be_freed = TRUE;
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200444 else
445 {
446 channel_free_contents(channel);
447 channel_free_channel(channel);
448 }
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200449 }
450}
451
452/*
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100453 * Close a channel and free all its resources if there is no further action
Bram Moolenaar46c85432016-02-26 11:17:46 +0100454 * possible, there is no callback to be invoked or the associated job was
455 * killed.
Bram Moolenaar70765942016-02-28 19:28:59 +0100456 * Return TRUE if the channel was freed.
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100457 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100458 static int
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100459channel_may_free(channel_T *channel)
460{
Bram Moolenaar46c85432016-02-26 11:17:46 +0100461 if (!channel_still_useful(channel))
Bram Moolenaar70765942016-02-28 19:28:59 +0100462 {
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100463 channel_free(channel);
Bram Moolenaar70765942016-02-28 19:28:59 +0100464 return TRUE;
465 }
466 return FALSE;
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +0100467}
468
469/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +0100470 * Decrement the reference count on "channel" and maybe free it when it goes
471 * down to zero. Don't free it if there is a pending action.
472 * Returns TRUE when the channel is no longer referenced.
473 */
474 int
475channel_unref(channel_T *channel)
476{
477 if (channel != NULL && --channel->ch_refcount <= 0)
478 return channel_may_free(channel);
479 return FALSE;
480}
481
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200482 int
483free_unused_channels_contents(int copyID, int mask)
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100484{
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200485 int did_free = FALSE;
486 channel_T *ch;
487
Bram Moolenaarc667da52019-11-30 20:52:27 +0100488 // This is invoked from the garbage collector, which only runs at a safe
489 // point.
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200490 ++safe_to_invoke_callback;
491
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200492 FOR_ALL_CHANNELS(ch)
Bram Moolenaar674127e2016-04-26 20:30:07 +0200493 if (!channel_still_useful(ch)
494 && (ch->ch_copyID & mask) != (copyID & mask))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200495 {
Bram Moolenaarc667da52019-11-30 20:52:27 +0100496 // Free the channel and ordinary items it contains, but don't
497 // recurse into Lists, Dictionaries etc.
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200498 channel_free_contents(ch);
499 did_free = TRUE;
500 }
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +0200501
502 --safe_to_invoke_callback;
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200503 return did_free;
504}
505
506 void
507free_unused_channels(int copyID, int mask)
508{
509 channel_T *ch;
510 channel_T *ch_next;
511
512 for (ch = first_channel; ch != NULL; ch = ch_next)
513 {
514 ch_next = ch->ch_next;
Bram Moolenaar674127e2016-04-26 20:30:07 +0200515 if (!channel_still_useful(ch)
516 && (ch->ch_copyID & mask) != (copyID & mask))
Bram Moolenaarc667da52019-11-30 20:52:27 +0100517 // Free the channel struct itself.
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200518 channel_free_channel(ch);
Bram Moolenaar107e1ee2016-04-08 17:07:19 +0200519 }
Bram Moolenaare0874f82016-01-24 20:36:41 +0100520}
521
Bram Moolenaard04a0202016-01-26 23:30:18 +0100522#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar77073442016-02-13 23:23:53 +0100523
Bram Moolenaarea781452019-09-04 18:53:12 +0200524# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
525/*
526 * Lookup the channel from the socket. Set "partp" to the fd index.
527 * Returns NULL when the socket isn't found.
528 */
529 static channel_T *
530channel_fd2channel(sock_T fd, ch_part_T *partp)
531{
532 channel_T *channel;
533 ch_part_T part;
534
535 if (fd != INVALID_FD)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200536 FOR_ALL_CHANNELS(channel)
Bram Moolenaarea781452019-09-04 18:53:12 +0200537 {
538 for (part = PART_SOCK; part < PART_IN; ++part)
539 if (channel->ch_part[part].ch_fd == fd)
540 {
541 *partp = part;
542 return channel;
543 }
544 }
545 return NULL;
546}
547
Bram Moolenaar77073442016-02-13 23:23:53 +0100548 static void
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100549channel_read_fd(int fd)
Bram Moolenaar77073442016-02-13 23:23:53 +0100550{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100551 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200552 ch_part_T part;
Bram Moolenaar77073442016-02-13 23:23:53 +0100553
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100554 channel = channel_fd2channel(fd, &part);
Bram Moolenaar77073442016-02-13 23:23:53 +0100555 if (channel == NULL)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200556 ch_error(NULL, "Channel for fd %d not found", fd);
Bram Moolenaar77073442016-02-13 23:23:53 +0100557 else
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200558 channel_read(channel, part, "channel_read_fd");
Bram Moolenaar77073442016-02-13 23:23:53 +0100559}
Bram Moolenaarea781452019-09-04 18:53:12 +0200560# endif
Bram Moolenaar77073442016-02-13 23:23:53 +0100561
Bram Moolenaare0874f82016-01-24 20:36:41 +0100562/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100563 * Read a command from netbeans.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100564 */
Bram Moolenaarea781452019-09-04 18:53:12 +0200565# ifdef FEAT_GUI_X11
Bram Moolenaard04a0202016-01-26 23:30:18 +0100566 static void
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200567messageFromServerX11(XtPointer clientData,
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200568 int *unused1 UNUSED,
569 XtInputId *unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100570{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100571 channel_read_fd((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100572}
Bram Moolenaarea781452019-09-04 18:53:12 +0200573# endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100574
Bram Moolenaarea781452019-09-04 18:53:12 +0200575# ifdef FEAT_GUI_GTK
576# if GTK_CHECK_VERSION(3,0,0)
Bram Moolenaar98921892016-02-23 17:14:37 +0100577 static gboolean
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200578messageFromServerGtk3(GIOChannel *unused1 UNUSED,
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200579 GIOCondition unused2 UNUSED,
580 gpointer clientData)
Bram Moolenaar98921892016-02-23 17:14:37 +0100581{
582 channel_read_fd(GPOINTER_TO_INT(clientData));
Bram Moolenaarc667da52019-11-30 20:52:27 +0100583 return TRUE; // Return FALSE instead in case the event source is to
584 // be removed after this function returns.
Bram Moolenaar98921892016-02-23 17:14:37 +0100585}
Bram Moolenaarea781452019-09-04 18:53:12 +0200586# else
Bram Moolenaard04a0202016-01-26 23:30:18 +0100587 static void
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200588messageFromServerGtk2(gpointer clientData,
Bram Moolenaarf8df45d2016-05-25 21:48:13 +0200589 gint unused1 UNUSED,
590 GdkInputCondition unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100591{
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100592 channel_read_fd((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100593}
Bram Moolenaarea781452019-09-04 18:53:12 +0200594# endif
Bram Moolenaar98921892016-02-23 17:14:37 +0100595# endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100596
597 static void
Bram Moolenaarbd67aac2019-09-21 23:09:04 +0200598channel_gui_register_one(channel_T *channel, ch_part_T part UNUSED)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100599{
Bram Moolenaarde279892016-03-11 22:19:44 +0100600 if (!CH_HAS_GUI)
601 return;
602
Bram Moolenaarc667da52019-11-30 20:52:27 +0100603 // gets stuck in handling events for a not connected channel
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200604 if (channel->ch_keep_open)
605 return;
606
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100607# ifdef FEAT_GUI_X11
Bram Moolenaarc667da52019-11-30 20:52:27 +0100608 // Tell notifier we are interested in being called when there is input on
609 // the editor connection socket.
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100610 if (channel->ch_part[part].ch_inputHandler == (XtInputId)NULL)
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200611 {
612 ch_log(channel, "Registering part %s with fd %d",
613 part_names[part], channel->ch_part[part].ch_fd);
614
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100615 channel->ch_part[part].ch_inputHandler = XtAppAddInput(
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100616 (XtAppContext)app_context,
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100617 channel->ch_part[part].ch_fd,
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100618 (XtPointer)(XtInputReadMask + XtInputExceptMask),
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200619 messageFromServerX11,
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100620 (XtPointer)(long)channel->ch_part[part].ch_fd);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200621 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100622# else
623# ifdef FEAT_GUI_GTK
Bram Moolenaarc667da52019-11-30 20:52:27 +0100624 // Tell gdk we are interested in being called when there is input on the
625 // editor connection socket.
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100626 if (channel->ch_part[part].ch_inputHandler == 0)
Bram Moolenaar98921892016-02-23 17:14:37 +0100627 {
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200628 ch_log(channel, "Registering part %s with fd %d",
629 part_names[part], channel->ch_part[part].ch_fd);
630# if GTK_CHECK_VERSION(3,0,0)
Bram Moolenaar98921892016-02-23 17:14:37 +0100631 GIOChannel *chnnl = g_io_channel_unix_new(
632 (gint)channel->ch_part[part].ch_fd);
633
634 channel->ch_part[part].ch_inputHandler = g_io_add_watch(
635 chnnl,
636 G_IO_IN|G_IO_HUP|G_IO_ERR|G_IO_PRI,
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200637 messageFromServerGtk3,
Bram Moolenaar98921892016-02-23 17:14:37 +0100638 GINT_TO_POINTER(channel->ch_part[part].ch_fd));
639
640 g_io_channel_unref(chnnl);
Bram Moolenaar98921892016-02-23 17:14:37 +0100641# else
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100642 channel->ch_part[part].ch_inputHandler = gdk_input_add(
643 (gint)channel->ch_part[part].ch_fd,
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100644 (GdkInputCondition)
645 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200646 messageFromServerGtk2,
Bram Moolenaarfffd5562016-02-20 18:44:39 +0100647 (gpointer)(long)channel->ch_part[part].ch_fd);
Bram Moolenaar98921892016-02-23 17:14:37 +0100648# endif
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200649 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100650# endif
651# endif
652}
653
Bram Moolenaarde279892016-03-11 22:19:44 +0100654 static void
Bram Moolenaar77073442016-02-13 23:23:53 +0100655channel_gui_register(channel_T *channel)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100656{
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100657 if (channel->CH_SOCK_FD != INVALID_FD)
658 channel_gui_register_one(channel, PART_SOCK);
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200659 if (channel->CH_OUT_FD != INVALID_FD
660 && channel->CH_OUT_FD != channel->CH_SOCK_FD)
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100661 channel_gui_register_one(channel, PART_OUT);
Bram Moolenaar13ebb032017-08-26 22:02:51 +0200662 if (channel->CH_ERR_FD != INVALID_FD
663 && channel->CH_ERR_FD != channel->CH_SOCK_FD
664 && channel->CH_ERR_FD != channel->CH_OUT_FD)
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100665 channel_gui_register_one(channel, PART_ERR);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100666}
667
668/*
669 * Register any of our file descriptors with the GUI event handling system.
670 * Called when the GUI has started.
671 */
672 void
673channel_gui_register_all(void)
674{
Bram Moolenaar77073442016-02-13 23:23:53 +0100675 channel_T *channel;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100676
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200677 FOR_ALL_CHANNELS(channel)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100678 channel_gui_register(channel);
679}
680
681 static void
Bram Moolenaarbd67aac2019-09-21 23:09:04 +0200682channel_gui_unregister_one(channel_T *channel UNUSED, ch_part_T part UNUSED)
Bram Moolenaarde279892016-03-11 22:19:44 +0100683{
684# ifdef FEAT_GUI_X11
685 if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL)
686 {
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200687 ch_log(channel, "Unregistering part %s", part_names[part]);
Bram Moolenaarde279892016-03-11 22:19:44 +0100688 XtRemoveInput(channel->ch_part[part].ch_inputHandler);
689 channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
690 }
691# else
692# ifdef FEAT_GUI_GTK
693 if (channel->ch_part[part].ch_inputHandler != 0)
694 {
Bram Moolenaarb0b98d52018-05-05 21:01:00 +0200695 ch_log(channel, "Unregistering part %s", part_names[part]);
Bram Moolenaarde279892016-03-11 22:19:44 +0100696# if GTK_CHECK_VERSION(3,0,0)
697 g_source_remove(channel->ch_part[part].ch_inputHandler);
698# else
699 gdk_input_remove(channel->ch_part[part].ch_inputHandler);
700# endif
701 channel->ch_part[part].ch_inputHandler = 0;
702 }
703# endif
704# endif
705}
706
707 static void
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100708channel_gui_unregister(channel_T *channel)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +0100709{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +0200710 ch_part_T part;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +0100711
Bram Moolenaar42d38a22016-02-20 18:18:59 +0100712 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaarde279892016-03-11 22:19:44 +0100713 channel_gui_unregister_one(channel, part);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100714}
715
Bram Moolenaarea781452019-09-04 18:53:12 +0200716#endif // FEAT_GUI
Bram Moolenaard04a0202016-01-26 23:30:18 +0100717
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100718static char *e_cannot_connect = N_("E902: Cannot connect to port");
719
Bram Moolenaard04a0202016-01-26 23:30:18 +0100720/*
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200721 * For Unix we need to call connect() again after connect() failed.
722 * On Win32 one time is sufficient.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100723 */
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200724 static int
725channel_connect(
726 channel_T *channel,
727 const struct sockaddr *server_addr,
728 int server_addrlen,
729 int *waittime)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100730{
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200731 int sd = -1;
Bram Moolenaar4f974752019-02-17 17:44:42 +0100732#ifdef MSWIN
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200733 u_long val = 1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100734#endif
735
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100736 while (TRUE)
737 {
Bram Moolenaar562ca712016-03-09 21:50:05 +0100738 long elapsed_msec = 0;
739 int waitnow;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200740 int ret;
Bram Moolenaar045a2842016-03-08 22:33:07 +0100741
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100742 if (sd >= 0)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100743 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200744 sd = socket(server_addr->sa_family, SOCK_STREAM, 0);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100745 if (sd == -1)
746 {
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200747 ch_error(channel, "in socket() in channel_connect().");
748 PERROR(_("E898: socket() in channel_connect()"));
749 return -1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100750 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100751
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200752 if (*waittime >= 0)
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100753 {
Bram Moolenaarc667da52019-11-30 20:52:27 +0100754 // Make connect() non-blocking.
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100755 if (
Bram Moolenaar4f974752019-02-17 17:44:42 +0100756#ifdef MSWIN
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100757 ioctlsocket(sd, FIONBIO, &val) < 0
758#else
759 fcntl(sd, F_SETFL, O_NONBLOCK) < 0
760#endif
761 )
762 {
763 SOCK_ERRNO;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200764 ch_error(channel,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200765 "channel_connect: Connect failed with errno %d", errno);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100766 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200767 return -1;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100768 }
769 }
770
Bram Moolenaarc667da52019-11-30 20:52:27 +0100771 // Try connecting to the server.
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200772 ch_log(channel, "Connecting...");
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100773
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200774 ret = connect(sd, server_addr, server_addrlen);
Bram Moolenaar045a2842016-03-08 22:33:07 +0100775 if (ret == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100776 // The connection could be established.
Bram Moolenaar045a2842016-03-08 22:33:07 +0100777 break;
778
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100779 SOCK_ERRNO;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200780 if (*waittime < 0 || (errno != EWOULDBLOCK
Bram Moolenaar045a2842016-03-08 22:33:07 +0100781 && errno != ECONNREFUSED
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100782#ifdef EINPROGRESS
Bram Moolenaar045a2842016-03-08 22:33:07 +0100783 && errno != EINPROGRESS
Bram Moolenaar6463ca22016-02-13 17:04:46 +0100784#endif
Bram Moolenaar045a2842016-03-08 22:33:07 +0100785 ))
786 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200787 ch_error(channel,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200788 "channel_connect: Connect failed with errno %d", errno);
Bram Moolenaar045a2842016-03-08 22:33:07 +0100789 PERROR(_(e_cannot_connect));
790 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200791 return -1;
792 }
793 else if (errno == ECONNREFUSED)
794 {
795 ch_error(channel, "channel_connect: Connection refused");
796 sock_close(sd);
797 return -1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100798 }
Bram Moolenaard04a0202016-01-26 23:30:18 +0100799
Bram Moolenaarc667da52019-11-30 20:52:27 +0100800 // Limit the waittime to 50 msec. If it doesn't work within this
801 // time we close the socket and try creating it again.
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200802 waitnow = *waittime > 50 ? 50 : *waittime;
Bram Moolenaar40e8cb22016-03-10 21:10:58 +0100803
Bram Moolenaarc667da52019-11-30 20:52:27 +0100804 // If connect() didn't finish then try using select() to wait for the
805 // connection to be made. For Win32 always use select() to wait.
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100806 {
807 struct timeval tv;
Bram Moolenaard42119f2016-02-28 20:51:49 +0100808 fd_set rfds;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100809 fd_set wfds;
Bram Moolenaar4f974752019-02-17 17:44:42 +0100810#ifndef MSWIN
Bram Moolenaard42119f2016-02-28 20:51:49 +0100811 int so_error = 0;
812 socklen_t so_error_len = sizeof(so_error);
Bram Moolenaar045a2842016-03-08 22:33:07 +0100813 struct timeval start_tv;
814 struct timeval end_tv;
Bram Moolenaare081e212016-02-28 22:33:46 +0100815#endif
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100816 FD_ZERO(&rfds);
817 FD_SET(sd, &rfds);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100818 FD_ZERO(&wfds);
819 FD_SET(sd, &wfds);
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100820
Bram Moolenaar562ca712016-03-09 21:50:05 +0100821 tv.tv_sec = waitnow / 1000;
822 tv.tv_usec = (waitnow % 1000) * 1000;
Bram Moolenaar4f974752019-02-17 17:44:42 +0100823#ifndef MSWIN
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100824 gettimeofday(&start_tv, NULL);
825#endif
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200826 ch_log(channel,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200827 "Waiting for connection (waiting %d msec)...", waitnow);
Bram Moolenaare74e8e72016-02-16 22:01:30 +0100828
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200829 ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100830 if (ret < 0)
831 {
832 SOCK_ERRNO;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200833 ch_error(channel,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200834 "channel_connect: Connect failed with errno %d", errno);
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100835 PERROR(_(e_cannot_connect));
836 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200837 return -1;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100838 }
Bram Moolenaard42119f2016-02-28 20:51:49 +0100839
Bram Moolenaar4f974752019-02-17 17:44:42 +0100840#ifdef MSWIN
Bram Moolenaarc667da52019-11-30 20:52:27 +0100841 // On Win32: select() is expected to work and wait for up to
842 // "waitnow" msec for the socket to be open.
Bram Moolenaar045a2842016-03-08 22:33:07 +0100843 if (FD_ISSET(sd, &wfds))
844 break;
Bram Moolenaar562ca712016-03-09 21:50:05 +0100845 elapsed_msec = waitnow;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200846 if (*waittime > 1 && elapsed_msec < *waittime)
Bram Moolenaar562ca712016-03-09 21:50:05 +0100847 {
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200848 *waittime -= elapsed_msec;
Bram Moolenaar562ca712016-03-09 21:50:05 +0100849 continue;
850 }
Bram Moolenaare081e212016-02-28 22:33:46 +0100851#else
Bram Moolenaarc667da52019-11-30 20:52:27 +0100852 // On Linux-like systems: See socket(7) for the behavior
853 // After putting the socket in non-blocking mode, connect() will
854 // return EINPROGRESS, select() will not wait (as if writing is
855 // possible), need to use getsockopt() to check if the socket is
856 // actually able to connect.
857 // We detect a failure to connect when either read and write fds
858 // are set. Use getsockopt() to find out what kind of failure.
Bram Moolenaar42bc6dd2016-03-02 20:48:47 +0100859 if (FD_ISSET(sd, &rfds) || FD_ISSET(sd, &wfds))
Bram Moolenaard42119f2016-02-28 20:51:49 +0100860 {
861 ret = getsockopt(sd,
Bram Moolenaar045a2842016-03-08 22:33:07 +0100862 SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
Bram Moolenaard42119f2016-02-28 20:51:49 +0100863 if (ret < 0 || (so_error != 0
864 && so_error != EWOULDBLOCK
865 && so_error != ECONNREFUSED
Bram Moolenaare081e212016-02-28 22:33:46 +0100866# ifdef EINPROGRESS
Bram Moolenaard42119f2016-02-28 20:51:49 +0100867 && so_error != EINPROGRESS
Bram Moolenaare081e212016-02-28 22:33:46 +0100868# endif
Bram Moolenaard42119f2016-02-28 20:51:49 +0100869 ))
870 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +0200871 ch_error(channel,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200872 "channel_connect: Connect failed with errno %d",
Bram Moolenaard42119f2016-02-28 20:51:49 +0100873 so_error);
874 PERROR(_(e_cannot_connect));
875 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200876 return -1;
877 }
878 else if (errno == ECONNREFUSED)
879 {
880 ch_error(channel, "channel_connect: Connection refused");
881 sock_close(sd);
882 return -1;
Bram Moolenaard42119f2016-02-28 20:51:49 +0100883 }
884 }
885
Bram Moolenaar045a2842016-03-08 22:33:07 +0100886 if (FD_ISSET(sd, &wfds) && so_error == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100887 // Did not detect an error, connection is established.
Bram Moolenaar045a2842016-03-08 22:33:07 +0100888 break;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100889
Bram Moolenaar045a2842016-03-08 22:33:07 +0100890 gettimeofday(&end_tv, NULL);
891 elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200892 + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100893#endif
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100894 }
Bram Moolenaar045a2842016-03-08 22:33:07 +0100895
Bram Moolenaar4f974752019-02-17 17:44:42 +0100896#ifndef MSWIN
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200897 if (*waittime > 1 && elapsed_msec < *waittime)
Bram Moolenaar045a2842016-03-08 22:33:07 +0100898 {
Bram Moolenaarc667da52019-11-30 20:52:27 +0100899 // The port isn't ready but we also didn't get an error.
900 // This happens when the server didn't open the socket
901 // yet. Select() may return early, wait until the remaining
902 // "waitnow" and try again.
Bram Moolenaar562ca712016-03-09 21:50:05 +0100903 waitnow -= elapsed_msec;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200904 *waittime -= elapsed_msec;
Bram Moolenaar562ca712016-03-09 21:50:05 +0100905 if (waitnow > 0)
906 {
907 mch_delay((long)waitnow, TRUE);
908 ui_breakcheck();
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200909 *waittime -= waitnow;
Bram Moolenaar562ca712016-03-09 21:50:05 +0100910 }
Bram Moolenaar045a2842016-03-08 22:33:07 +0100911 if (!got_int)
912 {
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200913 if (*waittime <= 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100914 // give it one more try
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200915 *waittime = 1;
Bram Moolenaar045a2842016-03-08 22:33:07 +0100916 continue;
917 }
Bram Moolenaarc667da52019-11-30 20:52:27 +0100918 // we were interrupted, behave as if timed out
Bram Moolenaar045a2842016-03-08 22:33:07 +0100919 }
920#endif
921
Bram Moolenaarc667da52019-11-30 20:52:27 +0100922 // We timed out.
Bram Moolenaar045a2842016-03-08 22:33:07 +0100923 ch_error(channel, "Connection timed out");
924 sock_close(sd);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200925 return -1;
Bram Moolenaar7a84dbe2016-02-07 21:29:00 +0100926 }
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100927
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200928 if (*waittime >= 0)
Bram Moolenaar7a84dbe2016-02-07 21:29:00 +0100929 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100930#ifdef MSWIN
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100931 val = 0;
932 ioctlsocket(sd, FIONBIO, &val);
933#else
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +0100934 (void)fcntl(sd, F_SETFL, 0);
Bram Moolenaar4d919d72016-02-05 22:36:41 +0100935#endif
936 }
937
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200938 return sd;
939}
940
941/*
942 * Open a socket channel to "hostname":"port".
943 * "waittime" is the time in msec to wait for the connection.
944 * When negative wait forever.
945 * Returns the channel for success.
946 * Returns NULL for failure.
947 */
948 channel_T *
949channel_open(
950 const char *hostname,
951 int port,
952 int waittime,
953 void (*nb_close_cb)(void))
954{
955 int sd = -1;
956 channel_T *channel = NULL;
957#ifdef FEAT_IPV6
Bram Moolenaara38b2b72020-05-03 17:03:29 +0200958 int err;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200959 struct addrinfo hints;
960 struct addrinfo *res = NULL;
961 struct addrinfo *addr = NULL;
962#else
963 struct sockaddr_in server;
964 struct hostent *host = NULL;
965#endif
966
967#ifdef MSWIN
968 channel_init_winsock();
969#endif
970
971 channel = add_channel();
972 if (channel == NULL)
973 {
974 ch_error(NULL, "Cannot allocate channel.");
975 return NULL;
976 }
977
978 // Get the server internet address and put into addr structure fill in the
979 // socket address structure and connect to server.
980#ifdef FEAT_IPV6
Bram Moolenaara80faa82020-04-12 19:37:17 +0200981 CLEAR_FIELD(hints);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200982 hints.ai_family = AF_UNSPEC;
983 hints.ai_socktype = SOCK_STREAM;
984# ifdef AI_ADDRCONFIG
985 hints.ai_flags = AI_ADDRCONFIG;
986# endif
987 // Set port number manually in order to prevent name resolution services
988 // from being invoked in the environment where AI_NUMERICSERV is not
989 // defined.
Bram Moolenaara38b2b72020-05-03 17:03:29 +0200990 if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0)
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200991 {
992 ch_error(channel, "in getaddrinfo() in channel_open()");
Bram Moolenaara38b2b72020-05-03 17:03:29 +0200993 semsg(_("E901: getaddrinfo() in channel_open(): %s"),
994 gai_strerror(err));
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200995 channel_free(channel);
996 return NULL;
997 }
998
999 for (addr = res; addr != NULL; addr = addr->ai_next)
1000 {
Bram Moolenaarb6fb0512020-04-18 18:24:18 +02001001 const char *dst = hostname;
Bram Moolenaarb6fb0512020-04-18 18:24:18 +02001002# ifdef HAVE_INET_NTOP
Bram Moolenaarb60db8b2020-05-29 21:38:42 +02001003 const void *src = NULL;
Bram Moolenaarb6fb0512020-04-18 18:24:18 +02001004 char buf[NUMBUFLEN];
Bram Moolenaar208534d2020-05-30 13:07:39 +02001005# endif
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001006
1007 if (addr->ai_family == AF_INET6)
1008 {
1009 struct sockaddr_in6 *sai = (struct sockaddr_in6 *)addr->ai_addr;
1010
1011 sai->sin6_port = htons(port);
Bram Moolenaar208534d2020-05-30 13:07:39 +02001012# ifdef HAVE_INET_NTOP
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001013 src = &sai->sin6_addr;
Bram Moolenaar208534d2020-05-30 13:07:39 +02001014# endif
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001015 }
1016 else if (addr->ai_family == AF_INET)
1017 {
1018 struct sockaddr_in *sai = (struct sockaddr_in *)addr->ai_addr;
1019
1020 sai->sin_port = htons(port);
Bram Moolenaar208534d2020-05-30 13:07:39 +02001021# ifdef HAVE_INET_NTOP
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001022 src = &sai->sin_addr;
Bram Moolenaar208534d2020-05-30 13:07:39 +02001023#endif
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001024 }
Bram Moolenaar208534d2020-05-30 13:07:39 +02001025# ifdef HAVE_INET_NTOP
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001026 if (src != NULL)
1027 {
1028 dst = inet_ntop(addr->ai_family, src, buf, sizeof(buf));
Bram Moolenaarb6fb0512020-04-18 18:24:18 +02001029 if (dst == NULL)
1030 dst = hostname;
1031 else if (STRCMP(hostname, dst) != 0)
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001032 ch_log(channel, "Resolved %s to %s", hostname, dst);
1033 }
Bram Moolenaarb6fb0512020-04-18 18:24:18 +02001034# endif
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001035
1036 ch_log(channel, "Trying to connect to %s port %d", dst, port);
1037
1038 // On Mac and Solaris a zero timeout almost never works. At least wait
1039 // one millisecond. Let's do it for all systems, because we don't know
1040 // why this is needed.
1041 if (waittime == 0)
1042 waittime = 1;
1043
Bram Moolenaarea554ca2020-05-07 17:46:59 +02001044 sd = channel_connect(channel, addr->ai_addr, (int)addr->ai_addrlen,
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001045 &waittime);
1046 if (sd >= 0)
1047 break;
1048 }
1049
1050 freeaddrinfo(res);
1051#else
Bram Moolenaara80faa82020-04-12 19:37:17 +02001052 CLEAR_FIELD(server);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001053 server.sin_family = AF_INET;
1054 server.sin_port = htons(port);
1055 if ((host = gethostbyname(hostname)) == NULL)
1056 {
1057 ch_error(channel, "in gethostbyname() in channel_open()");
1058 PERROR(_("E901: gethostbyname() in channel_open()"));
1059 channel_free(channel);
1060 return NULL;
1061 }
1062 {
1063 char *p;
1064
1065 // When using host->h_addr_list[0] directly ubsan warns for it to not
1066 // be aligned. First copy the pointer to avoid that.
1067 memcpy(&p, &host->h_addr_list[0], sizeof(p));
1068 memcpy((char *)&server.sin_addr, p, host->h_length);
1069 }
1070
1071 ch_log(channel, "Trying to connect to %s port %d", hostname, port);
1072
1073 // On Mac and Solaris a zero timeout almost never works. At least wait one
1074 // millisecond. Let's do it for all systems, because we don't know why
1075 // this is needed.
1076 if (waittime == 0)
1077 waittime = 1;
1078
1079 sd = channel_connect(channel, (struct sockaddr *)&server, sizeof(server),
1080 &waittime);
1081#endif
1082
1083 if (sd < 0)
1084 {
1085 channel_free(channel);
1086 return NULL;
1087 }
1088
1089 ch_log(channel, "Connection made");
1090
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001091 channel->CH_SOCK_FD = (sock_T)sd;
Bram Moolenaar4e221c92016-02-23 13:20:22 +01001092 channel->ch_nb_close_cb = nb_close_cb;
Bram Moolenaar03602ec2016-03-20 20:57:45 +01001093 channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001094 channel->ch_port = port;
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001095 channel->ch_to_be_closed |= (1U << PART_SOCK);
Bram Moolenaard04a0202016-01-26 23:30:18 +01001096
1097#ifdef FEAT_GUI
Bram Moolenaarde279892016-03-11 22:19:44 +01001098 channel_gui_register_one(channel, PART_SOCK);
Bram Moolenaard04a0202016-01-26 23:30:18 +01001099#endif
1100
Bram Moolenaar77073442016-02-13 23:23:53 +01001101 return channel;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001102}
1103
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001104/*
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001105 * Copy callback from "src" to "dest", incrementing the refcounts.
1106 */
1107 static void
1108copy_callback(callback_T *dest, callback_T *src)
1109{
1110 dest->cb_partial = src->cb_partial;
1111 if (dest->cb_partial != NULL)
1112 {
1113 dest->cb_name = src->cb_name;
1114 dest->cb_free_name = FALSE;
1115 ++dest->cb_partial->pt_refcount;
1116 }
1117 else
1118 {
1119 dest->cb_name = vim_strsave(src->cb_name);
1120 dest->cb_free_name = TRUE;
1121 func_ref(src->cb_name);
1122 }
1123}
1124
1125 static void
1126free_set_callback(callback_T *cbp, callback_T *callback)
1127{
1128 free_callback(cbp);
1129
1130 if (callback->cb_name != NULL && *callback->cb_name != NUL)
1131 copy_callback(cbp, callback);
1132 else
1133 cbp->cb_name = NULL;
1134}
1135
1136/*
1137 * Prepare buffer "buf" for writing channel output to.
1138 */
1139 static void
1140prepare_buffer(buf_T *buf)
1141{
1142 buf_T *save_curbuf = curbuf;
1143
1144 buf_copy_options(buf, BCO_ENTER);
1145 curbuf = buf;
1146#ifdef FEAT_QUICKFIX
1147 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
1148 set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
1149#endif
1150 if (curbuf->b_ml.ml_mfp == NULL)
1151 ml_open(curbuf);
1152 curbuf = save_curbuf;
1153}
1154
1155/*
1156 * Find a buffer matching "name" or create a new one.
1157 * Returns NULL if there is something very wrong (error already reported).
1158 */
1159 static buf_T *
Bram Moolenaar261f3462019-09-07 15:45:32 +02001160channel_find_buffer(char_u *name, int err, int msg)
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001161{
1162 buf_T *buf = NULL;
1163 buf_T *save_curbuf = curbuf;
1164
1165 if (name != NULL && *name != NUL)
1166 {
1167 buf = buflist_findname(name);
1168 if (buf == NULL)
1169 buf = buflist_findname_exp(name);
1170 }
1171 if (buf == NULL)
1172 {
1173 buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
1174 NULL, (linenr_T)0, BLN_LISTED | BLN_NEW);
1175 if (buf == NULL)
1176 return NULL;
1177 prepare_buffer(buf);
1178
1179 curbuf = buf;
1180 if (msg)
1181 ml_replace(1, (char_u *)(err ? "Reading from channel error..."
1182 : "Reading from channel output..."), TRUE);
1183 changed_bytes(1, 0);
1184 curbuf = save_curbuf;
1185 }
1186
1187 return buf;
1188}
1189
1190/*
1191 * Set various properties from an "opt" argument.
1192 */
1193 static void
1194channel_set_options(channel_T *channel, jobopt_T *opt)
1195{
1196 ch_part_T part;
1197
1198 if (opt->jo_set & JO_MODE)
1199 for (part = PART_SOCK; part < PART_COUNT; ++part)
1200 channel->ch_part[part].ch_mode = opt->jo_mode;
1201 if (opt->jo_set & JO_IN_MODE)
1202 channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode;
1203 if (opt->jo_set & JO_OUT_MODE)
1204 channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode;
1205 if (opt->jo_set & JO_ERR_MODE)
1206 channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode;
1207 channel->ch_nonblock = opt->jo_noblock;
1208
1209 if (opt->jo_set & JO_TIMEOUT)
1210 for (part = PART_SOCK; part < PART_COUNT; ++part)
1211 channel->ch_part[part].ch_timeout = opt->jo_timeout;
1212 if (opt->jo_set & JO_OUT_TIMEOUT)
1213 channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout;
1214 if (opt->jo_set & JO_ERR_TIMEOUT)
1215 channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout;
1216 if (opt->jo_set & JO_BLOCK_WRITE)
1217 channel->ch_part[PART_IN].ch_block_write = 1;
1218
1219 if (opt->jo_set & JO_CALLBACK)
1220 free_set_callback(&channel->ch_callback, &opt->jo_callback);
1221 if (opt->jo_set & JO_OUT_CALLBACK)
1222 free_set_callback(&channel->ch_part[PART_OUT].ch_callback,
1223 &opt->jo_out_cb);
1224 if (opt->jo_set & JO_ERR_CALLBACK)
1225 free_set_callback(&channel->ch_part[PART_ERR].ch_callback,
1226 &opt->jo_err_cb);
1227 if (opt->jo_set & JO_CLOSE_CALLBACK)
1228 free_set_callback(&channel->ch_close_cb, &opt->jo_close_cb);
1229 channel->ch_drop_never = opt->jo_drop_never;
1230
1231 if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
1232 {
1233 buf_T *buf;
1234
Bram Moolenaarc667da52019-11-30 20:52:27 +01001235 // writing output to a buffer. Default mode is NL.
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001236 if (!(opt->jo_set & JO_OUT_MODE))
1237 channel->ch_part[PART_OUT].ch_mode = MODE_NL;
1238 if (opt->jo_set & JO_OUT_BUF)
1239 {
1240 buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
1241 if (buf == NULL)
1242 semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
1243 }
1244 else
1245 {
1246 int msg = TRUE;
1247
1248 if (opt->jo_set2 & JO2_OUT_MSG)
1249 msg = opt->jo_message[PART_OUT];
Bram Moolenaar261f3462019-09-07 15:45:32 +02001250 buf = channel_find_buffer(opt->jo_io_name[PART_OUT], FALSE, msg);
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001251 }
1252 if (buf != NULL)
1253 {
1254 if (opt->jo_set & JO_OUT_MODIFIABLE)
1255 channel->ch_part[PART_OUT].ch_nomodifiable =
1256 !opt->jo_modifiable[PART_OUT];
1257
1258 if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable)
1259 {
1260 emsg(_(e_modifiable));
1261 }
1262 else
1263 {
1264 ch_log(channel, "writing out to buffer '%s'",
1265 (char *)buf->b_ffname);
1266 set_bufref(&channel->ch_part[PART_OUT].ch_bufref, buf);
1267 // if the buffer was deleted or unloaded resurrect it
1268 if (buf->b_ml.ml_mfp == NULL)
1269 prepare_buffer(buf);
1270 }
1271 }
1272 }
1273
1274 if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
1275 || (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
1276 && opt->jo_io[PART_OUT] == JIO_BUFFER)))
1277 {
1278 buf_T *buf;
1279
Bram Moolenaarc667da52019-11-30 20:52:27 +01001280 // writing err to a buffer. Default mode is NL.
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001281 if (!(opt->jo_set & JO_ERR_MODE))
1282 channel->ch_part[PART_ERR].ch_mode = MODE_NL;
1283 if (opt->jo_io[PART_ERR] == JIO_OUT)
1284 buf = channel->ch_part[PART_OUT].ch_bufref.br_buf;
1285 else if (opt->jo_set & JO_ERR_BUF)
1286 {
1287 buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
1288 if (buf == NULL)
1289 semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
1290 }
1291 else
1292 {
1293 int msg = TRUE;
1294
1295 if (opt->jo_set2 & JO2_ERR_MSG)
1296 msg = opt->jo_message[PART_ERR];
Bram Moolenaar261f3462019-09-07 15:45:32 +02001297 buf = channel_find_buffer(opt->jo_io_name[PART_ERR], TRUE, msg);
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02001298 }
1299 if (buf != NULL)
1300 {
1301 if (opt->jo_set & JO_ERR_MODIFIABLE)
1302 channel->ch_part[PART_ERR].ch_nomodifiable =
1303 !opt->jo_modifiable[PART_ERR];
1304 if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable)
1305 {
1306 emsg(_(e_modifiable));
1307 }
1308 else
1309 {
1310 ch_log(channel, "writing err to buffer '%s'",
1311 (char *)buf->b_ffname);
1312 set_bufref(&channel->ch_part[PART_ERR].ch_bufref, buf);
1313 // if the buffer was deleted or unloaded resurrect it
1314 if (buf->b_ml.ml_mfp == NULL)
1315 prepare_buffer(buf);
1316 }
1317 }
1318 }
1319
1320 channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
1321 channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR];
1322 channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN];
1323}
1324
1325/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001326 * Implements ch_open().
1327 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001328 static channel_T *
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001329channel_open_func(typval_T *argvars)
1330{
1331 char_u *address;
1332 char_u *p;
1333 char *rest;
1334 int port;
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001335 int is_ipv6 = FALSE;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001336 jobopt_T opt;
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02001337 channel_T *channel = NULL;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001338
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001339 address = tv_get_string(&argvars[0]);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001340 if (argvars[1].v_type != VAR_UNKNOWN
1341 && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
1342 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001343 emsg(_(e_invarg));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001344 return NULL;
1345 }
1346
Bram Moolenaarc667da52019-11-30 20:52:27 +01001347 // parse address
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001348 if (*address == '[')
1349 {
1350 // ipv6 address
1351 is_ipv6 = TRUE;
1352 p = vim_strchr(address + 1, ']');
1353 if (p == NULL || *++p != ':')
1354 {
1355 semsg(_(e_invarg2), address);
1356 return NULL;
1357 }
1358 }
1359 else
1360 {
1361 p = vim_strchr(address, ':');
1362 if (p == NULL)
1363 {
1364 semsg(_(e_invarg2), address);
1365 return NULL;
1366 }
1367 }
1368 port = strtol((char *)(p + 1), &rest, 10);
1369 if (*address == NUL || port <= 0 || port >= 65536 || *rest != NUL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001370 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001371 semsg(_(e_invarg2), address);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001372 return NULL;
1373 }
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001374 if (is_ipv6)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001375 {
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001376 // strip '[' and ']'
1377 ++address;
1378 *(p - 1) = NUL;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001379 }
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02001380 else
1381 *p = NUL;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001382
Bram Moolenaarc667da52019-11-30 20:52:27 +01001383 // parse options
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001384 clear_job_options(&opt);
1385 opt.jo_mode = MODE_JSON;
1386 opt.jo_timeout = 2000;
1387 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02001388 JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02001389 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001390 if (opt.jo_timeout < 0)
1391 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001392 emsg(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02001393 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001394 }
1395
1396 channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
1397 if (channel != NULL)
1398 {
1399 opt.jo_set = JO_ALL;
1400 channel_set_options(channel, &opt);
1401 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02001402theend:
1403 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01001404 return channel;
1405}
1406
Bram Moolenaarde279892016-03-11 22:19:44 +01001407 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001408ch_close_part(channel_T *channel, ch_part_T part)
Bram Moolenaarde279892016-03-11 22:19:44 +01001409{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001410 sock_T *fd = &channel->ch_part[part].ch_fd;
1411
Bram Moolenaarde279892016-03-11 22:19:44 +01001412 if (*fd != INVALID_FD)
1413 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001414 if (part == PART_SOCK)
1415 sock_close(*fd);
1416 else
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02001417 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001418 // When using a pty the same FD is set on multiple parts, only
1419 // close it when the last reference is closed.
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02001420 if ((part == PART_IN || channel->CH_IN_FD != *fd)
1421 && (part == PART_OUT || channel->CH_OUT_FD != *fd)
1422 && (part == PART_ERR || channel->CH_ERR_FD != *fd))
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02001423 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01001424#ifdef MSWIN
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02001425 if (channel->ch_named_pipe)
1426 DisconnectNamedPipe((HANDLE)fd);
1427#endif
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02001428 fd_close(*fd);
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02001429 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02001430 }
Bram Moolenaarde279892016-03-11 22:19:44 +01001431 *fd = INVALID_FD;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001432
Bram Moolenaarc667da52019-11-30 20:52:27 +01001433 // channel is closed, may want to end the job if it was the last
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001434 channel->ch_to_be_closed &= ~(1U << part);
Bram Moolenaarde279892016-03-11 22:19:44 +01001435 }
1436}
1437
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001438 void
Bram Moolenaard8070362016-02-15 21:56:54 +01001439channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001440{
Bram Moolenaarde279892016-03-11 22:19:44 +01001441 if (in != INVALID_FD)
1442 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001443 ch_close_part(channel, PART_IN);
Bram Moolenaarde279892016-03-11 22:19:44 +01001444 channel->CH_IN_FD = in;
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001445# if defined(UNIX)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001446 // Do not end the job when all output channels are closed, wait until
1447 // the job ended.
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01001448 if (mch_isatty(in))
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001449 channel->ch_to_be_closed |= (1U << PART_IN);
1450# endif
Bram Moolenaarde279892016-03-11 22:19:44 +01001451 }
1452 if (out != INVALID_FD)
1453 {
1454# if defined(FEAT_GUI)
1455 channel_gui_unregister_one(channel, PART_OUT);
1456# endif
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001457 ch_close_part(channel, PART_OUT);
Bram Moolenaarde279892016-03-11 22:19:44 +01001458 channel->CH_OUT_FD = out;
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001459 channel->ch_to_be_closed |= (1U << PART_OUT);
Bram Moolenaarde279892016-03-11 22:19:44 +01001460# if defined(FEAT_GUI)
1461 channel_gui_register_one(channel, PART_OUT);
1462# endif
1463 }
1464 if (err != INVALID_FD)
1465 {
1466# if defined(FEAT_GUI)
1467 channel_gui_unregister_one(channel, PART_ERR);
1468# endif
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001469 ch_close_part(channel, PART_ERR);
Bram Moolenaarde279892016-03-11 22:19:44 +01001470 channel->CH_ERR_FD = err;
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02001471 channel->ch_to_be_closed |= (1U << PART_ERR);
Bram Moolenaarde279892016-03-11 22:19:44 +01001472# if defined(FEAT_GUI)
1473 channel_gui_register_one(channel, PART_ERR);
1474# endif
1475 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001476}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001477
Bram Moolenaard6051b52016-02-28 15:49:03 +01001478/*
Bram Moolenaar014069a2016-03-03 22:51:40 +01001479 * Sets the job the channel is associated with and associated options.
Bram Moolenaard6051b52016-02-28 15:49:03 +01001480 * This does not keep a refcount, when the job is freed ch_job is cleared.
1481 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001482 void
Bram Moolenaar014069a2016-03-03 22:51:40 +01001483channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01001484{
Bram Moolenaar77073442016-02-13 23:23:53 +01001485 channel->ch_job = job;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001486
1487 channel_set_options(channel, options);
1488
1489 if (job->jv_in_buf != NULL)
1490 {
1491 chanpart_T *in_part = &channel->ch_part[PART_IN];
1492
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001493 set_bufref(&in_part->ch_bufref, job->jv_in_buf);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001494 ch_log(channel, "reading from buffer '%s'",
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001495 (char *)in_part->ch_bufref.br_buf->b_ffname);
Bram Moolenaar014069a2016-03-03 22:51:40 +01001496 if (options->jo_set & JO_IN_TOP)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001497 {
1498 if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT))
1499 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001500 // Special mode: send last-but-one line when appending a line
1501 // to the buffer.
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001502 in_part->ch_bufref.br_buf->b_write_to_channel = TRUE;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001503 in_part->ch_buf_append = TRUE;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001504 in_part->ch_buf_top =
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001505 in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001506 }
1507 else
1508 in_part->ch_buf_top = options->jo_in_top;
1509 }
Bram Moolenaar014069a2016-03-03 22:51:40 +01001510 else
1511 in_part->ch_buf_top = 1;
1512 if (options->jo_set & JO_IN_BOT)
1513 in_part->ch_buf_bot = options->jo_in_bot;
1514 else
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001515 in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001516 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01001517}
1518
1519/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001520 * Set the callback for "channel"/"part" for the response with "id".
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001521 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001522 static void
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001523channel_set_req_callback(
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001524 channel_T *channel,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001525 ch_part_T part,
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02001526 callback_T *callback,
Bram Moolenaar1735bc92016-03-14 23:05:14 +01001527 int id)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001528{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001529 cbq_T *head = &channel->ch_part[part].ch_cb_head;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001530 cbq_T *item = ALLOC_ONE(cbq_T);
Bram Moolenaara07fec92016-02-05 21:04:08 +01001531
1532 if (item != NULL)
1533 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02001534 copy_callback(&item->cq_callback, callback);
Bram Moolenaar77073442016-02-13 23:23:53 +01001535 item->cq_seq_nr = id;
1536 item->cq_prev = head->cq_prev;
1537 head->cq_prev = item;
1538 item->cq_next = NULL;
1539 if (item->cq_prev == NULL)
1540 head->cq_next = item;
1541 else
1542 item->cq_prev->cq_next = item;
Bram Moolenaara07fec92016-02-05 21:04:08 +01001543 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001544}
1545
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001546 static void
1547write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
1548{
1549 char_u *line = ml_get_buf(buf, lnum, FALSE);
Bram Moolenaar367aabd2016-03-08 17:13:06 +01001550 int len = (int)STRLEN(line);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001551 char_u *p;
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001552 int i;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001553
Bram Moolenaarc667da52019-11-30 20:52:27 +01001554 // Need to make a copy to be able to append a NL.
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001555 if ((p = alloc(len + 2)) == NULL)
1556 return;
Bram Moolenaaradb78a72016-06-27 21:10:31 +02001557 memcpy((char *)p, (char *)line, len);
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001558
Bram Moolenaaref68e4f2017-09-02 16:28:36 +02001559 if (channel->ch_write_text_mode)
1560 p[len] = CAR;
1561 else
1562 {
1563 for (i = 0; i < len; ++i)
1564 if (p[i] == NL)
1565 p[i] = NUL;
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02001566
Bram Moolenaaref68e4f2017-09-02 16:28:36 +02001567 p[len] = NL;
1568 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001569 p[len + 1] = NUL;
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01001570 channel_send(channel, PART_IN, p, len + 1, "write_buf_line");
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001571 vim_free(p);
1572}
1573
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001574/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001575 * Return TRUE if "channel" can be written to.
1576 * Returns FALSE if the input is closed or the write would block.
1577 */
1578 static int
1579can_write_buf_line(channel_T *channel)
1580{
1581 chanpart_T *in_part = &channel->ch_part[PART_IN];
1582
1583 if (in_part->ch_fd == INVALID_FD)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001584 return FALSE; // pipe was closed
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001585
Bram Moolenaarc667da52019-11-30 20:52:27 +01001586 // for testing: block every other attempt to write
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001587 if (in_part->ch_block_write == 1)
1588 in_part->ch_block_write = -1;
1589 else if (in_part->ch_block_write == -1)
1590 in_part->ch_block_write = 1;
1591
Bram Moolenaarc667da52019-11-30 20:52:27 +01001592 // TODO: Win32 implementation, probably using WaitForMultipleObjects()
Bram Moolenaar4f974752019-02-17 17:44:42 +01001593#ifndef MSWIN
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001594 {
1595# if defined(HAVE_SELECT)
1596 struct timeval tval;
1597 fd_set wfds;
1598 int ret;
1599
1600 FD_ZERO(&wfds);
1601 FD_SET((int)in_part->ch_fd, &wfds);
1602 tval.tv_sec = 0;
1603 tval.tv_usec = 0;
1604 for (;;)
1605 {
1606 ret = select((int)in_part->ch_fd + 1, NULL, &wfds, NULL, &tval);
1607# ifdef EINTR
1608 SOCK_ERRNO;
1609 if (ret == -1 && errno == EINTR)
1610 continue;
1611# endif
1612 if (ret <= 0 || in_part->ch_block_write == 1)
1613 {
1614 if (ret > 0)
1615 ch_log(channel, "FAKED Input not ready for writing");
1616 else
1617 ch_log(channel, "Input not ready for writing");
1618 return FALSE;
1619 }
1620 break;
1621 }
1622# else
1623 struct pollfd fds;
1624
1625 fds.fd = in_part->ch_fd;
1626 fds.events = POLLOUT;
1627 if (poll(&fds, 1, 0) <= 0)
1628 {
1629 ch_log(channel, "Input not ready for writing");
1630 return FALSE;
1631 }
1632 if (in_part->ch_block_write == 1)
1633 {
1634 ch_log(channel, "FAKED Input not ready for writing");
1635 return FALSE;
1636 }
1637# endif
1638 }
1639#endif
1640 return TRUE;
1641}
1642
1643/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001644 * Write any buffer lines to the input channel.
Bram Moolenaar014069a2016-03-03 22:51:40 +01001645 */
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001646 static void
Bram Moolenaar014069a2016-03-03 22:51:40 +01001647channel_write_in(channel_T *channel)
1648{
1649 chanpart_T *in_part = &channel->ch_part[PART_IN];
1650 linenr_T lnum;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001651 buf_T *buf = in_part->ch_bufref.br_buf;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001652 int written = 0;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001653
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001654 if (buf == NULL || in_part->ch_buf_append)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001655 return; // no buffer or using appending
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001656 if (!bufref_valid(&in_part->ch_bufref) || buf->b_ml.ml_mfp == NULL)
Bram Moolenaar014069a2016-03-03 22:51:40 +01001657 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001658 // buffer was wiped out or unloaded
Bram Moolenaarc4da1132017-07-15 19:39:43 +02001659 ch_log(channel, "input buffer has been wiped out");
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001660 in_part->ch_bufref.br_buf = NULL;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001661 return;
1662 }
Bram Moolenaar014069a2016-03-03 22:51:40 +01001663
1664 for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot
1665 && lnum <= buf->b_ml.ml_line_count; ++lnum)
1666 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001667 if (!can_write_buf_line(channel))
1668 break;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001669 write_buf_line(buf, lnum, channel);
1670 ++written;
Bram Moolenaar014069a2016-03-03 22:51:40 +01001671 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001672
1673 if (written == 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001674 ch_log(channel, "written line %d to channel", (int)lnum - 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001675 else if (written > 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001676 ch_log(channel, "written %d lines to channel", written);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001677
Bram Moolenaar014069a2016-03-03 22:51:40 +01001678 in_part->ch_buf_top = lnum;
Bram Moolenaard8b55492016-09-01 14:35:22 +02001679 if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001680 {
Bram Moolenaardada6d22017-09-02 17:18:35 +02001681#if defined(FEAT_TERMINAL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001682 // Send CTRL-D or "eof_chars" to close stdin on MS-Windows.
Bram Moolenaar3346cc42017-09-02 14:54:21 +02001683 if (channel->ch_job != NULL)
1684 term_send_eof(channel);
1685#endif
1686
Bram Moolenaarc667da52019-11-30 20:52:27 +01001687 // Writing is done, no longer need the buffer.
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001688 in_part->ch_bufref.br_buf = NULL;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001689 ch_log(channel, "Finished writing all lines to channel");
Bram Moolenaard8b55492016-09-01 14:35:22 +02001690
Bram Moolenaarc667da52019-11-30 20:52:27 +01001691 // Close the pipe/socket, so that the other side gets EOF.
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001692 ch_close_part(channel, PART_IN);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001693 }
1694 else
Bram Moolenaar4ac2e8d2018-04-08 12:38:26 +02001695 ch_log(channel, "Still %ld more lines to write",
1696 (long)(buf->b_ml.ml_line_count - lnum + 1));
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001697}
1698
1699/*
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02001700 * Handle buffer "buf" being freed, remove it from any channels.
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001701 */
1702 void
1703channel_buffer_free(buf_T *buf)
1704{
1705 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001706 ch_part_T part;
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001707
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001708 FOR_ALL_CHANNELS(channel)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001709 for (part = PART_SOCK; part < PART_COUNT; ++part)
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001710 {
1711 chanpart_T *ch_part = &channel->ch_part[part];
1712
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001713 if (ch_part->ch_bufref.br_buf == buf)
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001714 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001715 ch_log(channel, "%s buffer has been wiped out",
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001716 part_names[part]);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001717 ch_part->ch_bufref.br_buf = NULL;
Bram Moolenaarde7eb0a2016-05-09 20:54:33 +02001718 }
Bram Moolenaare0f76d02016-05-09 20:38:53 +02001719 }
1720}
1721
1722/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001723 * Write any lines waiting to be written to "channel".
1724 */
1725 static void
1726channel_write_input(channel_T *channel)
1727{
1728 chanpart_T *in_part = &channel->ch_part[PART_IN];
1729
1730 if (in_part->ch_writeque.wq_next != NULL)
1731 channel_send(channel, PART_IN, (char_u *)"", 0, "channel_write_input");
1732 else if (in_part->ch_bufref.br_buf != NULL)
1733 {
1734 if (in_part->ch_buf_append)
1735 channel_write_new_lines(in_part->ch_bufref.br_buf);
1736 else
1737 channel_write_in(channel);
1738 }
1739}
1740
1741/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001742 * Write any lines waiting to be written to a channel.
1743 */
1744 void
Bram Moolenaarcf089462016-06-12 21:18:43 +02001745channel_write_any_lines(void)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001746{
1747 channel_T *channel;
1748
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001749 FOR_ALL_CHANNELS(channel)
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02001750 channel_write_input(channel);
Bram Moolenaar014069a2016-03-03 22:51:40 +01001751}
1752
1753/*
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001754 * Write appended lines above the last one in "buf" to the channel.
1755 */
1756 void
1757channel_write_new_lines(buf_T *buf)
1758{
1759 channel_T *channel;
1760 int found_one = FALSE;
1761
Bram Moolenaarc667da52019-11-30 20:52:27 +01001762 // There could be more than one channel for the buffer, loop over all of
1763 // them.
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001764 FOR_ALL_CHANNELS(channel)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001765 {
1766 chanpart_T *in_part = &channel->ch_part[PART_IN];
1767 linenr_T lnum;
1768 int written = 0;
1769
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001770 if (in_part->ch_bufref.br_buf == buf && in_part->ch_buf_append)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001771 {
1772 if (in_part->ch_fd == INVALID_FD)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001773 continue; // pipe was closed
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001774 found_one = TRUE;
1775 for (lnum = in_part->ch_buf_bot; lnum < buf->b_ml.ml_line_count;
1776 ++lnum)
1777 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001778 if (!can_write_buf_line(channel))
1779 break;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001780 write_buf_line(buf, lnum, channel);
1781 ++written;
1782 }
1783
1784 if (written == 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001785 ch_log(channel, "written line %d to channel", (int)lnum - 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001786 else if (written > 1)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02001787 ch_log(channel, "written %d lines to channel", written);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02001788 if (lnum < buf->b_ml.ml_line_count)
Bram Moolenaar4ac2e8d2018-04-08 12:38:26 +02001789 ch_log(channel, "Still %ld more lines to write",
1790 (long)(buf->b_ml.ml_line_count - lnum));
Bram Moolenaar99ef0622016-03-06 20:22:25 +01001791
1792 in_part->ch_buf_bot = lnum;
1793 }
1794 }
1795 if (!found_one)
1796 buf->b_write_to_channel = FALSE;
1797}
1798
1799/*
Bram Moolenaar77073442016-02-13 23:23:53 +01001800 * Invoke the "callback" on channel "channel".
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02001801 * This does not redraw but sets channel_need_redraw;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001802 */
1803 static void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02001804invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001805{
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001806 typval_T rettv;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001807
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02001808 if (safe_to_invoke_callback == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001809 iemsg("INTERNAL: Invoking callback when it is not safe");
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02001810
Bram Moolenaar77073442016-02-13 23:23:53 +01001811 argv[0].v_type = VAR_CHANNEL;
1812 argv[0].vval.v_channel = channel;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01001813
Bram Moolenaarc6538bc2019-08-03 18:17:11 +02001814 call_callback(callback, -1, &rettv, 2, argv);
Bram Moolenaaree1cffc2016-02-21 19:14:41 +01001815 clear_tv(&rettv);
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02001816 channel_need_redraw = TRUE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01001817}
1818
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01001819/*
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001820 * Return the first node from "channel"/"part" without removing it.
1821 * Returns NULL if there is nothing.
1822 */
1823 readq_T *
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001824channel_peek(channel_T *channel, ch_part_T part)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001825{
1826 readq_T *head = &channel->ch_part[part].ch_head;
1827
1828 return head->rq_next;
1829}
1830
1831/*
1832 * Return a pointer to the first NL in "node".
1833 * Skips over NUL characters.
1834 * Returns NULL if there is no NL.
1835 */
1836 char_u *
1837channel_first_nl(readq_T *node)
1838{
1839 char_u *buffer = node->rq_buffer;
1840 long_u i;
1841
1842 for (i = 0; i < node->rq_buflen; ++i)
1843 if (buffer[i] == NL)
1844 return buffer + i;
1845 return NULL;
1846}
1847
1848/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001849 * Return the first buffer from channel "channel"/"part" and remove it.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001850 * The caller must free it.
1851 * Returns NULL if there is nothing.
1852 */
1853 char_u *
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001854channel_get(channel_T *channel, ch_part_T part, int *outlen)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001855{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001856 readq_T *head = &channel->ch_part[part].ch_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01001857 readq_T *node = head->rq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001858 char_u *p;
1859
Bram Moolenaar77073442016-02-13 23:23:53 +01001860 if (node == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001861 return NULL;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001862 if (outlen != NULL)
1863 *outlen += node->rq_buflen;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001864 // dispose of the node but keep the buffer
Bram Moolenaar77073442016-02-13 23:23:53 +01001865 p = node->rq_buffer;
1866 head->rq_next = node->rq_next;
1867 if (node->rq_next == NULL)
1868 head->rq_prev = NULL;
1869 else
1870 node->rq_next->rq_prev = NULL;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001871 vim_free(node);
1872 return p;
1873}
1874
1875/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001876 * Returns the whole buffer contents concatenated for "channel"/"part".
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001877 * Replaces NUL bytes with NL.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001878 */
1879 static char_u *
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001880channel_get_all(channel_T *channel, ch_part_T part, int *outlen)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001881{
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001882 readq_T *head = &channel->ch_part[part].ch_head;
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01001883 readq_T *node;
Bram Moolenaaradb78a72016-06-27 21:10:31 +02001884 long_u len = 0;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001885 char_u *res;
1886 char_u *p;
1887
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001888 // Concatenate everything into one buffer.
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001889 for (node = head->rq_next; node != NULL; node = node->rq_next)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001890 len += node->rq_buflen;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02001891 res = alloc(len + 1);
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001892 if (res == NULL)
1893 return NULL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001894 p = res;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001895 for (node = head->rq_next; node != NULL; node = node->rq_next)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001896 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001897 mch_memmove(p, node->rq_buffer, node->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001898 p += node->rq_buflen;
1899 }
1900 *p = NUL;
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001901
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001902 // Free all buffers
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001903 do
1904 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001905 p = channel_get(channel, part, NULL);
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001906 vim_free(p);
1907 } while (p != NULL);
1908
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001909 if (outlen != NULL)
1910 {
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001911 // Returning the length, keep NUL characters.
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001912 *outlen += len;
1913 return res;
1914 }
1915
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001916 // Turn all NUL into NL, so that the result can be used as a string.
1917 p = res;
1918 while (p < res + len)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001919 {
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001920 if (*p == NUL)
1921 *p = NL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01001922#ifdef MSWIN
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01001923 else if (*p == 0x1b)
1924 {
1925 // crush the escape sequence OSC 0/1/2: ESC ]0;
1926 if (p + 3 < res + len
1927 && p[1] == ']'
1928 && (p[2] == '0' || p[2] == '1' || p[2] == '2')
1929 && p[3] == ';')
1930 {
1931 // '\a' becomes a NL
1932 while (p < res + (len - 1) && *p != '\a')
1933 ++p;
1934 // BEL is zero width characters, suppress display mistake
1935 // ConPTY (after 10.0.18317) requires advance checking
1936 if (p[-1] == NUL)
1937 p[-1] = 0x07;
1938 }
1939 }
1940#endif
1941 ++p;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001942 }
1943
Bram Moolenaaree1f7b32016-03-28 14:42:14 +02001944 return res;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001945}
1946
1947/*
Bram Moolenaarcf089462016-06-12 21:18:43 +02001948 * Consume "len" bytes from the head of "node".
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001949 * Caller must check these bytes are available.
1950 */
1951 void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001952channel_consume(channel_T *channel, ch_part_T part, int len)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001953{
1954 readq_T *head = &channel->ch_part[part].ch_head;
1955 readq_T *node = head->rq_next;
1956 char_u *buf = node->rq_buffer;
1957
1958 mch_memmove(buf, buf + len, node->rq_buflen - len);
1959 node->rq_buflen -= len;
Bram Moolenaar772153f2019-03-04 12:09:49 +01001960 node->rq_buffer[node->rq_buflen] = NUL;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001961}
1962
1963/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001964 * Collapses the first and second buffer for "channel"/"part".
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001965 * Returns FAIL if that is not possible.
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001966 * When "want_nl" is TRUE collapse more buffers until a NL is found.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001967 */
1968 int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02001969channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001970{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01001971 readq_T *head = &channel->ch_part[part].ch_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01001972 readq_T *node = head->rq_next;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001973 readq_T *last_node;
1974 readq_T *n;
1975 char_u *newbuf;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001976 char_u *p;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001977 long_u len;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001978
Bram Moolenaar77073442016-02-13 23:23:53 +01001979 if (node == NULL || node->rq_next == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001980 return FAIL;
1981
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001982 last_node = node->rq_next;
Bram Moolenaar772153f2019-03-04 12:09:49 +01001983 len = node->rq_buflen + last_node->rq_buflen;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001984 if (want_nl)
1985 while (last_node->rq_next != NULL
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001986 && channel_first_nl(last_node) == NULL)
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001987 {
1988 last_node = last_node->rq_next;
1989 len += last_node->rq_buflen;
1990 }
1991
Bram Moolenaar772153f2019-03-04 12:09:49 +01001992 p = newbuf = alloc(len + 1);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001993 if (newbuf == NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01001994 return FAIL; // out of memory
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02001995 mch_memmove(p, node->rq_buffer, node->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001996 p += node->rq_buflen;
Bram Moolenaar77073442016-02-13 23:23:53 +01001997 vim_free(node->rq_buffer);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02001998 node->rq_buffer = newbuf;
1999 for (n = node; n != last_node; )
2000 {
2001 n = n->rq_next;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002002 mch_memmove(p, n->rq_buffer, n->rq_buflen);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002003 p += n->rq_buflen;
2004 vim_free(n->rq_buffer);
2005 }
Bram Moolenaar772153f2019-03-04 12:09:49 +01002006 *p = NUL;
Bram Moolenaarbbe8d912016-06-05 16:10:57 +02002007 node->rq_buflen = (long_u)(p - newbuf);
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002008
Bram Moolenaarc667da52019-11-30 20:52:27 +01002009 // dispose of the collapsed nodes and their buffers
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002010 for (n = node->rq_next; n != last_node; )
2011 {
2012 n = n->rq_next;
2013 vim_free(n->rq_prev);
2014 }
2015 node->rq_next = last_node->rq_next;
2016 if (last_node->rq_next == NULL)
2017 head->rq_prev = node;
2018 else
2019 last_node->rq_next->rq_prev = node;
2020 vim_free(last_node);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002021 return OK;
2022}
2023
2024/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002025 * Store "buf[len]" on "channel"/"part".
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002026 * When "prepend" is TRUE put in front, otherwise append at the end.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002027 * Returns OK or FAIL.
2028 */
2029 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002030channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002031 int prepend, char *lead)
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002032{
2033 readq_T *node;
2034 readq_T *head = &channel->ch_part[part].ch_head;
2035 char_u *p;
2036 int i;
2037
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002038 node = ALLOC_ONE(readq_T);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002039 if (node == NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002040 return FAIL; // out of memory
2041 // A NUL is added at the end, because netbeans code expects that.
2042 // Otherwise a NUL may appear inside the text.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002043 node->rq_buffer = alloc(len + 1);
2044 if (node->rq_buffer == NULL)
2045 {
2046 vim_free(node);
Bram Moolenaarc667da52019-11-30 20:52:27 +01002047 return FAIL; // out of memory
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002048 }
2049
2050 if (channel->ch_part[part].ch_mode == MODE_NL)
2051 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002052 // Drop any CR before a NL.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002053 p = node->rq_buffer;
2054 for (i = 0; i < len; ++i)
2055 if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
2056 *p++ = buf[i];
2057 *p = NUL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002058 node->rq_buflen = (long_u)(p - node->rq_buffer);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002059 }
2060 else
2061 {
2062 mch_memmove(node->rq_buffer, buf, len);
2063 node->rq_buffer[len] = NUL;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002064 node->rq_buflen = (long_u)len;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002065 }
2066
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002067 if (prepend)
2068 {
Bram Moolenaarad3ec762019-04-21 00:00:13 +02002069 // prepend node to the head of the queue
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002070 node->rq_next = head->rq_next;
2071 node->rq_prev = NULL;
2072 if (head->rq_next == NULL)
2073 head->rq_prev = node;
2074 else
2075 head->rq_next->rq_prev = node;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002076 head->rq_next = node;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002077 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002078 else
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002079 {
Bram Moolenaarad3ec762019-04-21 00:00:13 +02002080 // append node to the tail of the queue
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002081 node->rq_next = NULL;
2082 node->rq_prev = head->rq_prev;
2083 if (head->rq_prev == NULL)
2084 head->rq_next = node;
2085 else
2086 head->rq_prev->rq_next = node;
2087 head->rq_prev = node;
2088 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002089
Bram Moolenaar71eeb742017-09-13 22:18:01 +02002090 if (ch_log_active() && lead != NULL)
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002091 {
Bram Moolenaar4b16ee72018-08-09 22:15:34 +02002092 ch_log_lead(lead, channel, part);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002093 fprintf(log_fd, "'");
Bram Moolenaar42335f52018-09-13 15:33:43 +02002094 vim_ignored = (int)fwrite(buf, len, 1, log_fd);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002095 fprintf(log_fd, "'\n");
2096 }
2097 return OK;
2098}
2099
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002100/*
2101 * Try to fill the buffer of "reader".
2102 * Returns FALSE when nothing was added.
2103 */
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002104 static int
2105channel_fill(js_read_T *reader)
2106{
2107 channel_T *channel = (channel_T *)reader->js_cookie;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002108 ch_part_T part = reader->js_cookie_arg;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002109 char_u *next = channel_get(channel, part, NULL);
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002110 int keeplen;
2111 int addlen;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002112 char_u *p;
2113
2114 if (next == NULL)
2115 return FALSE;
2116
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002117 keeplen = reader->js_end - reader->js_buf;
2118 if (keeplen > 0)
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002119 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002120 // Prepend unused text.
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002121 addlen = (int)STRLEN(next);
2122 p = alloc(keeplen + addlen + 1);
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002123 if (p == NULL)
2124 {
2125 vim_free(next);
2126 return FALSE;
2127 }
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002128 mch_memmove(p, reader->js_buf, keeplen);
2129 mch_memmove(p + keeplen, next, addlen + 1);
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002130 vim_free(next);
2131 next = p;
2132 }
2133
2134 vim_free(reader->js_buf);
2135 reader->js_buf = next;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002136 return TRUE;
2137}
2138
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002139/*
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002140 * Use the read buffer of "channel"/"part" and parse a JSON message that is
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002141 * complete. The messages are added to the queue.
Bram Moolenaard7ece102016-02-02 23:23:02 +01002142 * Return TRUE if there is more to read.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002143 */
Bram Moolenaard7ece102016-02-02 23:23:02 +01002144 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002145channel_parse_json(channel_T *channel, ch_part_T part)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002146{
2147 js_read_T reader;
2148 typval_T listtv;
2149 jsonq_T *item;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002150 chanpart_T *chanpart = &channel->ch_part[part];
2151 jsonq_T *head = &chanpart->ch_json_head;
2152 int status;
Bram Moolenaard7ece102016-02-02 23:23:02 +01002153 int ret;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002154
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002155 if (channel_peek(channel, part) == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002156 return FALSE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002157
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002158 reader.js_buf = channel_get(channel, part, NULL);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002159 reader.js_used = 0;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002160 reader.js_fill = channel_fill;
Bram Moolenaar77073442016-02-13 23:23:53 +01002161 reader.js_cookie = channel;
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002162 reader.js_cookie_arg = part;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002163
Bram Moolenaarc667da52019-11-30 20:52:27 +01002164 // When a message is incomplete we wait for a short while for more to
2165 // arrive. After the delay drop the input, otherwise a truncated string
2166 // or list will make us hang.
2167 // Do not generate error messages, they will be written in a channel log.
Bram Moolenaar03c60c12017-01-10 15:15:37 +01002168 ++emsg_silent;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002169 status = json_decode(&reader, &listtv,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002170 chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
Bram Moolenaar03c60c12017-01-10 15:15:37 +01002171 --emsg_silent;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002172 if (status == OK)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002173 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002174 // Only accept the response when it is a list with at least two
2175 // items.
Bram Moolenaar6076fe12016-02-05 22:49:56 +01002176 if (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002177 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002178 if (listtv.v_type != VAR_LIST)
2179 ch_error(channel, "Did not receive a list, discarding");
2180 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002181 ch_error(channel, "Expected list with two items, got %d",
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002182 listtv.vval.v_list->lv_len);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002183 clear_tv(&listtv);
Bram Moolenaard7ece102016-02-02 23:23:02 +01002184 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002185 else
2186 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002187 item = ALLOC_ONE(jsonq_T);
Bram Moolenaard7ece102016-02-02 23:23:02 +01002188 if (item == NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002189 clear_tv(&listtv);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002190 else
2191 {
Bram Moolenaar958dc692016-12-01 15:34:12 +01002192 item->jq_no_callback = FALSE;
Bram Moolenaar77073442016-02-13 23:23:53 +01002193 item->jq_value = alloc_tv();
2194 if (item->jq_value == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002195 {
2196 vim_free(item);
2197 clear_tv(&listtv);
2198 }
2199 else
2200 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002201 *item->jq_value = listtv;
2202 item->jq_prev = head->jq_prev;
2203 head->jq_prev = item;
2204 item->jq_next = NULL;
2205 if (item->jq_prev == NULL)
2206 head->jq_next = item;
2207 else
2208 item->jq_prev->jq_next = item;
Bram Moolenaard7ece102016-02-02 23:23:02 +01002209 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002210 }
2211 }
2212 }
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002213
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002214 if (status == OK)
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002215 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002216 else if (status == MAYBE)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002217 {
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002218 size_t buflen = STRLEN(reader.js_buf);
2219
2220 if (chanpart->ch_wait_len < buflen)
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002221 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002222 // First time encountering incomplete message or after receiving
2223 // more (but still incomplete): set a deadline of 100 msec.
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002224 ch_log(channel,
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002225 "Incomplete message (%d bytes) - wait 100 msec for more",
Bram Moolenaarb113c3a2017-02-28 21:26:17 +01002226 (int)buflen);
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002227 reader.js_used = 0;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002228 chanpart->ch_wait_len = buflen;
Bram Moolenaar4f974752019-02-17 17:44:42 +01002229#ifdef MSWIN
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002230 chanpart->ch_deadline = GetTickCount() + 100L;
2231#else
2232 gettimeofday(&chanpart->ch_deadline, NULL);
2233 chanpart->ch_deadline.tv_usec += 100 * 1000;
2234 if (chanpart->ch_deadline.tv_usec > 1000 * 1000)
2235 {
2236 chanpart->ch_deadline.tv_usec -= 1000 * 1000;
2237 ++chanpart->ch_deadline.tv_sec;
2238 }
2239#endif
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002240 }
2241 else
2242 {
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002243 int timeout;
Bram Moolenaar4f974752019-02-17 17:44:42 +01002244#ifdef MSWIN
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002245 timeout = GetTickCount() > chanpart->ch_deadline;
2246#else
2247 {
2248 struct timeval now_tv;
2249
2250 gettimeofday(&now_tv, NULL);
2251 timeout = now_tv.tv_sec > chanpart->ch_deadline.tv_sec
2252 || (now_tv.tv_sec == chanpart->ch_deadline.tv_sec
2253 && now_tv.tv_usec > chanpart->ch_deadline.tv_usec);
2254 }
2255#endif
2256 if (timeout)
2257 {
2258 status = FAIL;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002259 chanpart->ch_wait_len = 0;
2260 ch_log(channel, "timed out");
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002261 }
2262 else
2263 {
2264 reader.js_used = 0;
2265 ch_log(channel, "still waiting on incomplete message");
2266 }
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002267 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01002268 }
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002269
2270 if (status == FAIL)
2271 {
2272 ch_error(channel, "Decoding failed - discarding input");
2273 ret = FALSE;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01002274 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002275 }
2276 else if (reader.js_buf[reader.js_used] != NUL)
2277 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002278 // Put the unread part back into the channel.
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002279 channel_save(channel, part, reader.js_buf + reader.js_used,
Bram Moolenaar46c00a62016-03-28 14:11:42 +02002280 (int)(reader.js_end - reader.js_buf) - reader.js_used,
2281 TRUE, NULL);
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002282 ret = status == MAYBE ? FALSE: TRUE;
2283 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01002284 else
2285 ret = FALSE;
2286
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002287 vim_free(reader.js_buf);
Bram Moolenaard7ece102016-02-02 23:23:02 +01002288 return ret;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002289}
2290
2291/*
Bram Moolenaard46ae142016-02-16 13:33:52 +01002292 * Remove "node" from the queue that it is in. Does not free it.
Bram Moolenaara07fec92016-02-05 21:04:08 +01002293 */
2294 static void
Bram Moolenaar77073442016-02-13 23:23:53 +01002295remove_cb_node(cbq_T *head, cbq_T *node)
Bram Moolenaara07fec92016-02-05 21:04:08 +01002296{
Bram Moolenaar77073442016-02-13 23:23:53 +01002297 if (node->cq_prev == NULL)
2298 head->cq_next = node->cq_next;
2299 else
2300 node->cq_prev->cq_next = node->cq_next;
2301 if (node->cq_next == NULL)
2302 head->cq_prev = node->cq_prev;
2303 else
2304 node->cq_next->cq_prev = node->cq_prev;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002305}
2306
2307/*
2308 * Remove "node" from the queue that it is in and free it.
Bram Moolenaar77073442016-02-13 23:23:53 +01002309 * Caller should have freed or used node->jq_value.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002310 */
2311 static void
Bram Moolenaar77073442016-02-13 23:23:53 +01002312remove_json_node(jsonq_T *head, jsonq_T *node)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002313{
Bram Moolenaar77073442016-02-13 23:23:53 +01002314 if (node->jq_prev == NULL)
2315 head->jq_next = node->jq_next;
2316 else
2317 node->jq_prev->jq_next = node->jq_next;
2318 if (node->jq_next == NULL)
2319 head->jq_prev = node->jq_prev;
2320 else
2321 node->jq_next->jq_prev = node->jq_prev;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002322 vim_free(node);
2323}
2324
2325/*
Bram Moolenaar38ea7842019-06-09 19:51:58 +02002326 * Add "id" to the list of JSON message IDs we are waiting on.
2327 */
2328 static void
2329channel_add_block_id(chanpart_T *chanpart, int id)
2330{
2331 garray_T *gap = &chanpart->ch_block_ids;
2332
2333 if (gap->ga_growsize == 0)
2334 ga_init2(gap, (int)sizeof(int), 10);
2335 if (ga_grow(gap, 1) == OK)
2336 {
2337 ((int *)gap->ga_data)[gap->ga_len] = id;
2338 ++gap->ga_len;
2339 }
2340}
2341
2342/*
2343 * Remove "id" from the list of JSON message IDs we are waiting on.
2344 */
2345 static void
2346channel_remove_block_id(chanpart_T *chanpart, int id)
2347{
2348 garray_T *gap = &chanpart->ch_block_ids;
2349 int i;
2350
2351 for (i = 0; i < gap->ga_len; ++i)
2352 if (((int *)gap->ga_data)[i] == id)
2353 {
2354 --gap->ga_len;
2355 if (i < gap->ga_len)
2356 {
2357 int *p = ((int *)gap->ga_data) + i;
2358
2359 mch_memmove(p, p + 1, (gap->ga_len - i) * sizeof(int));
2360 }
2361 return;
2362 }
2363 siemsg("INTERNAL: channel_remove_block_id: cannot find id %d", id);
2364}
2365
2366/*
2367 * Return TRUE if "id" is in the list of JSON message IDs we are waiting on.
2368 */
2369 static int
2370channel_has_block_id(chanpart_T *chanpart, int id)
2371{
2372 garray_T *gap = &chanpart->ch_block_ids;
2373 int i;
2374
2375 for (i = 0; i < gap->ga_len; ++i)
2376 if (((int *)gap->ga_data)[i] == id)
2377 return TRUE;
2378 return FALSE;
2379}
2380
2381/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002382 * Get a message from the JSON queue for channel "channel".
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002383 * When "id" is positive it must match the first number in the list.
Bram Moolenaar38ea7842019-06-09 19:51:58 +02002384 * When "id" is zero or negative jut get the first message. But not one
2385 * in the ch_block_ids list.
Bram Moolenaar958dc692016-12-01 15:34:12 +01002386 * When "without_callback" is TRUE also get messages that were pushed back.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002387 * Return OK when found and return the value in "rettv".
2388 * Return FAIL otherwise.
2389 */
2390 static int
Bram Moolenaar958dc692016-12-01 15:34:12 +01002391channel_get_json(
2392 channel_T *channel,
2393 ch_part_T part,
2394 int id,
2395 int without_callback,
2396 typval_T **rettv)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002397{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002398 jsonq_T *head = &channel->ch_part[part].ch_json_head;
Bram Moolenaar77073442016-02-13 23:23:53 +01002399 jsonq_T *item = head->jq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002400
Bram Moolenaar77073442016-02-13 23:23:53 +01002401 while (item != NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002402 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002403 list_T *l = item->jq_value->vval.v_list;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002404 typval_T *tv;
2405
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002406 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002407 tv = &l->lv_first->li_tv;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002408
Bram Moolenaar958dc692016-12-01 15:34:12 +01002409 if ((without_callback || !item->jq_no_callback)
2410 && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
Bram Moolenaare56bf152016-02-08 23:23:42 +01002411 || (id <= 0 && (tv->v_type != VAR_NUMBER
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002412 || tv->vval.v_number == 0
Bram Moolenaar38ea7842019-06-09 19:51:58 +02002413 || !channel_has_block_id(
2414 &channel->ch_part[part], tv->vval.v_number)))))
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002415 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002416 *rettv = item->jq_value;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01002417 if (tv->v_type == VAR_NUMBER)
Bram Moolenaar4ac2e8d2018-04-08 12:38:26 +02002418 ch_log(channel, "Getting JSON message %ld",
2419 (long)tv->vval.v_number);
Bram Moolenaar77073442016-02-13 23:23:53 +01002420 remove_json_node(head, item);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002421 return OK;
2422 }
Bram Moolenaar77073442016-02-13 23:23:53 +01002423 item = item->jq_next;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002424 }
2425 return FAIL;
2426}
2427
Bram Moolenaar958dc692016-12-01 15:34:12 +01002428/*
2429 * Put back "rettv" into the JSON queue, there was no callback for it.
2430 * Takes over the values in "rettv".
2431 */
2432 static void
2433channel_push_json(channel_T *channel, ch_part_T part, typval_T *rettv)
2434{
2435 jsonq_T *head = &channel->ch_part[part].ch_json_head;
2436 jsonq_T *item = head->jq_next;
2437 jsonq_T *newitem;
2438
2439 if (head->jq_prev != NULL && head->jq_prev->jq_no_callback)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002440 // last item was pushed back, append to the end
Bram Moolenaar958dc692016-12-01 15:34:12 +01002441 item = NULL;
2442 else while (item != NULL && item->jq_no_callback)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002443 // append after the last item that was pushed back
Bram Moolenaar958dc692016-12-01 15:34:12 +01002444 item = item->jq_next;
2445
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002446 newitem = ALLOC_ONE(jsonq_T);
Bram Moolenaar958dc692016-12-01 15:34:12 +01002447 if (newitem == NULL)
2448 clear_tv(rettv);
2449 else
2450 {
2451 newitem->jq_value = alloc_tv();
2452 if (newitem->jq_value == NULL)
2453 {
2454 vim_free(newitem);
2455 clear_tv(rettv);
2456 }
2457 else
2458 {
2459 newitem->jq_no_callback = FALSE;
2460 *newitem->jq_value = *rettv;
2461 if (item == NULL)
2462 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002463 // append to the end
Bram Moolenaar958dc692016-12-01 15:34:12 +01002464 newitem->jq_prev = head->jq_prev;
2465 head->jq_prev = newitem;
2466 newitem->jq_next = NULL;
2467 if (newitem->jq_prev == NULL)
2468 head->jq_next = newitem;
2469 else
2470 newitem->jq_prev->jq_next = newitem;
2471 }
2472 else
2473 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002474 // append after "item"
Bram Moolenaar958dc692016-12-01 15:34:12 +01002475 newitem->jq_prev = item;
2476 newitem->jq_next = item->jq_next;
2477 item->jq_next = newitem;
2478 if (newitem->jq_next == NULL)
2479 head->jq_prev = newitem;
2480 else
2481 newitem->jq_next->jq_prev = newitem;
2482 }
2483 }
2484 }
2485}
2486
Bram Moolenaarece61b02016-02-20 21:39:05 +01002487#define CH_JSON_MAX_ARGS 4
2488
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002489/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002490 * Execute a command received over "channel"/"part"
Bram Moolenaarece61b02016-02-20 21:39:05 +01002491 * "argv[0]" is the command string.
2492 * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing.
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002493 */
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002494 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002495channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002496{
Bram Moolenaarece61b02016-02-20 21:39:05 +01002497 char_u *cmd = argv[0].vval.v_string;
2498 char_u *arg;
2499 int options = channel->ch_part[part].ch_mode == MODE_JS ? JSON_JS : 0;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002500
Bram Moolenaarece61b02016-02-20 21:39:05 +01002501 if (argv[1].v_type != VAR_STRING)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002502 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002503 ch_error(channel, "received command with non-string argument");
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002504 if (p_verbose > 2)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002505 emsg(_("E903: received command with non-string argument"));
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002506 return;
2507 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002508 arg = argv[1].vval.v_string;
Bram Moolenaar14ad6112016-02-01 21:47:13 +01002509 if (arg == NULL)
2510 arg = (char_u *)"";
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002511
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002512 if (STRCMP(cmd, "ex") == 0)
2513 {
Bram Moolenaar53989552019-12-23 22:59:18 +01002514 int called_emsg_before = called_emsg;
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002515
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002516 ch_log(channel, "Executing ex command '%s'", (char *)arg);
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002517 ++emsg_silent;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002518 do_cmdline_cmd(arg);
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002519 --emsg_silent;
Bram Moolenaar53989552019-12-23 22:59:18 +01002520 if (called_emsg > called_emsg_before)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002521 ch_log(channel, "Ex command error: '%s'",
Bram Moolenaarc4dcd602016-03-26 22:56:46 +01002522 (char *)get_vim_var_str(VV_ERRMSG));
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002523 }
2524 else if (STRCMP(cmd, "normal") == 0)
2525 {
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002526 exarg_T ea;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002527
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002528 ch_log(channel, "Executing normal command '%s'", (char *)arg);
Bram Moolenaara80faa82020-04-12 19:37:17 +02002529 CLEAR_FIELD(ea);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002530 ea.arg = arg;
2531 ea.addr_count = 0;
Bram Moolenaarc667da52019-11-30 20:52:27 +01002532 ea.forceit = TRUE; // no mapping
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002533 ex_normal(&ea);
2534 }
2535 else if (STRCMP(cmd, "redraw") == 0)
2536 {
2537 exarg_T ea;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002538
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002539 ch_log(channel, "redraw");
Bram Moolenaara80faa82020-04-12 19:37:17 +02002540 CLEAR_FIELD(ea);
Bram Moolenaar14ad6112016-02-01 21:47:13 +01002541 ea.forceit = *arg != NUL;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002542 ex_redraw(&ea);
2543 showruler(FALSE);
2544 setcursor();
Bram Moolenaara338adc2018-01-31 20:51:47 +01002545 out_flush_cursor(TRUE, FALSE);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002546 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002547 else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002548 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002549 int is_call = cmd[0] == 'c';
2550 int id_idx = is_call ? 3 : 2;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002551
Bram Moolenaarece61b02016-02-20 21:39:05 +01002552 if (argv[id_idx].v_type != VAR_UNKNOWN
2553 && argv[id_idx].v_type != VAR_NUMBER)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002554 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002555 ch_error(channel, "last argument for expr/call must be a number");
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002556 if (p_verbose > 2)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002557 emsg(_("E904: last argument for expr/call must be a number"));
Bram Moolenaarece61b02016-02-20 21:39:05 +01002558 }
2559 else if (is_call && argv[2].v_type != VAR_LIST)
2560 {
2561 ch_error(channel, "third argument for call must be a list");
2562 if (p_verbose > 2)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002563 emsg(_("E904: third argument for call must be a list"));
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002564 }
2565 else
2566 {
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002567 typval_T *tv = NULL;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002568 typval_T res_tv;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002569 typval_T err_tv;
Bram Moolenaar55fab432016-02-07 16:53:13 +01002570 char_u *json = NULL;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002571
Bram Moolenaarc667da52019-11-30 20:52:27 +01002572 // Don't pollute the display with errors.
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +01002573 ++emsg_skip;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002574 if (!is_call)
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002575 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002576 ch_log(channel, "Evaluating expression '%s'", (char *)arg);
Bram Moolenaarece61b02016-02-20 21:39:05 +01002577 tv = eval_expr(arg, NULL);
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002578 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002579 else
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002580 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002581 ch_log(channel, "Calling '%s'", (char *)arg);
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002582 if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK)
2583 tv = &res_tv;
Bram Moolenaarac74d5e2016-03-20 14:31:00 +01002584 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002585
2586 if (argv[id_idx].v_type == VAR_NUMBER)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002587 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002588 int id = argv[id_idx].vval.v_number;
2589
Bram Moolenaar55fab432016-02-07 16:53:13 +01002590 if (tv != NULL)
Bram Moolenaarf1f07922016-08-26 17:58:53 +02002591 json = json_encode_nr_expr(id, tv, options | JSON_NL);
Bram Moolenaar55fab432016-02-07 16:53:13 +01002592 if (tv == NULL || (json != NULL && *json == NUL))
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002593 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002594 // If evaluation failed or the result can't be encoded
2595 // then return the string "ERROR".
Bram Moolenaar77073442016-02-13 23:23:53 +01002596 vim_free(json);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002597 err_tv.v_type = VAR_STRING;
2598 err_tv.vval.v_string = (char_u *)"ERROR";
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002599 json = json_encode_nr_expr(id, &err_tv, options | JSON_NL);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002600 }
Bram Moolenaar55fab432016-02-07 16:53:13 +01002601 if (json != NULL)
2602 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002603 channel_send(channel,
2604 part == PART_SOCK ? PART_SOCK : PART_IN,
Bram Moolenaarbf2cc5f2016-07-07 20:45:06 +02002605 json, (int)STRLEN(json), (char *)cmd);
Bram Moolenaar55fab432016-02-07 16:53:13 +01002606 vim_free(json);
2607 }
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002608 }
Bram Moolenaar55fab432016-02-07 16:53:13 +01002609 --emsg_skip;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002610 if (tv == &res_tv)
2611 clear_tv(tv);
Bram Moolenaarc8fe3382016-09-04 20:44:42 +02002612 else
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +01002613 free_tv(tv);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +01002614 }
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002615 }
2616 else if (p_verbose > 2)
Bram Moolenaarece61b02016-02-20 21:39:05 +01002617 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002618 ch_error(channel, "Received unknown command: %s", (char *)cmd);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002619 semsg(_("E905: received unknown command: %s"), cmd);
Bram Moolenaarece61b02016-02-20 21:39:05 +01002620 }
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002621}
2622
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02002623/*
2624 * Invoke the callback at "cbhead".
2625 * Does not redraw but sets channel_need_redraw.
2626 */
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002627 static void
2628invoke_one_time_callback(
2629 channel_T *channel,
2630 cbq_T *cbhead,
2631 cbq_T *item,
2632 typval_T *argv)
2633{
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002634 ch_log(channel, "Invoking one-time callback %s",
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002635 (char *)item->cq_callback.cb_name);
Bram Moolenaarc667da52019-11-30 20:52:27 +01002636 // Remove the item from the list first, if the callback
2637 // invokes ch_close() the list will be cleared.
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002638 remove_cb_node(cbhead, item);
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002639 invoke_callback(channel, &item->cq_callback, argv);
2640 free_callback(&item->cq_callback);
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002641 vim_free(item);
2642}
2643
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002644 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002645append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002646{
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002647 bufref_T save_curbuf = {NULL, 0, 0};
2648 win_T *save_curwin = NULL;
2649 tabpage_T *save_curtab = NULL;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002650 linenr_T lnum = buffer->b_ml.ml_line_count;
2651 int save_write_to = buffer->b_write_to_channel;
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002652 chanpart_T *ch_part = &channel->ch_part[part];
2653 int save_p_ma = buffer->b_p_ma;
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002654 int empty = (buffer->b_ml.ml_flags & ML_EMPTY) ? 1 : 0;
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002655
2656 if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
2657 {
2658 if (!ch_part->ch_nomod_error)
2659 {
2660 ch_error(channel, "Buffer is not modifiable, cannot append");
2661 ch_part->ch_nomod_error = TRUE;
2662 }
2663 return;
2664 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002665
Bram Moolenaarc667da52019-11-30 20:52:27 +01002666 // If the buffer is also used as input insert above the last
2667 // line. Don't write these lines.
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002668 if (save_write_to)
2669 {
2670 --lnum;
2671 buffer->b_write_to_channel = FALSE;
2672 }
2673
Bram Moolenaarc667da52019-11-30 20:52:27 +01002674 // Append to the buffer
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002675 ch_log(channel, "appending line %d to buffer", (int)lnum + 1 - empty);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002676
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002677 buffer->b_p_ma = TRUE;
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002678
Bram Moolenaarc667da52019-11-30 20:52:27 +01002679 // Save curbuf/curwin/curtab and make "buffer" the current buffer.
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002680 switch_to_win_for_buf(buffer, &save_curwin, &save_curtab, &save_curbuf);
2681
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002682 u_sync(TRUE);
Bram Moolenaarc667da52019-11-30 20:52:27 +01002683 // ignore undo failure, undo is not very useful here
Bram Moolenaar42335f52018-09-13 15:33:43 +02002684 vim_ignored = u_save(lnum - empty, lnum + 1);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002685
Bram Moolenaar169ebb02016-09-07 23:32:23 +02002686 if (empty)
2687 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002688 // The buffer is empty, replace the first (dummy) line.
Bram Moolenaar169ebb02016-09-07 23:32:23 +02002689 ml_replace(lnum, msg, TRUE);
2690 lnum = 0;
2691 }
2692 else
2693 ml_append(lnum, msg, 0, FALSE);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002694 appended_lines_mark(lnum, 1L);
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002695
Bram Moolenaarc667da52019-11-30 20:52:27 +01002696 // Restore curbuf/curwin/curtab
Bram Moolenaar6b7355a2017-08-04 21:37:54 +02002697 restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
2698
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02002699 if (ch_part->ch_nomodifiable)
2700 buffer->b_p_ma = FALSE;
2701 else
2702 buffer->b_p_ma = save_p_ma;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002703
2704 if (buffer->b_nwindows > 0)
2705 {
2706 win_T *wp;
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002707
2708 FOR_ALL_WINDOWS(wp)
2709 {
Bram Moolenaar4641a122019-07-29 22:10:23 +02002710 if (wp->w_buffer == buffer)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002711 {
Bram Moolenaar4641a122019-07-29 22:10:23 +02002712 int move_cursor = save_write_to
2713 ? wp->w_cursor.lnum == lnum + 1
2714 : (wp->w_cursor.lnum == lnum
2715 && wp->w_cursor.col == 0);
2716
2717 // If the cursor is at or above the new line, move it one line
2718 // down. If the topline is outdated update it now.
2719 if (move_cursor || wp->w_topline > buffer->b_ml.ml_line_count)
2720 {
2721 if (move_cursor)
2722 ++wp->w_cursor.lnum;
2723 save_curwin = curwin;
2724 curwin = wp;
2725 curbuf = curwin->w_buffer;
2726 scroll_cursor_bot(0, FALSE);
2727 curwin = save_curwin;
2728 curbuf = curwin->w_buffer;
2729 }
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002730 }
2731 }
Bram Moolenaar29ae3772017-04-30 19:39:39 +02002732 redraw_buf_and_status_later(buffer, VALID);
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002733 channel_need_redraw = TRUE;
2734 }
2735
2736 if (save_write_to)
2737 {
2738 channel_T *ch;
2739
Bram Moolenaarc667da52019-11-30 20:52:27 +01002740 // Find channels reading from this buffer and adjust their
2741 // next-to-read line number.
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002742 buffer->b_write_to_channel = TRUE;
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002743 FOR_ALL_CHANNELS(ch)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002744 {
2745 chanpart_T *in_part = &ch->ch_part[PART_IN];
2746
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002747 if (in_part->ch_bufref.br_buf == buffer)
Bram Moolenaar99ef0622016-03-06 20:22:25 +01002748 in_part->ch_buf_bot = buffer->b_ml.ml_line_count;
2749 }
2750 }
2751}
2752
Bram Moolenaar437905c2016-04-26 19:01:05 +02002753 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002754drop_messages(channel_T *channel, ch_part_T part)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002755{
2756 char_u *msg;
2757
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002758 while ((msg = channel_get(channel, part, NULL)) != NULL)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002759 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002760 ch_log(channel, "Dropping message '%s'", (char *)msg);
Bram Moolenaar437905c2016-04-26 19:01:05 +02002761 vim_free(msg);
2762 }
2763}
2764
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002765/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002766 * Invoke a callback for "channel"/"part" if needed.
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02002767 * This does not redraw but sets channel_need_redraw when redraw is needed.
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002768 * Return TRUE when a message was handled, there might be another one.
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002769 */
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002770 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02002771may_invoke_callback(channel_T *channel, ch_part_T part)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002772{
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002773 char_u *msg = NULL;
2774 typval_T *listtv = NULL;
Bram Moolenaarece61b02016-02-20 21:39:05 +01002775 typval_T argv[CH_JSON_MAX_ARGS];
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002776 int seq_nr = -1;
Bram Moolenaarec68a992016-10-03 21:37:41 +02002777 chanpart_T *ch_part = &channel->ch_part[part];
2778 ch_mode_T ch_mode = ch_part->ch_mode;
2779 cbq_T *cbhead = &ch_part->ch_cb_head;
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002780 cbq_T *cbitem;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002781 callback_T *callback = NULL;
Bram Moolenaar187db502016-02-27 14:44:26 +01002782 buf_T *buffer = NULL;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002783 char_u *p;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002784
Bram Moolenaar4e221c92016-02-23 13:20:22 +01002785 if (channel->ch_nb_close_cb != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002786 // this channel is handled elsewhere (netbeans)
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002787 return FALSE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002788
Bram Moolenaarc667da52019-11-30 20:52:27 +01002789 // Use a message-specific callback, part callback or channel callback
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002790 for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
2791 if (cbitem->cq_seq_nr == 0)
2792 break;
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002793 if (cbitem != NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002794 callback = &cbitem->cq_callback;
2795 else if (ch_part->ch_callback.cb_name != NULL)
2796 callback = &ch_part->ch_callback;
2797 else if (channel->ch_callback.cb_name != NULL)
2798 callback = &channel->ch_callback;
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002799
Bram Moolenaarec68a992016-10-03 21:37:41 +02002800 buffer = ch_part->ch_bufref.br_buf;
Bram Moolenaarc4da1132017-07-15 19:39:43 +02002801 if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
2802 || buffer->b_ml.ml_mfp == NULL))
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002803 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002804 // buffer was wiped out or unloaded
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002805 ch_log(channel, "%s buffer has been wiped out", part_names[part]);
Bram Moolenaarec68a992016-10-03 21:37:41 +02002806 ch_part->ch_bufref.br_buf = NULL;
Bram Moolenaarc7f0ebc2016-02-27 21:10:09 +01002807 buffer = NULL;
2808 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002809
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002810 if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002811 {
Bram Moolenaarece61b02016-02-20 21:39:05 +01002812 listitem_T *item;
2813 int argc = 0;
2814
Bram Moolenaarc667da52019-11-30 20:52:27 +01002815 // Get any json message in the queue.
Bram Moolenaar958dc692016-12-01 15:34:12 +01002816 if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002817 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002818 // Parse readahead, return when there is still no message.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002819 channel_parse_json(channel, part);
Bram Moolenaar958dc692016-12-01 15:34:12 +01002820 if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002821 return FALSE;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002822 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002823
Bram Moolenaarece61b02016-02-20 21:39:05 +01002824 for (item = listtv->vval.v_list->lv_first;
2825 item != NULL && argc < CH_JSON_MAX_ARGS;
2826 item = item->li_next)
2827 argv[argc++] = item->li_tv;
2828 while (argc < CH_JSON_MAX_ARGS)
2829 argv[argc++].v_type = VAR_UNKNOWN;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002830
Bram Moolenaarece61b02016-02-20 21:39:05 +01002831 if (argv[0].v_type == VAR_STRING)
2832 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002833 // ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg]
Bram Moolenaarece61b02016-02-20 21:39:05 +01002834 channel_exe_cmd(channel, part, argv);
Bram Moolenaar77073442016-02-13 23:23:53 +01002835 free_tv(listtv);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002836 return TRUE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002837 }
2838
Bram Moolenaarece61b02016-02-20 21:39:05 +01002839 if (argv[0].v_type != VAR_NUMBER)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002840 {
Bram Moolenaar77073442016-02-13 23:23:53 +01002841 ch_error(channel,
Bram Moolenaar81661fb2016-02-18 22:23:34 +01002842 "Dropping message with invalid sequence number type");
Bram Moolenaar77073442016-02-13 23:23:53 +01002843 free_tv(listtv);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002844 return FALSE;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002845 }
Bram Moolenaarece61b02016-02-20 21:39:05 +01002846 seq_nr = argv[0].vval.v_number;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002847 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01002848 else if (channel_peek(channel, part) == NULL)
Bram Moolenaard7ece102016-02-02 23:23:02 +01002849 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002850 // nothing to read on RAW or NL channel
Bram Moolenaard7ece102016-02-02 23:23:02 +01002851 return FALSE;
2852 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002853 else
2854 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002855 // If there is no callback or buffer drop the message.
Bram Moolenaar187db502016-02-27 14:44:26 +01002856 if (callback == NULL && buffer == NULL)
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002857 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002858 // If there is a close callback it may use ch_read() to get the
2859 // messages.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002860 if (channel->ch_close_cb.cb_name == NULL && !channel->ch_drop_never)
Bram Moolenaar437905c2016-04-26 19:01:05 +02002861 drop_messages(channel, part);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002862 return FALSE;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002863 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002864
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002865 if (ch_mode == MODE_NL)
2866 {
Bram Moolenaarec68a992016-10-03 21:37:41 +02002867 char_u *nl = NULL;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002868 char_u *buf;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002869 readq_T *node;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002870
Bram Moolenaarc667da52019-11-30 20:52:27 +01002871 // See if we have a message ending in NL in the first buffer. If
2872 // not try to concatenate the first and the second buffer.
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002873 while (TRUE)
2874 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002875 node = channel_peek(channel, part);
2876 nl = channel_first_nl(node);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002877 if (nl != NULL)
2878 break;
Bram Moolenaar9ed96ef2016-06-04 17:17:11 +02002879 if (channel_collapse(channel, part, TRUE) == FAIL)
Bram Moolenaarec68a992016-10-03 21:37:41 +02002880 {
2881 if (ch_part->ch_fd == INVALID_FD && node->rq_buflen > 0)
2882 break;
Bram Moolenaarc667da52019-11-30 20:52:27 +01002883 return FALSE; // incomplete message
Bram Moolenaarec68a992016-10-03 21:37:41 +02002884 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002885 }
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002886 buf = node->rq_buffer;
2887
Bram Moolenaar772153f2019-03-04 12:09:49 +01002888 // Convert NUL to NL, the internal representation.
2889 for (p = buf; (nl == NULL || p < nl)
2890 && p < buf + node->rq_buflen; ++p)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002891 if (*p == NUL)
2892 *p = NL;
2893
Bram Moolenaar772153f2019-03-04 12:09:49 +01002894 if (nl == NULL)
Bram Moolenaar187db502016-02-27 14:44:26 +01002895 {
Bram Moolenaar772153f2019-03-04 12:09:49 +01002896 // get the whole buffer, drop the NL
2897 msg = channel_get(channel, part, NULL);
2898 }
2899 else if (nl + 1 == buf + node->rq_buflen)
2900 {
2901 // get the whole buffer
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002902 msg = channel_get(channel, part, NULL);
Bram Moolenaar187db502016-02-27 14:44:26 +01002903 *nl = NUL;
2904 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002905 else
2906 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002907 // Copy the message into allocated memory (excluding the NL)
2908 // and remove it from the buffer (including the NL).
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002909 msg = vim_strnsave(buf, (int)(nl - buf));
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002910 channel_consume(channel, part, (int)(nl - buf) + 1);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002911 }
2912 }
2913 else
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002914 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002915 // For a raw channel we don't know where the message ends, just
2916 // get everything we have.
2917 // Convert NUL to NL, the internal representation.
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002918 msg = channel_get_all(channel, part, NULL);
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02002919 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01002920
Bram Moolenaarbf73b912016-03-02 21:16:59 +01002921 if (msg == NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002922 return FALSE; // out of memory (and avoids Coverity warning)
Bram Moolenaarbf73b912016-03-02 21:16:59 +01002923
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002924 argv[1].v_type = VAR_STRING;
2925 argv[1].vval.v_string = msg;
2926 }
2927
Bram Moolenaara07fec92016-02-05 21:04:08 +01002928 if (seq_nr > 0)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002929 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002930 int done = FALSE;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002931
Bram Moolenaarc667da52019-11-30 20:52:27 +01002932 // JSON or JS mode: invoke the one-time callback with the matching nr
Bram Moolenaar5983ad02016-03-05 20:54:36 +01002933 for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002934 if (cbitem->cq_seq_nr == seq_nr)
Bram Moolenaara07fec92016-02-05 21:04:08 +01002935 {
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002936 invoke_one_time_callback(channel, cbhead, cbitem, argv);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002937 done = TRUE;
Bram Moolenaara07fec92016-02-05 21:04:08 +01002938 break;
2939 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002940 if (!done)
Bram Moolenaar958dc692016-12-01 15:34:12 +01002941 {
2942 if (channel->ch_drop_never)
2943 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002944 // message must be read with ch_read()
Bram Moolenaar958dc692016-12-01 15:34:12 +01002945 channel_push_json(channel, part, listtv);
2946 listtv = NULL;
2947 }
2948 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002949 ch_log(channel, "Dropping message %d without callback",
Bram Moolenaar958dc692016-12-01 15:34:12 +01002950 seq_nr);
2951 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002952 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002953 else if (callback != NULL || buffer != NULL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002954 {
Bram Moolenaar187db502016-02-27 14:44:26 +01002955 if (buffer != NULL)
2956 {
Bram Moolenaarcc7f8be2016-02-29 22:55:56 +01002957 if (msg == NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01002958 // JSON or JS mode: re-encode the message.
Bram Moolenaarcc7f8be2016-02-29 22:55:56 +01002959 msg = json_encode(listtv, ch_mode);
2960 if (msg != NULL)
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002961 {
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02002962#ifdef FEAT_TERMINAL
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002963 if (buffer->b_term != NULL)
2964 write_to_term(buffer, msg, channel);
2965 else
Bram Moolenaarc0aa4822017-07-16 14:04:29 +02002966#endif
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02002967 append_to_buffer(buffer, msg, channel, part);
2968 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002969 }
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002970
Bram Moolenaar187db502016-02-27 14:44:26 +01002971 if (callback != NULL)
2972 {
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002973 if (cbitem != NULL)
2974 invoke_one_time_callback(channel, cbhead, cbitem, argv);
2975 else
2976 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01002977 // invoke the channel callback
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002978 ch_log(channel, "Invoking channel callback %s",
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02002979 (char *)callback->cb_name);
2980 invoke_callback(channel, callback, argv);
Bram Moolenaard6547fc2016-03-03 19:35:02 +01002981 }
Bram Moolenaar187db502016-02-27 14:44:26 +01002982 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002983 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01002984 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02002985 ch_log(channel, "Dropping message %d", seq_nr);
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01002986
Bram Moolenaar19d2f152016-02-01 21:38:19 +01002987 if (listtv != NULL)
Bram Moolenaar77073442016-02-13 23:23:53 +01002988 free_tv(listtv);
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002989 vim_free(msg);
Bram Moolenaardf5b27b2016-02-02 18:43:17 +01002990
2991 return TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002992}
2993
Bram Moolenaar113e1072019-01-20 15:30:40 +01002994#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01002995/*
Bram Moolenaar77073442016-02-13 23:23:53 +01002996 * Return TRUE when channel "channel" is open for writing to.
2997 * Also returns FALSE or invalid "channel".
Bram Moolenaard04a0202016-01-26 23:30:18 +01002998 */
2999 int
Bram Moolenaar77073442016-02-13 23:23:53 +01003000channel_can_write_to(channel_T *channel)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003001{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003002 return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01003003 || channel->CH_IN_FD != INVALID_FD);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003004}
Bram Moolenaar113e1072019-01-20 15:30:40 +01003005#endif
Bram Moolenaard04a0202016-01-26 23:30:18 +01003006
3007/*
Bram Moolenaar77073442016-02-13 23:23:53 +01003008 * Return TRUE when channel "channel" is open for reading or writing.
3009 * Also returns FALSE for invalid "channel".
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003010 */
3011 int
Bram Moolenaar77073442016-02-13 23:23:53 +01003012channel_is_open(channel_T *channel)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003013{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003014 return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003015 || channel->CH_IN_FD != INVALID_FD
3016 || channel->CH_OUT_FD != INVALID_FD
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01003017 || channel->CH_ERR_FD != INVALID_FD);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003018}
3019
3020/*
Bram Moolenaar437905c2016-04-26 19:01:05 +02003021 * Return TRUE if "channel" has JSON or other typeahead.
3022 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02003023 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003024channel_has_readahead(channel_T *channel, ch_part_T part)
Bram Moolenaar437905c2016-04-26 19:01:05 +02003025{
3026 ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
3027
3028 if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
3029 {
3030 jsonq_T *head = &channel->ch_part[part].ch_json_head;
Bram Moolenaar437905c2016-04-26 19:01:05 +02003031
Bram Moolenaar4340fc92019-06-28 22:06:49 +02003032 if (head->jq_next == NULL)
3033 // Parse json from readahead, there might be a complete message to
3034 // process.
3035 channel_parse_json(channel, part);
3036
3037 return head->jq_next != NULL;
Bram Moolenaar437905c2016-04-26 19:01:05 +02003038 }
3039 return channel_peek(channel, part) != NULL;
3040}
3041
3042/*
Bram Moolenaar77073442016-02-13 23:23:53 +01003043 * Return a string indicating the status of the channel.
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003044 * If "req_part" is not negative check that part.
Bram Moolenaar77073442016-02-13 23:23:53 +01003045 */
3046 char *
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003047channel_status(channel_T *channel, int req_part)
Bram Moolenaar77073442016-02-13 23:23:53 +01003048{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003049 ch_part_T part;
Bram Moolenaar437905c2016-04-26 19:01:05 +02003050 int has_readahead = FALSE;
3051
Bram Moolenaar77073442016-02-13 23:23:53 +01003052 if (channel == NULL)
3053 return "fail";
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003054 if (req_part == PART_OUT)
3055 {
3056 if (channel->CH_OUT_FD != INVALID_FD)
3057 return "open";
3058 if (channel_has_readahead(channel, PART_OUT))
Bram Moolenaar437905c2016-04-26 19:01:05 +02003059 has_readahead = TRUE;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003060 }
3061 else if (req_part == PART_ERR)
3062 {
3063 if (channel->CH_ERR_FD != INVALID_FD)
3064 return "open";
3065 if (channel_has_readahead(channel, PART_ERR))
3066 has_readahead = TRUE;
3067 }
3068 else
3069 {
3070 if (channel_is_open(channel))
3071 return "open";
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003072 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003073 if (channel_has_readahead(channel, part))
3074 {
3075 has_readahead = TRUE;
3076 break;
3077 }
3078 }
Bram Moolenaar437905c2016-04-26 19:01:05 +02003079
3080 if (has_readahead)
3081 return "buffered";
Bram Moolenaar77073442016-02-13 23:23:53 +01003082 return "closed";
3083}
3084
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003085 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003086channel_part_info(channel_T *channel, dict_T *dict, char *name, ch_part_T part)
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003087{
3088 chanpart_T *chanpart = &channel->ch_part[part];
Bram Moolenaarc667da52019-11-30 20:52:27 +01003089 char namebuf[20]; // longest is "sock_timeout"
Bram Moolenaar3f3fbd32016-03-21 12:36:28 +01003090 size_t tail;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003091 char *status;
Bram Moolenaar573e4452016-03-21 22:35:10 +01003092 char *s = "";
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003093
Bram Moolenaar925ccfd2016-03-28 22:38:02 +02003094 vim_strncpy((char_u *)namebuf, (char_u *)name, 4);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003095 STRCAT(namebuf, "_");
3096 tail = STRLEN(namebuf);
3097
3098 STRCPY(namebuf + tail, "status");
Bram Moolenaar7ef38102016-09-26 22:36:58 +02003099 if (chanpart->ch_fd != INVALID_FD)
3100 status = "open";
3101 else if (channel_has_readahead(channel, part))
3102 status = "buffered";
3103 else
3104 status = "closed";
Bram Moolenaare0be1672018-07-08 16:50:37 +02003105 dict_add_string(dict, namebuf, (char_u *)status);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003106
3107 STRCPY(namebuf + tail, "mode");
3108 switch (chanpart->ch_mode)
3109 {
3110 case MODE_NL: s = "NL"; break;
3111 case MODE_RAW: s = "RAW"; break;
3112 case MODE_JSON: s = "JSON"; break;
3113 case MODE_JS: s = "JS"; break;
3114 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02003115 dict_add_string(dict, namebuf, (char_u *)s);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003116
3117 STRCPY(namebuf + tail, "io");
3118 if (part == PART_SOCK)
3119 s = "socket";
3120 else switch (chanpart->ch_io)
3121 {
3122 case JIO_NULL: s = "null"; break;
3123 case JIO_PIPE: s = "pipe"; break;
3124 case JIO_FILE: s = "file"; break;
3125 case JIO_BUFFER: s = "buffer"; break;
3126 case JIO_OUT: s = "out"; break;
3127 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02003128 dict_add_string(dict, namebuf, (char_u *)s);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003129
3130 STRCPY(namebuf + tail, "timeout");
Bram Moolenaare0be1672018-07-08 16:50:37 +02003131 dict_add_number(dict, namebuf, chanpart->ch_timeout);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003132}
3133
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02003134 static void
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003135channel_info(channel_T *channel, dict_T *dict)
3136{
Bram Moolenaare0be1672018-07-08 16:50:37 +02003137 dict_add_number(dict, "id", channel->ch_id);
3138 dict_add_string(dict, "status", (char_u *)channel_status(channel, -1));
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003139
3140 if (channel->ch_hostname != NULL)
3141 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02003142 dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
3143 dict_add_number(dict, "port", channel->ch_port);
Bram Moolenaar03602ec2016-03-20 20:57:45 +01003144 channel_part_info(channel, dict, "sock", PART_SOCK);
3145 }
3146 else
3147 {
3148 channel_part_info(channel, dict, "out", PART_OUT);
3149 channel_part_info(channel, dict, "err", PART_ERR);
3150 channel_part_info(channel, dict, "in", PART_IN);
3151 }
3152}
3153
Bram Moolenaar77073442016-02-13 23:23:53 +01003154/*
3155 * Close channel "channel".
Bram Moolenaarc8dcbb12016-02-25 23:10:17 +01003156 * Trigger the close callback if "invoke_close_cb" is TRUE.
Bram Moolenaar187db502016-02-27 14:44:26 +01003157 * Does not clear the buffers.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003158 */
3159 void
Bram Moolenaar8b374212016-02-24 20:43:06 +01003160channel_close(channel_T *channel, int invoke_close_cb)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003161{
Bram Moolenaar81661fb2016-02-18 22:23:34 +01003162 ch_log(channel, "Closing channel");
Bram Moolenaard04a0202016-01-26 23:30:18 +01003163
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003164#ifdef FEAT_GUI
3165 channel_gui_unregister(channel);
3166#endif
3167
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003168 ch_close_part(channel, PART_SOCK);
3169 ch_close_part(channel, PART_IN);
3170 ch_close_part(channel, PART_OUT);
3171 ch_close_part(channel, PART_ERR);
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01003172
Bram Moolenaara9f02812017-08-05 17:40:38 +02003173 if (invoke_close_cb)
Bram Moolenaar4e221c92016-02-23 13:20:22 +01003174 {
Bram Moolenaara9f02812017-08-05 17:40:38 +02003175 ch_part_T part;
Bram Moolenaar4e221c92016-02-23 13:20:22 +01003176
Bram Moolenaarc667da52019-11-30 20:52:27 +01003177 // Invoke callbacks and flush buffers before the close callback.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003178 if (channel->ch_close_cb.cb_name != NULL)
Bram Moolenaara9f02812017-08-05 17:40:38 +02003179 ch_log(channel,
3180 "Invoking callbacks and flushing buffers before closing");
3181 for (part = PART_SOCK; part < PART_IN; ++part)
3182 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003183 if (channel->ch_close_cb.cb_name != NULL
Bram Moolenaara9f02812017-08-05 17:40:38 +02003184 || channel->ch_part[part].ch_bufref.br_buf != NULL)
3185 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003186 // Increment the refcount to avoid the channel being freed
3187 // halfway.
Bram Moolenaara9f02812017-08-05 17:40:38 +02003188 ++channel->ch_refcount;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003189 if (channel->ch_close_cb.cb_name == NULL)
Bram Moolenaara9f02812017-08-05 17:40:38 +02003190 ch_log(channel, "flushing %s buffers before closing",
3191 part_names[part]);
3192 while (may_invoke_callback(channel, part))
3193 ;
3194 --channel->ch_refcount;
3195 }
3196 }
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003197
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003198 if (channel->ch_close_cb.cb_name != NULL)
Bram Moolenaara9f02812017-08-05 17:40:38 +02003199 {
3200 typval_T argv[1];
3201 typval_T rettv;
Bram Moolenaara9f02812017-08-05 17:40:38 +02003202
Bram Moolenaarc667da52019-11-30 20:52:27 +01003203 // Increment the refcount to avoid the channel being freed
3204 // halfway.
Bram Moolenaara9f02812017-08-05 17:40:38 +02003205 ++channel->ch_refcount;
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003206 ch_log(channel, "Invoking close callback %s",
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003207 (char *)channel->ch_close_cb.cb_name);
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003208 argv[0].v_type = VAR_CHANNEL;
3209 argv[0].vval.v_channel = channel;
Bram Moolenaarc6538bc2019-08-03 18:17:11 +02003210 call_callback(&channel->ch_close_cb, -1, &rettv, 1, argv);
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003211 clear_tv(&rettv);
Bram Moolenaarcefe4f92016-05-04 21:49:19 +02003212 channel_need_redraw = TRUE;
Bram Moolenaar4e221c92016-02-23 13:20:22 +01003213
Bram Moolenaarc667da52019-11-30 20:52:27 +01003214 // the callback is only called once
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003215 free_callback(&channel->ch_close_cb);
Bram Moolenaar437905c2016-04-26 19:01:05 +02003216
Bram Moolenaara9f02812017-08-05 17:40:38 +02003217 if (channel_need_redraw)
3218 {
3219 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02003220 redraw_after_callback(TRUE);
Bram Moolenaara9f02812017-08-05 17:40:38 +02003221 }
Bram Moolenaarcefe4f92016-05-04 21:49:19 +02003222
Bram Moolenaara9f02812017-08-05 17:40:38 +02003223 if (!channel->ch_drop_never)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003224 // any remaining messages are useless now
Bram Moolenaara9f02812017-08-05 17:40:38 +02003225 for (part = PART_SOCK; part < PART_IN; ++part)
3226 drop_messages(channel, part);
Bram Moolenaar5fd8b782017-11-11 15:54:00 +01003227
3228 --channel->ch_refcount;
Bram Moolenaara9f02812017-08-05 17:40:38 +02003229 }
Bram Moolenaar4e221c92016-02-23 13:20:22 +01003230 }
3231
3232 channel->ch_nb_close_cb = NULL;
Bram Moolenaard85f2712017-07-28 21:51:57 +02003233
3234#ifdef FEAT_TERMINAL
3235 term_channel_closed(channel);
3236#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +01003237}
3238
Bram Moolenaard04a0202016-01-26 23:30:18 +01003239/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02003240 * Close the "in" part channel "channel".
3241 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02003242 static void
Bram Moolenaar0874a832016-09-01 15:11:51 +02003243channel_close_in(channel_T *channel)
3244{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003245 ch_close_part(channel, PART_IN);
Bram Moolenaar0874a832016-09-01 15:11:51 +02003246}
3247
Bram Moolenaaraba680a2017-09-09 16:42:53 +02003248 static void
3249remove_from_writeque(writeq_T *wq, writeq_T *entry)
3250{
3251 ga_clear(&entry->wq_ga);
3252 wq->wq_next = entry->wq_next;
3253 if (wq->wq_next == NULL)
3254 wq->wq_prev = NULL;
3255 else
3256 wq->wq_next->wq_prev = NULL;
Bram Moolenaar5b5adf52017-09-09 18:16:43 +02003257 vim_free(entry);
Bram Moolenaaraba680a2017-09-09 16:42:53 +02003258}
3259
Bram Moolenaar0874a832016-09-01 15:11:51 +02003260/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003261 * Clear the read buffer on "channel"/"part".
Bram Moolenaard04a0202016-01-26 23:30:18 +01003262 */
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003263 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003264channel_clear_one(channel_T *channel, ch_part_T part)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003265{
Bram Moolenaaraba680a2017-09-09 16:42:53 +02003266 chanpart_T *ch_part = &channel->ch_part[part];
3267 jsonq_T *json_head = &ch_part->ch_json_head;
3268 cbq_T *cb_head = &ch_part->ch_cb_head;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003269
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003270 while (channel_peek(channel, part) != NULL)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003271 vim_free(channel_get(channel, part, NULL));
Bram Moolenaar77073442016-02-13 23:23:53 +01003272
3273 while (cb_head->cq_next != NULL)
Bram Moolenaard46ae142016-02-16 13:33:52 +01003274 {
3275 cbq_T *node = cb_head->cq_next;
3276
3277 remove_cb_node(cb_head, node);
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003278 free_callback(&node->cq_callback);
Bram Moolenaard46ae142016-02-16 13:33:52 +01003279 vim_free(node);
3280 }
Bram Moolenaar77073442016-02-13 23:23:53 +01003281
3282 while (json_head->jq_next != NULL)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003283 {
Bram Moolenaar77073442016-02-13 23:23:53 +01003284 free_tv(json_head->jq_next->jq_value);
3285 remove_json_node(json_head, json_head->jq_next);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003286 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01003287
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003288 free_callback(&ch_part->ch_callback);
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003289 ga_clear(&ch_part->ch_block_ids);
Bram Moolenaaraba680a2017-09-09 16:42:53 +02003290
3291 while (ch_part->ch_writeque.wq_next != NULL)
3292 remove_from_writeque(&ch_part->ch_writeque,
3293 ch_part->ch_writeque.wq_next);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003294}
3295
3296/*
3297 * Clear all the read buffers on "channel".
3298 */
3299 void
3300channel_clear(channel_T *channel)
3301{
Bram Moolenaard6051b52016-02-28 15:49:03 +01003302 ch_log(channel, "Clearing channel");
Bram Moolenaard23a8232018-02-10 18:45:26 +01003303 VIM_CLEAR(channel->ch_hostname);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003304 channel_clear_one(channel, PART_SOCK);
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003305 channel_clear_one(channel, PART_OUT);
3306 channel_clear_one(channel, PART_ERR);
Bram Moolenaar5b5adf52017-09-09 18:16:43 +02003307 channel_clear_one(channel, PART_IN);
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02003308 free_callback(&channel->ch_callback);
3309 free_callback(&channel->ch_close_cb);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003310}
3311
Bram Moolenaar77073442016-02-13 23:23:53 +01003312#if defined(EXITFREE) || defined(PROTO)
3313 void
3314channel_free_all(void)
3315{
3316 channel_T *channel;
3317
Bram Moolenaard6051b52016-02-28 15:49:03 +01003318 ch_log(NULL, "channel_free_all()");
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003319 FOR_ALL_CHANNELS(channel)
Bram Moolenaar77073442016-02-13 23:23:53 +01003320 channel_clear(channel);
3321}
3322#endif
3323
3324
Bram Moolenaarc667da52019-11-30 20:52:27 +01003325// Sent when the netbeans channel is found closed when reading.
Bram Moolenaareed284a2016-02-22 23:13:33 +01003326#define DETACH_MSG_RAW "DETACH\n"
Bram Moolenaard04a0202016-01-26 23:30:18 +01003327
Bram Moolenaarc667da52019-11-30 20:52:27 +01003328// Buffer size for reading incoming messages.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003329#define MAXMSGSIZE 4096
3330
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003331#if defined(HAVE_SELECT)
3332/*
3333 * Add write fds where we are waiting for writing to be possible.
3334 */
3335 static int
3336channel_fill_wfds(int maxfd_arg, fd_set *wfds)
3337{
3338 int maxfd = maxfd_arg;
3339 channel_T *ch;
3340
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003341 FOR_ALL_CHANNELS(ch)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003342 {
3343 chanpart_T *in_part = &ch->ch_part[PART_IN];
3344
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02003345 if (in_part->ch_fd != INVALID_FD
3346 && (in_part->ch_bufref.br_buf != NULL
3347 || in_part->ch_writeque.wq_next != NULL))
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003348 {
3349 FD_SET((int)in_part->ch_fd, wfds);
3350 if ((int)in_part->ch_fd >= maxfd)
3351 maxfd = (int)in_part->ch_fd + 1;
3352 }
3353 }
3354 return maxfd;
3355}
3356#else
3357/*
3358 * Add write fds where we are waiting for writing to be possible.
3359 */
3360 static int
3361channel_fill_poll_write(int nfd_in, struct pollfd *fds)
3362{
3363 int nfd = nfd_in;
3364 channel_T *ch;
3365
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003366 FOR_ALL_CHANNELS(ch)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003367 {
3368 chanpart_T *in_part = &ch->ch_part[PART_IN];
3369
Bram Moolenaar683b7962017-08-19 15:51:59 +02003370 if (in_part->ch_fd != INVALID_FD
3371 && (in_part->ch_bufref.br_buf != NULL
3372 || in_part->ch_writeque.wq_next != NULL))
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003373 {
3374 in_part->ch_poll_idx = nfd;
3375 fds[nfd].fd = in_part->ch_fd;
3376 fds[nfd].events = POLLOUT;
3377 ++nfd;
3378 }
3379 else
3380 in_part->ch_poll_idx = -1;
3381 }
3382 return nfd;
3383}
3384#endif
3385
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003386typedef enum {
3387 CW_READY,
3388 CW_NOT_READY,
3389 CW_ERROR
3390} channel_wait_result;
3391
Bram Moolenaard04a0202016-01-26 23:30:18 +01003392/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003393 * Check for reading from "fd" with "timeout" msec.
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003394 * Return CW_READY when there is something to read.
3395 * Return CW_NOT_READY when there is nothing to read.
3396 * Return CW_ERROR when there is an error.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003397 */
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003398 static channel_wait_result
Bram Moolenaard8070362016-02-15 21:56:54 +01003399channel_wait(channel_T *channel, sock_T fd, int timeout)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003400{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003401 if (timeout > 0)
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003402 ch_log(channel, "Waiting for up to %d msec", timeout);
Bram Moolenaard8070362016-02-15 21:56:54 +01003403
Bram Moolenaar4f974752019-02-17 17:44:42 +01003404# ifdef MSWIN
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003405 if (fd != channel->CH_SOCK_FD)
Bram Moolenaard8070362016-02-15 21:56:54 +01003406 {
3407 DWORD nread;
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003408 int sleep_time;
Bram Moolenaard8070362016-02-15 21:56:54 +01003409 DWORD deadline = GetTickCount() + timeout;
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003410 int delay = 1;
Bram Moolenaard8070362016-02-15 21:56:54 +01003411
Bram Moolenaarc667da52019-11-30 20:52:27 +01003412 // reading from a pipe, not a socket
Bram Moolenaard8070362016-02-15 21:56:54 +01003413 while (TRUE)
3414 {
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003415 int r = PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL);
3416
3417 if (r && nread > 0)
3418 return CW_READY;
Bram Moolenaar31faed62019-01-22 23:01:40 +01003419
3420 if (channel->ch_named_pipe)
3421 {
3422 DisconnectNamedPipe((HANDLE)fd);
3423 ConnectNamedPipe((HANDLE)fd, NULL);
3424 }
3425 else if (r == 0)
Bram Moolenaarb091f302019-01-19 14:37:00 +01003426 return CW_ERROR;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003427
Bram Moolenaarc667da52019-11-30 20:52:27 +01003428 // perhaps write some buffer lines
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003429 channel_write_any_lines();
3430
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003431 sleep_time = deadline - GetTickCount();
3432 if (sleep_time <= 0)
Bram Moolenaard8070362016-02-15 21:56:54 +01003433 break;
Bram Moolenaarc667da52019-11-30 20:52:27 +01003434 // Wait for a little while. Very short at first, up to 10 msec
3435 // after looping a few times.
Bram Moolenaar84e1d2b2016-03-28 14:20:41 +02003436 if (sleep_time > delay)
3437 sleep_time = delay;
3438 Sleep(sleep_time);
3439 delay = delay * 2;
3440 if (delay > 10)
3441 delay = 10;
Bram Moolenaard8070362016-02-15 21:56:54 +01003442 }
Bram Moolenaard8070362016-02-15 21:56:54 +01003443 }
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003444 else
Bram Moolenaard8070362016-02-15 21:56:54 +01003445#endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003446 {
Bram Moolenaar9186a272016-02-23 19:34:01 +01003447#if defined(HAVE_SELECT)
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003448 struct timeval tval;
3449 fd_set rfds;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003450 fd_set wfds;
3451 int ret;
3452 int maxfd;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003453
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003454 tval.tv_sec = timeout / 1000;
3455 tval.tv_usec = (timeout % 1000) * 1000;
3456 for (;;)
3457 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003458 FD_ZERO(&rfds);
3459 FD_SET((int)fd, &rfds);
3460
Bram Moolenaarc667da52019-11-30 20:52:27 +01003461 // Write lines to a pipe when a pipe can be written to. Need to
3462 // set this every time, some buffers may be done.
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003463 maxfd = (int)fd + 1;
3464 FD_ZERO(&wfds);
3465 maxfd = channel_fill_wfds(maxfd, &wfds);
3466
3467 ret = select(maxfd, &rfds, &wfds, NULL, &tval);
Bram Moolenaar9186a272016-02-23 19:34:01 +01003468# ifdef EINTR
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003469 SOCK_ERRNO;
3470 if (ret == -1 && errno == EINTR)
3471 continue;
Bram Moolenaar9186a272016-02-23 19:34:01 +01003472# endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003473 if (ret > 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003474 {
3475 if (FD_ISSET(fd, &rfds))
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003476 return CW_READY;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003477 channel_write_any_lines();
3478 continue;
3479 }
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003480 break;
3481 }
Bram Moolenaar9186a272016-02-23 19:34:01 +01003482#else
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003483 for (;;)
3484 {
3485 struct pollfd fds[MAX_OPEN_CHANNELS + 1];
3486 int nfd = 1;
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003487
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003488 fds[0].fd = fd;
3489 fds[0].events = POLLIN;
3490 nfd = channel_fill_poll_write(nfd, fds);
3491 if (poll(fds, nfd, timeout) > 0)
3492 {
3493 if (fds[0].revents & POLLIN)
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003494 return CW_READY;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02003495 channel_write_any_lines();
3496 continue;
3497 }
3498 break;
3499 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003500#endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003501 }
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003502 return CW_NOT_READY;
3503}
3504
3505 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003506ch_close_part_on_error(
3507 channel_T *channel, ch_part_T part, int is_err, char *func)
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003508{
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003509 char msg[] = "%s(): Read %s from ch_part[%d], closing";
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003510
3511 if (is_err)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003512 // Do not call emsg(), most likely the other end just exited.
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003513 ch_error(channel, msg, func, "error", part);
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003514 else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003515 ch_log(channel, msg, func, "EOF", part);
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003516
Bram Moolenaarc667da52019-11-30 20:52:27 +01003517 // Queue a "DETACH" netbeans message in the command queue in order to
3518 // terminate the netbeans session later. Do not end the session here
3519 // directly as we may be running in the context of a call to
3520 // netbeans_parse_messages():
3521 // netbeans_parse_messages
3522 // -> autocmd triggered while processing the netbeans cmd
3523 // -> ui_breakcheck
3524 // -> gui event loop or select loop
3525 // -> channel_read()
3526 // Only send "DETACH" for a netbeans channel.
Bram Moolenaar715d2852016-04-30 17:06:31 +02003527 if (channel->ch_nb_close_cb != NULL)
Bram Moolenaar8ddef482016-10-09 15:43:25 +02003528 channel_save(channel, PART_SOCK, (char_u *)DETACH_MSG_RAW,
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003529 (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
3530
Bram Moolenaarc667da52019-11-30 20:52:27 +01003531 // When reading is not possible close this part of the channel. Don't
3532 // close the channel yet, there may be something to read on another part.
3533 // When stdout and stderr use the same FD we get the error only on one of
3534 // them, also close the other.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02003535 if (part == PART_OUT || part == PART_ERR)
3536 {
3537 ch_part_T other = part == PART_OUT ? PART_ERR : PART_OUT;
3538
3539 if (channel->ch_part[part].ch_fd == channel->ch_part[other].ch_fd)
3540 ch_close_part(channel, other);
3541 }
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003542 ch_close_part(channel, part);
Bram Moolenaarbf981ee2016-05-28 13:20:31 +02003543
3544#ifdef FEAT_GUI
Bram Moolenaarc667da52019-11-30 20:52:27 +01003545 // Stop listening to GUI events right away.
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003546 channel_gui_unregister_one(channel, part);
Bram Moolenaarbf981ee2016-05-28 13:20:31 +02003547#endif
Bram Moolenaarcf7ff702016-05-09 17:20:14 +02003548}
3549
3550 static void
3551channel_close_now(channel_T *channel)
3552{
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003553 ch_log(channel, "Closing channel because all readable fds are closed");
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003554 if (channel->ch_nb_close_cb != NULL)
3555 (*channel->ch_nb_close_cb)();
Bram Moolenaar958dc692016-12-01 15:34:12 +01003556 channel_close(channel, TRUE);
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003557}
3558
3559/*
Bram Moolenaar77073442016-02-13 23:23:53 +01003560 * Read from channel "channel" for as long as there is something to read.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003561 * "part" is PART_SOCK, PART_OUT or PART_ERR.
Bram Moolenaar655da312016-05-28 22:22:34 +02003562 * The data is put in the read queue. No callbacks are invoked here.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003563 */
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003564 static void
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003565channel_read(channel_T *channel, ch_part_T part, char *func)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003566{
3567 static char_u *buf = NULL;
3568 int len = 0;
3569 int readlen = 0;
Bram Moolenaard8070362016-02-15 21:56:54 +01003570 sock_T fd;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003571 int use_socket = FALSE;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003572
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003573 fd = channel->ch_part[part].ch_fd;
3574 if (fd == INVALID_FD)
3575 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003576 ch_error(channel, "channel_read() called while %s part is closed",
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003577 part_names[part]);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003578 return;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003579 }
3580 use_socket = fd == channel->CH_SOCK_FD;
Bram Moolenaard04a0202016-01-26 23:30:18 +01003581
Bram Moolenaarc667da52019-11-30 20:52:27 +01003582 // Allocate a buffer to read into.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003583 if (buf == NULL)
3584 {
3585 buf = alloc(MAXMSGSIZE);
3586 if (buf == NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003587 return; // out of memory!
Bram Moolenaard04a0202016-01-26 23:30:18 +01003588 }
3589
Bram Moolenaarc667da52019-11-30 20:52:27 +01003590 // Keep on reading for as long as there is something to read.
3591 // Use select() or poll() to avoid blocking on a message that is exactly
3592 // MAXMSGSIZE long.
Bram Moolenaard04a0202016-01-26 23:30:18 +01003593 for (;;)
3594 {
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003595 if (channel_wait(channel, fd, 0) != CW_READY)
Bram Moolenaard04a0202016-01-26 23:30:18 +01003596 break;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003597 if (use_socket)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003598 len = sock_read(fd, (char *)buf, MAXMSGSIZE);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003599 else
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003600 len = fd_read(fd, (char *)buf, MAXMSGSIZE);
Bram Moolenaard04a0202016-01-26 23:30:18 +01003601 if (len <= 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003602 break; // error or nothing more to read
Bram Moolenaard04a0202016-01-26 23:30:18 +01003603
Bram Moolenaarc667da52019-11-30 20:52:27 +01003604 // Store the read message in the queue.
Bram Moolenaar46c00a62016-03-28 14:11:42 +02003605 channel_save(channel, part, buf, len, FALSE, "RECV ");
Bram Moolenaard04a0202016-01-26 23:30:18 +01003606 readlen += len;
3607 if (len < MAXMSGSIZE)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003608 break; // did read everything that's available
Bram Moolenaard04a0202016-01-26 23:30:18 +01003609 }
3610
Bram Moolenaarc667da52019-11-30 20:52:27 +01003611 // Reading a disconnection (readlen == 0), or an error.
Bram Moolenaarbd73ae12016-02-22 22:19:22 +01003612 if (readlen <= 0)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003613 {
3614 if (!channel->ch_keep_open)
3615 ch_close_part_on_error(channel, part, (len < 0), func);
3616 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01003617#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003618 else if (CH_HAS_GUI && gtk_main_level() > 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +01003619 // signal the main loop that there is something to read
Bram Moolenaard04a0202016-01-26 23:30:18 +01003620 gtk_main_quit();
3621#endif
3622}
3623
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003624/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003625 * Read from RAW or NL "channel"/"part". Blocks until there is something to
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003626 * read or the timeout expires.
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003627 * When "raw" is TRUE don't block waiting on a NL.
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02003628 * Does not trigger timers or handle messages.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003629 * Returns what was read in allocated memory.
3630 * Returns NULL in case of error or timeout.
3631 */
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003632 static char_u *
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003633channel_read_block(
3634 channel_T *channel, ch_part_T part, int timeout, int raw, int *outlen)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003635{
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003636 char_u *buf;
3637 char_u *msg;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003638 ch_mode_T mode = channel->ch_part[part].ch_mode;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003639 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003640 char_u *nl;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003641 readq_T *node;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01003642
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003643 ch_log(channel, "Blocking %s read, timeout: %d msec",
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003644 mode == MODE_RAW ? "RAW" : "NL", timeout);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003645
3646 while (TRUE)
3647 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003648 node = channel_peek(channel, part);
3649 if (node != NULL)
3650 {
3651 if (mode == MODE_RAW || (mode == MODE_NL
3652 && channel_first_nl(node) != NULL))
Bram Moolenaarc667da52019-11-30 20:52:27 +01003653 // got a complete message
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003654 break;
3655 if (channel_collapse(channel, part, mode == MODE_NL) == OK)
3656 continue;
Bram Moolenaarc667da52019-11-30 20:52:27 +01003657 // If not blocking or nothing more is coming then return what we
3658 // have.
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003659 if (raw || fd == INVALID_FD)
3660 break;
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003661 }
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003662
Bram Moolenaarc667da52019-11-30 20:52:27 +01003663 // Wait for up to the channel timeout.
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003664 if (fd == INVALID_FD)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003665 return NULL;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003666 if (channel_wait(channel, fd, timeout) != CW_READY)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003667 {
3668 ch_log(channel, "Timed out");
3669 return NULL;
3670 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003671 channel_read(channel, part, "channel_read_block");
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003672 }
3673
Bram Moolenaarc667da52019-11-30 20:52:27 +01003674 // We have a complete message now.
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003675 if (mode == MODE_RAW || outlen != NULL)
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003676 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003677 msg = channel_get_all(channel, part, outlen);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003678 }
3679 else
3680 {
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003681 char_u *p;
3682
3683 buf = node->rq_buffer;
3684 nl = channel_first_nl(node);
3685
Bram Moolenaarc667da52019-11-30 20:52:27 +01003686 // Convert NUL to NL, the internal representation.
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003687 for (p = buf; (nl == NULL || p < nl) && p < buf + node->rq_buflen; ++p)
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003688 if (*p == NUL)
3689 *p = NL;
3690
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003691 if (nl == NULL)
3692 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003693 // must be a closed channel with missing NL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003694 msg = channel_get(channel, part, NULL);
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003695 }
3696 else if (nl + 1 == buf + node->rq_buflen)
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003697 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003698 // get the whole buffer
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003699 msg = channel_get(channel, part, NULL);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003700 *nl = NUL;
3701 }
3702 else
3703 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003704 // Copy the message into allocated memory and remove it from the
3705 // buffer.
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003706 msg = vim_strnsave(buf, (int)(nl - buf));
Bram Moolenaar5f1032d2016-06-07 22:16:36 +02003707 channel_consume(channel, part, (int)(nl - buf) + 1);
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003708 }
3709 }
Bram Moolenaar71eeb742017-09-13 22:18:01 +02003710 if (ch_log_active())
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02003711 ch_log(channel, "Returning %d bytes", (int)STRLEN(msg));
Bram Moolenaar9a6e33a2016-02-16 19:25:12 +01003712 return msg;
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003713}
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003714
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02003715static int channel_blocking_wait = 0;
3716
3717/*
3718 * Return TRUE if in a blocking wait that might trigger callbacks.
3719 */
3720 int
3721channel_in_blocking_wait(void)
3722{
3723 return channel_blocking_wait > 0;
3724}
3725
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003726/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003727 * Read one JSON message with ID "id" from "channel"/"part" and store the
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003728 * result in "rettv".
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01003729 * When "id" is -1 accept any message;
Bram Moolenaar4d919d72016-02-05 22:36:41 +01003730 * Blocks until the message is received or the timeout is reached.
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003731 * In corner cases this can be called recursively, that is why ch_block_ids is
3732 * a list.
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003733 */
Bram Moolenaar958dc692016-12-01 15:34:12 +01003734 static int
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01003735channel_read_json_block(
Bram Moolenaard6051b52016-02-28 15:49:03 +01003736 channel_T *channel,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003737 ch_part_T part,
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003738 int timeout_arg,
Bram Moolenaard6051b52016-02-28 15:49:03 +01003739 int id,
3740 typval_T **rettv)
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003741{
Bram Moolenaare56bf152016-02-08 23:23:42 +01003742 int more;
Bram Moolenaard8070362016-02-15 21:56:54 +01003743 sock_T fd;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003744 int timeout;
3745 chanpart_T *chanpart = &channel->ch_part[part];
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003746 int retval = FAIL;
Bram Moolenaard7ece102016-02-02 23:23:02 +01003747
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003748 ch_log(channel, "Blocking read JSON for id %d", id);
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02003749 ++channel_blocking_wait;
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003750
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003751 if (id >= 0)
3752 channel_add_block_id(chanpart, id);
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003753
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003754 for (;;)
3755 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01003756 more = channel_parse_json(channel, part);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003757
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003758 // search for message "id"
Bram Moolenaar958dc692016-12-01 15:34:12 +01003759 if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
Bram Moolenaare56bf152016-02-08 23:23:42 +01003760 {
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003761 ch_log(channel, "Received JSON for id %d", id);
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003762 retval = OK;
3763 break;
Bram Moolenaare56bf152016-02-08 23:23:42 +01003764 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003765
Bram Moolenaard7ece102016-02-02 23:23:02 +01003766 if (!more)
3767 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003768 // Handle any other messages in the queue. If done some more
3769 // messages may have arrived.
Bram Moolenaard7ece102016-02-02 23:23:02 +01003770 if (channel_parse_messages())
3771 continue;
3772
Bram Moolenaarc667da52019-11-30 20:52:27 +01003773 // Wait for up to the timeout. If there was an incomplete message
3774 // use the deadline for that.
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003775 timeout = timeout_arg;
Bram Moolenaar88989cc2017-02-06 21:56:09 +01003776 if (chanpart->ch_wait_len > 0)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003777 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01003778#ifdef MSWIN
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003779 timeout = chanpart->ch_deadline - GetTickCount() + 1;
3780#else
3781 {
3782 struct timeval now_tv;
3783
3784 gettimeofday(&now_tv, NULL);
3785 timeout = (chanpart->ch_deadline.tv_sec
3786 - now_tv.tv_sec) * 1000
3787 + (chanpart->ch_deadline.tv_usec
3788 - now_tv.tv_usec) / 1000
3789 + 1;
3790 }
3791#endif
3792 if (timeout < 0)
3793 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01003794 // Something went wrong, channel_parse_json() didn't
3795 // discard message. Cancel waiting.
Bram Moolenaar88989cc2017-02-06 21:56:09 +01003796 chanpart->ch_wait_len = 0;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003797 timeout = timeout_arg;
3798 }
3799 else if (timeout > timeout_arg)
3800 timeout = timeout_arg;
3801 }
3802 fd = chanpart->ch_fd;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003803 if (fd == INVALID_FD
3804 || channel_wait(channel, fd, timeout) != CW_READY)
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003805 {
3806 if (timeout == timeout_arg)
3807 {
3808 if (fd != INVALID_FD)
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003809 ch_log(channel, "Timed out on id %d", id);
Bram Moolenaarba61ac02016-03-20 16:40:37 +01003810 break;
3811 }
3812 }
3813 else
3814 channel_read(channel, part, "channel_read_json_block");
Bram Moolenaard7ece102016-02-02 23:23:02 +01003815 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01003816 }
Bram Moolenaar38ea7842019-06-09 19:51:58 +02003817 if (id >= 0)
3818 channel_remove_block_id(chanpart, id);
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02003819 --channel_blocking_wait;
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003820
Bram Moolenaar8aeec402019-09-15 23:02:04 +02003821 return retval;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01003822}
3823
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003824/*
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02003825 * Get the channel from the argument.
3826 * Returns NULL if the handle is invalid.
3827 * When "check_open" is TRUE check that the channel can be used.
3828 * When "reading" is TRUE "check_open" considers typeahead useful.
3829 * "part" is used to check typeahead, when PART_COUNT use the default part.
3830 */
3831 static channel_T *
3832get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part)
3833{
3834 channel_T *channel = NULL;
3835 int has_readahead = FALSE;
3836
3837 if (tv->v_type == VAR_JOB)
3838 {
3839 if (tv->vval.v_job != NULL)
3840 channel = tv->vval.v_job->jv_channel;
3841 }
3842 else if (tv->v_type == VAR_CHANNEL)
3843 {
3844 channel = tv->vval.v_channel;
3845 }
3846 else
3847 {
3848 semsg(_(e_invarg2), tv_get_string(tv));
3849 return NULL;
3850 }
3851 if (channel != NULL && reading)
3852 has_readahead = channel_has_readahead(channel,
3853 part != PART_COUNT ? part : channel_part_read(channel));
3854
3855 if (check_open && (channel == NULL || (!channel_is_open(channel)
3856 && !(reading && has_readahead))))
3857 {
3858 emsg(_("E906: not an open channel"));
3859 return NULL;
3860 }
3861 return channel;
3862}
3863
3864/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003865 * Common for ch_read() and ch_readraw().
3866 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02003867 static void
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003868common_channel_read(typval_T *argvars, typval_T *rettv, int raw, int blob)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003869{
3870 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003871 ch_part_T part = PART_COUNT;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003872 jobopt_T opt;
3873 int mode;
3874 int timeout;
3875 int id = -1;
3876 typval_T *listtv = NULL;
3877
Bram Moolenaarc667da52019-11-30 20:52:27 +01003878 // return an empty string by default
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003879 rettv->v_type = VAR_STRING;
3880 rettv->vval.v_string = NULL;
3881
3882 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02003883 if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID, 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003884 == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003885 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003886
Bram Moolenaar437905c2016-04-26 19:01:05 +02003887 if (opt.jo_set & JO_PART)
3888 part = opt.jo_part;
3889 channel = get_channel_arg(&argvars[0], TRUE, TRUE, part);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003890 if (channel != NULL)
3891 {
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003892 if (part == PART_COUNT)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003893 part = channel_part_read(channel);
3894 mode = channel_get_mode(channel, part);
3895 timeout = channel_get_timeout(channel, part);
3896 if (opt.jo_set & JO_TIMEOUT)
3897 timeout = opt.jo_timeout;
3898
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003899 if (blob)
3900 {
3901 int outlen = 0;
3902 char_u *p = channel_read_block(channel, part,
3903 timeout, TRUE, &outlen);
3904 if (p != NULL)
3905 {
3906 blob_T *b = blob_alloc();
3907
3908 if (b != NULL)
3909 {
3910 b->bv_ga.ga_len = outlen;
3911 if (ga_grow(&b->bv_ga, outlen) == FAIL)
3912 blob_free(b);
3913 else
3914 {
3915 memcpy(b->bv_ga.ga_data, p, outlen);
3916 rettv_blob_set(rettv, b);
3917 }
3918 }
3919 vim_free(p);
3920 }
3921 }
3922 else if (raw || mode == MODE_RAW || mode == MODE_NL)
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01003923 rettv->vval.v_string = channel_read_block(channel, part,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003924 timeout, raw, NULL);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003925 else
3926 {
3927 if (opt.jo_set & JO_ID)
3928 id = opt.jo_id;
3929 channel_read_json_block(channel, part, timeout, id, &listtv);
3930 if (listtv != NULL)
3931 {
3932 *rettv = *listtv;
3933 vim_free(listtv);
3934 }
3935 else
3936 {
3937 rettv->v_type = VAR_SPECIAL;
3938 rettv->vval.v_number = VVAL_NONE;
3939 }
3940 }
3941 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02003942
3943theend:
3944 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01003945}
3946
Bram Moolenaar80a8d382020-05-03 22:57:32 +02003947#if defined(MSWIN) || defined(__HAIKU__) || defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003948/*
3949 * Check the channels for anything that is ready to be read.
3950 * The data is put in the read queue.
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003951 * if "only_keep_open" is TRUE only check channels where ch_keep_open is set.
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003952 */
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003953 void
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003954channel_handle_events(int only_keep_open)
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003955{
3956 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003957 ch_part_T part;
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003958 sock_T fd;
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003959
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003960 FOR_ALL_CHANNELS(channel)
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003961 {
Bram Moolenaar13ebb032017-08-26 22:02:51 +02003962 if (only_keep_open && !channel->ch_keep_open)
3963 continue;
3964
Bram Moolenaarc667da52019-11-30 20:52:27 +01003965 // check the socket and pipes
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003966 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003967 {
3968 fd = channel->ch_part[part].ch_fd;
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003969 if (fd != INVALID_FD)
3970 {
3971 int r = channel_wait(channel, fd, 0);
3972
3973 if (r == CW_READY)
3974 channel_read(channel, part, "channel_handle_events");
3975 else if (r == CW_ERROR)
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02003976 ch_close_part_on_error(channel, part, TRUE,
3977 "channel_handle_events");
Bram Moolenaarb2658a12016-04-26 17:16:24 +02003978 }
Bram Moolenaarb7522a22016-02-21 17:20:55 +01003979 }
Bram Moolenaar80a8d382020-05-03 22:57:32 +02003980
3981# ifdef __HAIKU__
3982 // Workaround for Haiku: Since select/poll cannot detect EOF from tty,
3983 // should close fds when the job has finished if 'channel' connects to
3984 // the pty.
3985 if (channel->ch_job != NULL)
3986 {
3987 job_T *job = channel->ch_job;
3988
3989 if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED)
3990 for (part = PART_SOCK; part < PART_COUNT; ++part)
3991 ch_close_part(channel, part);
3992 }
3993# endif
Bram Moolenaared5a78e2016-02-19 21:05:03 +01003994 }
3995}
Bram Moolenaar80a8d382020-05-03 22:57:32 +02003996#endif
Bram Moolenaar85be35f2016-01-27 21:08:18 +01003997
Bram Moolenaar4ab79682017-08-27 14:50:47 +02003998# if defined(FEAT_GUI) || defined(PROTO)
3999/*
4000 * Return TRUE when there is any channel with a keep_open flag.
4001 */
4002 int
4003channel_any_keep_open()
4004{
4005 channel_T *channel;
4006
Bram Moolenaaraeea7212020-04-02 18:50:46 +02004007 FOR_ALL_CHANNELS(channel)
Bram Moolenaar4ab79682017-08-27 14:50:47 +02004008 if (channel->ch_keep_open)
4009 return TRUE;
4010 return FALSE;
4011}
4012# endif
4013
Bram Moolenaard04a0202016-01-26 23:30:18 +01004014/*
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004015 * Set "channel"/"part" to non-blocking.
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02004016 * Only works for sockets and pipes.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004017 */
4018 void
4019channel_set_nonblock(channel_T *channel, ch_part_T part)
4020{
4021 chanpart_T *ch_part = &channel->ch_part[part];
Bram Moolenaar0b146882018-09-06 16:27:24 +02004022 int fd = ch_part->ch_fd;
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004023
4024 if (fd != INVALID_FD)
4025 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01004026#ifdef MSWIN
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02004027 u_long val = 1;
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004028
Bram Moolenaarf66a2cd2017-08-18 21:53:22 +02004029 ioctlsocket(fd, FIONBIO, &val);
4030#else
Bram Moolenaardc926dd2017-08-19 21:26:44 +02004031 (void)fcntl(fd, F_SETFL, O_NONBLOCK);
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004032#endif
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004033 ch_part->ch_nonblocking = TRUE;
4034 }
4035}
4036
4037/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004038 * Write "buf" (NUL terminated string) to "channel"/"part".
Bram Moolenaard04a0202016-01-26 23:30:18 +01004039 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01004040 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +01004041 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01004042 int
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01004043channel_send(
4044 channel_T *channel,
4045 ch_part_T part,
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004046 char_u *buf_arg,
4047 int len_arg,
Bram Moolenaar79cbdcb2016-11-11 21:14:03 +01004048 char *fun)
Bram Moolenaard04a0202016-01-26 23:30:18 +01004049{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004050 int res;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004051 sock_T fd;
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004052 chanpart_T *ch_part = &channel->ch_part[part];
4053 int did_use_queue = FALSE;
Bram Moolenaard04a0202016-01-26 23:30:18 +01004054
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004055 fd = ch_part->ch_fd;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004056 if (fd == INVALID_FD)
Bram Moolenaard04a0202016-01-26 23:30:18 +01004057 {
4058 if (!channel->ch_error && fun != NULL)
4059 {
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02004060 ch_error(channel, "%s(): write while not connected", fun);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004061 semsg(_("E630: %s(): write while not connected"), fun);
Bram Moolenaard04a0202016-01-26 23:30:18 +01004062 }
4063 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01004064 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +01004065 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01004066
Bram Moolenaar0b146882018-09-06 16:27:24 +02004067 if (channel->ch_nonblock && !ch_part->ch_nonblocking)
4068 channel_set_nonblock(channel, part);
4069
Bram Moolenaar71eeb742017-09-13 22:18:01 +02004070 if (ch_log_active())
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004071 {
Bram Moolenaar4b16ee72018-08-09 22:15:34 +02004072 ch_log_lead("SEND ", channel, part);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004073 fprintf(log_fd, "'");
Bram Moolenaar42335f52018-09-13 15:33:43 +02004074 vim_ignored = (int)fwrite(buf_arg, len_arg, 1, log_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004075 fprintf(log_fd, "'\n");
4076 fflush(log_fd);
Bram Moolenaar101e9922019-09-25 21:43:11 +02004077 did_repeated_msg = 0;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004078 }
4079
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004080 for (;;)
Bram Moolenaard04a0202016-01-26 23:30:18 +01004081 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004082 writeq_T *wq = &ch_part->ch_writeque;
4083 char_u *buf;
4084 int len;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +01004085
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004086 if (wq->wq_next != NULL)
4087 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004088 // first write what was queued
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004089 buf = wq->wq_next->wq_ga.ga_data;
4090 len = wq->wq_next->wq_ga.ga_len;
4091 did_use_queue = TRUE;
4092 }
4093 else
4094 {
4095 if (len_arg == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +01004096 // nothing to write, called from channel_select_check()
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004097 return OK;
4098 buf = buf_arg;
4099 len = len_arg;
4100 }
4101
4102 if (part == PART_SOCK)
4103 res = sock_write(fd, (char *)buf, len);
4104 else
Bram Moolenaar31faed62019-01-22 23:01:40 +01004105 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004106 res = fd_write(fd, (char *)buf, len);
Bram Moolenaar4f974752019-02-17 17:44:42 +01004107#ifdef MSWIN
Bram Moolenaar31faed62019-01-22 23:01:40 +01004108 if (channel->ch_named_pipe && res < 0)
4109 {
4110 DisconnectNamedPipe((HANDLE)fd);
4111 ConnectNamedPipe((HANDLE)fd, NULL);
4112 }
4113#endif
4114 }
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004115 if (res < 0 && (errno == EWOULDBLOCK
4116#ifdef EAGAIN
4117 || errno == EAGAIN
4118#endif
4119 ))
Bram Moolenaarc667da52019-11-30 20:52:27 +01004120 res = 0; // nothing got written
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004121
4122 if (res >= 0 && ch_part->ch_nonblocking)
4123 {
4124 writeq_T *entry = wq->wq_next;
4125
4126 if (did_use_queue)
4127 ch_log(channel, "Sent %d bytes now", res);
4128 if (res == len)
4129 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004130 // Wrote all the buf[len] bytes.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004131 if (entry != NULL)
4132 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004133 // Remove the entry from the write queue.
Bram Moolenaaraba680a2017-09-09 16:42:53 +02004134 remove_from_writeque(wq, entry);
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004135 continue;
4136 }
4137 if (did_use_queue)
4138 ch_log(channel, "Write queue empty");
4139 }
4140 else
4141 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004142 // Wrote only buf[res] bytes, can't write more now.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004143 if (entry != NULL)
4144 {
4145 if (res > 0)
4146 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004147 // Remove the bytes that were written.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004148 mch_memmove(entry->wq_ga.ga_data,
4149 (char *)entry->wq_ga.ga_data + res,
4150 len - res);
4151 entry->wq_ga.ga_len -= res;
4152 }
4153 buf = buf_arg;
4154 len = len_arg;
4155 }
4156 else
4157 {
4158 buf += res;
4159 len -= res;
4160 }
4161 ch_log(channel, "Adding %d bytes to the write queue", len);
4162
Bram Moolenaarc667da52019-11-30 20:52:27 +01004163 // Append the not written bytes of the argument to the write
4164 // buffer. Limit entries to 4000 bytes.
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004165 if (wq->wq_prev != NULL
4166 && wq->wq_prev->wq_ga.ga_len + len < 4000)
4167 {
4168 writeq_T *last = wq->wq_prev;
4169
Bram Moolenaarc667da52019-11-30 20:52:27 +01004170 // append to the last entry
Bram Moolenaar0d071552019-07-08 22:04:03 +02004171 if (len > 0 && ga_grow(&last->wq_ga, len) == OK)
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004172 {
4173 mch_memmove((char *)last->wq_ga.ga_data
4174 + last->wq_ga.ga_len,
4175 buf, len);
4176 last->wq_ga.ga_len += len;
4177 }
4178 }
4179 else
4180 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004181 writeq_T *last = ALLOC_ONE(writeq_T);
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004182
4183 if (last != NULL)
4184 {
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004185 last->wq_prev = wq->wq_prev;
4186 last->wq_next = NULL;
4187 if (wq->wq_prev == NULL)
4188 wq->wq_next = last;
4189 else
4190 wq->wq_prev->wq_next = last;
4191 wq->wq_prev = last;
4192 ga_init2(&last->wq_ga, 1, 1000);
Bram Moolenaar0d071552019-07-08 22:04:03 +02004193 if (len > 0 && ga_grow(&last->wq_ga, len) == OK)
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004194 {
4195 mch_memmove(last->wq_ga.ga_data, buf, len);
4196 last->wq_ga.ga_len = len;
4197 }
4198 }
4199 }
4200 }
4201 }
4202 else if (res != len)
4203 {
4204 if (!channel->ch_error && fun != NULL)
4205 {
4206 ch_error(channel, "%s(): write failed", fun);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004207 semsg(_("E631: %s(): write failed"), fun);
Bram Moolenaar97bd5e62017-08-18 20:50:30 +02004208 }
4209 channel->ch_error = TRUE;
4210 return FAIL;
4211 }
4212
4213 channel->ch_error = FALSE;
4214 return OK;
4215 }
Bram Moolenaard04a0202016-01-26 23:30:18 +01004216}
4217
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004218/*
4219 * Common for "ch_sendexpr()" and "ch_sendraw()".
4220 * Returns the channel if the caller should read the response.
Bram Moolenaaraad30bb2016-06-26 17:31:03 +02004221 * Sets "part_read" to the read fd.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004222 * Otherwise returns NULL.
4223 */
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004224 static channel_T *
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004225send_common(
4226 typval_T *argvars,
4227 char_u *text,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004228 int len,
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004229 int id,
4230 int eval,
4231 jobopt_T *opt,
4232 char *fun,
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004233 ch_part_T *part_read)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004234{
4235 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004236 ch_part_T part_send;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004237
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004238 clear_job_options(opt);
Bram Moolenaar437905c2016-04-26 19:01:05 +02004239 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004240 if (channel == NULL)
4241 return NULL;
4242 part_send = channel_part_send(channel);
4243 *part_read = channel_part_read(channel);
4244
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004245 if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT, 0) == FAIL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004246 return NULL;
4247
Bram Moolenaarc667da52019-11-30 20:52:27 +01004248 // Set the callback. An empty callback means no callback and not reading
4249 // the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
4250 // allowed.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02004251 if (opt->jo_callback.cb_name != NULL && *opt->jo_callback.cb_name != NUL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004252 {
4253 if (eval)
4254 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004255 semsg(_("E917: Cannot use a callback with %s()"), fun);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004256 return NULL;
4257 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02004258 channel_set_req_callback(channel, *part_read, &opt->jo_callback, id);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004259 }
4260
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004261 if (channel_send(channel, part_send, text, len, fun) == OK
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02004262 && opt->jo_callback.cb_name == NULL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004263 return channel;
4264 return NULL;
4265}
4266
4267/*
4268 * common for "ch_evalexpr()" and "ch_sendexpr()"
4269 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004270 static void
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004271ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
4272{
4273 char_u *text;
4274 typval_T *listtv;
4275 channel_T *channel;
4276 int id;
4277 ch_mode_T ch_mode;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004278 ch_part_T part_send;
4279 ch_part_T part_read;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004280 jobopt_T opt;
4281 int timeout;
4282
Bram Moolenaarc667da52019-11-30 20:52:27 +01004283 // return an empty string by default
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004284 rettv->v_type = VAR_STRING;
4285 rettv->vval.v_string = NULL;
4286
Bram Moolenaar437905c2016-04-26 19:01:05 +02004287 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004288 if (channel == NULL)
4289 return;
4290 part_send = channel_part_send(channel);
4291
4292 ch_mode = channel_get_mode(channel, part_send);
4293 if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
4294 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004295 emsg(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004296 return;
4297 }
4298
Bram Moolenaare9d6a292016-03-20 19:31:33 +01004299 id = ++channel->ch_last_msg_id;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004300 text = json_encode_nr_expr(id, &argvars[1],
Bram Moolenaarf1f07922016-08-26 17:58:53 +02004301 (ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004302 if (text == NULL)
4303 return;
4304
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004305 channel = send_common(argvars, text, (int)STRLEN(text), id, eval, &opt,
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004306 eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
4307 vim_free(text);
4308 if (channel != NULL && eval)
4309 {
4310 if (opt.jo_set & JO_TIMEOUT)
4311 timeout = opt.jo_timeout;
4312 else
4313 timeout = channel_get_timeout(channel, part_read);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004314 if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
4315 == OK)
4316 {
4317 list_T *list = listtv->vval.v_list;
4318
Bram Moolenaarc667da52019-11-30 20:52:27 +01004319 // Move the item from the list and then change the type to
4320 // avoid the value being freed.
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004321 *rettv = list->lv_u.mat.lv_last->li_tv;
4322 list->lv_u.mat.lv_last->li_tv.v_type = VAR_NUMBER;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004323 free_tv(listtv);
4324 }
4325 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004326 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004327}
4328
4329/*
4330 * common for "ch_evalraw()" and "ch_sendraw()"
4331 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004332 static void
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004333ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
4334{
4335 char_u buf[NUMBUFLEN];
4336 char_u *text;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004337 int len;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004338 channel_T *channel;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004339 ch_part_T part_read;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004340 jobopt_T opt;
4341 int timeout;
4342
Bram Moolenaarc667da52019-11-30 20:52:27 +01004343 // return an empty string by default
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004344 rettv->v_type = VAR_STRING;
4345 rettv->vval.v_string = NULL;
4346
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004347 if (argvars[1].v_type == VAR_BLOB)
4348 {
4349 text = argvars[1].vval.v_blob->bv_ga.ga_data;
4350 len = argvars[1].vval.v_blob->bv_ga.ga_len;
4351 }
4352 else
4353 {
4354 text = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaare4074252019-01-17 14:31:14 +01004355 len = (int)STRLEN(text);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004356 }
4357 channel = send_common(argvars, text, len, 0, eval, &opt,
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004358 eval ? "ch_evalraw" : "ch_sendraw", &part_read);
4359 if (channel != NULL && eval)
4360 {
4361 if (opt.jo_set & JO_TIMEOUT)
4362 timeout = opt.jo_timeout;
4363 else
4364 timeout = channel_get_timeout(channel, part_read);
Bram Moolenaar620ca2d2017-12-09 19:13:13 +01004365 rettv->vval.v_string = channel_read_block(channel, part_read,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004366 timeout, TRUE, NULL);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004367 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004368 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004369}
4370
Bram Moolenaarc667da52019-11-30 20:52:27 +01004371#define KEEP_OPEN_TIME 20 // msec
Bram Moolenaarf3360612017-10-01 16:21:31 +02004372
Bram Moolenaar8aeec402019-09-15 23:02:04 +02004373#if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004374/*
4375 * Add open channels to the poll struct.
4376 * Return the adjusted struct index.
4377 * The type of "fds" is hidden to avoid problems with the function proto.
4378 */
4379 int
Bram Moolenaarf3360612017-10-01 16:21:31 +02004380channel_poll_setup(int nfd_in, void *fds_in, int *towait)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004381{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004382 int nfd = nfd_in;
4383 channel_T *channel;
4384 struct pollfd *fds = fds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004385 ch_part_T part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004386
Bram Moolenaaraeea7212020-04-02 18:50:46 +02004387 FOR_ALL_CHANNELS(channel)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004388 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004389 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004390 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004391 chanpart_T *ch_part = &channel->ch_part[part];
4392
4393 if (ch_part->ch_fd != INVALID_FD)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004394 {
Bram Moolenaarf3360612017-10-01 16:21:31 +02004395 if (channel->ch_keep_open)
4396 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004397 // For unknown reason poll() returns immediately for a
4398 // keep-open channel. Instead of adding it to the fds add
4399 // a short timeout and check, like polling.
Bram Moolenaarf3360612017-10-01 16:21:31 +02004400 if (*towait < 0 || *towait > KEEP_OPEN_TIME)
4401 *towait = KEEP_OPEN_TIME;
4402 }
4403 else
4404 {
4405 ch_part->ch_poll_idx = nfd;
4406 fds[nfd].fd = ch_part->ch_fd;
4407 fds[nfd].events = POLLIN;
4408 nfd++;
4409 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004410 }
4411 else
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004412 channel->ch_part[part].ch_poll_idx = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004413 }
4414 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004415
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004416 nfd = channel_fill_poll_write(nfd, fds);
4417
Bram Moolenaare0874f82016-01-24 20:36:41 +01004418 return nfd;
4419}
4420
4421/*
4422 * The type of "fds" is hidden to avoid problems with the function proto.
4423 */
4424 int
4425channel_poll_check(int ret_in, void *fds_in)
4426{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004427 int ret = ret_in;
4428 channel_T *channel;
4429 struct pollfd *fds = fds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004430 ch_part_T part;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004431 int idx;
4432 chanpart_T *in_part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004433
Bram Moolenaaraeea7212020-04-02 18:50:46 +02004434 FOR_ALL_CHANNELS(channel)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004435 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004436 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004437 {
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004438 idx = channel->ch_part[part].ch_poll_idx;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004439
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004440 if (ret > 0 && idx != -1 && (fds[idx].revents & POLLIN))
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004441 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004442 channel_read(channel, part, "channel_poll_check");
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004443 --ret;
4444 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02004445 else if (channel->ch_part[part].ch_fd != INVALID_FD
4446 && channel->ch_keep_open)
4447 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004448 // polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02004449 channel_read(channel, part, "channel_poll_check_keep_open");
4450 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004451 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004452
4453 in_part = &channel->ch_part[PART_IN];
4454 idx = in_part->ch_poll_idx;
4455 if (ret > 0 && idx != -1 && (fds[idx].revents & POLLOUT))
4456 {
Bram Moolenaar683b7962017-08-19 15:51:59 +02004457 channel_write_input(channel);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004458 --ret;
4459 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004460 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004461
4462 return ret;
4463}
Bram Moolenaarc667da52019-11-30 20:52:27 +01004464#endif // UNIX && !HAVE_SELECT
Bram Moolenaare0874f82016-01-24 20:36:41 +01004465
Bram Moolenaar8aeec402019-09-15 23:02:04 +02004466#if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaarf3360612017-10-01 16:21:31 +02004467
Bram Moolenaare0874f82016-01-24 20:36:41 +01004468/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004469 * The "fd_set" type is hidden to avoid problems with the function proto.
Bram Moolenaare0874f82016-01-24 20:36:41 +01004470 */
4471 int
Bram Moolenaarf3360612017-10-01 16:21:31 +02004472channel_select_setup(
4473 int maxfd_in,
4474 void *rfds_in,
4475 void *wfds_in,
4476 struct timeval *tv,
4477 struct timeval **tvp)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004478{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004479 int maxfd = maxfd_in;
4480 channel_T *channel;
4481 fd_set *rfds = rfds_in;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004482 fd_set *wfds = wfds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004483 ch_part_T part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004484
Bram Moolenaaraeea7212020-04-02 18:50:46 +02004485 FOR_ALL_CHANNELS(channel)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004486 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004487 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004488 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004489 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004490
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004491 if (fd != INVALID_FD)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004492 {
Bram Moolenaarf3360612017-10-01 16:21:31 +02004493 if (channel->ch_keep_open)
4494 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004495 // For unknown reason select() returns immediately for a
4496 // keep-open channel. Instead of adding it to the rfds add
4497 // a short timeout and check, like polling.
Bram Moolenaarf3360612017-10-01 16:21:31 +02004498 if (*tvp == NULL || tv->tv_sec > 0
4499 || tv->tv_usec > KEEP_OPEN_TIME * 1000)
4500 {
4501 *tvp = tv;
4502 tv->tv_sec = 0;
4503 tv->tv_usec = KEEP_OPEN_TIME * 1000;
4504 }
4505 }
4506 else
4507 {
4508 FD_SET((int)fd, rfds);
4509 if (maxfd < (int)fd)
4510 maxfd = (int)fd;
4511 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004512 }
4513 }
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004514 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004515
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004516 maxfd = channel_fill_wfds(maxfd, wfds);
4517
Bram Moolenaare0874f82016-01-24 20:36:41 +01004518 return maxfd;
4519}
4520
4521/*
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004522 * The "fd_set" type is hidden to avoid problems with the function proto.
Bram Moolenaare0874f82016-01-24 20:36:41 +01004523 */
4524 int
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004525channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
Bram Moolenaare0874f82016-01-24 20:36:41 +01004526{
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004527 int ret = ret_in;
4528 channel_T *channel;
4529 fd_set *rfds = rfds_in;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004530 fd_set *wfds = wfds_in;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004531 ch_part_T part;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004532 chanpart_T *in_part;
Bram Moolenaare0874f82016-01-24 20:36:41 +01004533
Bram Moolenaaraeea7212020-04-02 18:50:46 +02004534 FOR_ALL_CHANNELS(channel)
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004535 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004536 for (part = PART_SOCK; part < PART_IN; ++part)
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004537 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004538 sock_T fd = channel->ch_part[part].ch_fd;
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004539
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004540 if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds))
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004541 {
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004542 channel_read(channel, part, "channel_select_check");
Bram Moolenaar3c518402017-09-08 20:47:00 +02004543 FD_CLR(fd, rfds);
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004544 --ret;
4545 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02004546 else if (fd != INVALID_FD && channel->ch_keep_open)
4547 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004548 // polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02004549 channel_read(channel, part, "channel_select_check_keep_open");
4550 }
Bram Moolenaar7b3ca762016-02-14 19:13:43 +01004551 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004552
4553 in_part = &channel->ch_part[PART_IN];
4554 if (ret > 0 && in_part->ch_fd != INVALID_FD
4555 && FD_ISSET(in_part->ch_fd, wfds))
4556 {
Bram Moolenaar8aeec402019-09-15 23:02:04 +02004557 // Clear the flag first, ch_fd may change in channel_write_input().
Bram Moolenaar3c518402017-09-08 20:47:00 +02004558 FD_CLR(in_part->ch_fd, wfds);
Bram Moolenaar9af97782018-04-03 12:51:01 +02004559 channel_write_input(channel);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02004560 --ret;
4561 }
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004562
4563# ifdef __HAIKU__
4564 // Workaround for Haiku: Since select/poll cannot detect EOF from tty,
4565 // should close fds when the job has finished if 'channel' connects to
4566 // the pty.
4567 if (channel->ch_job != NULL)
4568 {
4569 job_T *job = channel->ch_job;
4570
4571 if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED)
4572 for (part = PART_SOCK; part < PART_COUNT; ++part)
4573 ch_close_part(channel, part);
4574 }
4575# endif
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01004576 }
Bram Moolenaare0874f82016-01-24 20:36:41 +01004577
4578 return ret;
4579}
Bram Moolenaar8aeec402019-09-15 23:02:04 +02004580#endif // !MSWIN && HAVE_SELECT
Bram Moolenaare0874f82016-01-24 20:36:41 +01004581
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004582/*
Bram Moolenaard7ece102016-02-02 23:23:02 +01004583 * Execute queued up commands.
Bram Moolenaar8aeec402019-09-15 23:02:04 +02004584 * Invoked from the main loop when it's safe to execute received commands,
4585 * and during a blocking wait for ch_evalexpr().
Bram Moolenaard7ece102016-02-02 23:23:02 +01004586 * Return TRUE when something was done.
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004587 */
Bram Moolenaard7ece102016-02-02 23:23:02 +01004588 int
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004589channel_parse_messages(void)
4590{
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004591 channel_T *channel = first_channel;
4592 int ret = FALSE;
4593 int r;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004594 ch_part_T part = PART_SOCK;
Bram Moolenaar09c56902020-03-28 18:06:31 +01004595 static int recursive = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004596#ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004597 elapsed_T start_tv;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004598#endif
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004599
Bram Moolenaara9c3a302020-03-26 16:03:45 +01004600 // The code below may invoke callbacks, which might call us back.
Bram Moolenaar09c56902020-03-28 18:06:31 +01004601 // In a recursive call channels will not be closed.
4602 ++recursive;
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004603 ++safe_to_invoke_callback;
4604
Bram Moolenaara9c3a302020-03-26 16:03:45 +01004605#ifdef ELAPSED_FUNC
4606 ELAPSED_INIT(start_tv);
4607#endif
4608
Bram Moolenaarc667da52019-11-30 20:52:27 +01004609 // Only do this message when another message was given, otherwise we get
4610 // lots of them.
Bram Moolenaar101e9922019-09-25 21:43:11 +02004611 if ((did_repeated_msg & REPEATED_MSG_LOOKING) == 0)
Bram Moolenaard0b65022016-03-06 21:50:33 +01004612 {
4613 ch_log(NULL, "looking for messages on channels");
Bram Moolenaar101e9922019-09-25 21:43:11 +02004614 // now we should also give the message for SafeState
4615 did_repeated_msg = REPEATED_MSG_LOOKING;
Bram Moolenaard0b65022016-03-06 21:50:33 +01004616 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004617 while (channel != NULL)
4618 {
Bram Moolenaar09c56902020-03-28 18:06:31 +01004619 if (recursive == 1)
Bram Moolenaarcf7ff702016-05-09 17:20:14 +02004620 {
Bram Moolenaar09c56902020-03-28 18:06:31 +01004621 if (channel_can_close(channel))
4622 {
4623 channel->ch_to_be_closed = (1U << PART_COUNT);
4624 channel_close_now(channel);
4625 // channel may have been freed, start over
4626 channel = first_channel;
4627 continue;
4628 }
4629 if (channel->ch_to_be_freed || channel->ch_killing)
4630 {
4631 channel_free_contents(channel);
4632 if (channel->ch_job != NULL)
4633 channel->ch_job->jv_channel = NULL;
Bram Moolenaar71658f72020-03-24 20:35:19 +01004634
Bram Moolenaar09c56902020-03-28 18:06:31 +01004635 // free the channel and then start over
4636 channel_free_channel(channel);
4637 channel = first_channel;
4638 continue;
4639 }
4640 if (channel->ch_refcount == 0 && !channel_still_useful(channel))
4641 {
4642 // channel is no longer useful, free it
4643 channel_free(channel);
4644 channel = first_channel;
4645 part = PART_SOCK;
4646 continue;
4647 }
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004648 }
Bram Moolenaar09c56902020-03-28 18:06:31 +01004649
Bram Moolenaar187db502016-02-27 14:44:26 +01004650 if (channel->ch_part[part].ch_fd != INVALID_FD
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004651 || channel_has_readahead(channel, part))
Bram Moolenaard7ece102016-02-02 23:23:02 +01004652 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004653 // Increase the refcount, in case the handler causes the channel
4654 // to be unreferenced or closed.
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004655 ++channel->ch_refcount;
4656 r = may_invoke_callback(channel, part);
4657 if (r == OK)
4658 ret = TRUE;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004659 if (channel_unref(channel) || (r == OK
4660#ifdef ELAPSED_FUNC
Bram Moolenaarc667da52019-11-30 20:52:27 +01004661 // Limit the time we loop here to 100 msec, otherwise
4662 // Vim becomes unresponsive when the callback takes
4663 // more than a bit of time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004664 && ELAPSED_FUNC(start_tv) < 100L
4665#endif
4666 ))
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004667 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01004668 // channel was freed or something was done, start over
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004669 channel = first_channel;
4670 part = PART_SOCK;
4671 continue;
4672 }
Bram Moolenaard7ece102016-02-02 23:23:02 +01004673 }
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004674 if (part < PART_ERR)
4675 ++part;
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004676 else
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004677 {
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004678 channel = channel->ch_next;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004679 part = PART_SOCK;
4680 }
Bram Moolenaar3bece9f2016-02-15 20:39:46 +01004681 }
Bram Moolenaar187db502016-02-27 14:44:26 +01004682
Bram Moolenaar7f7c3322016-04-18 19:27:24 +02004683 if (channel_need_redraw)
Bram Moolenaar187db502016-02-27 14:44:26 +01004684 {
4685 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02004686 redraw_after_callback(TRUE);
Bram Moolenaar187db502016-02-27 14:44:26 +01004687 }
4688
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004689 --safe_to_invoke_callback;
Bram Moolenaar09c56902020-03-28 18:06:31 +01004690 --recursive;
Bram Moolenaarfb6ffc72016-05-09 17:58:04 +02004691
Bram Moolenaard7ece102016-02-02 23:23:02 +01004692 return ret;
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01004693}
4694
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01004695/*
Bram Moolenaar8a8199e2016-11-26 15:13:33 +01004696 * Return TRUE if any channel has readahead. That means we should not block on
4697 * waiting for input.
4698 */
4699 int
4700channel_any_readahead(void)
4701{
4702 channel_T *channel = first_channel;
4703 ch_part_T part = PART_SOCK;
4704
4705 while (channel != NULL)
4706 {
4707 if (channel_has_readahead(channel, part))
4708 return TRUE;
4709 if (part < PART_ERR)
4710 ++part;
4711 else
4712 {
4713 channel = channel->ch_next;
4714 part = PART_SOCK;
4715 }
4716 }
4717 return FALSE;
4718}
4719
4720/*
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01004721 * Mark references to lists used in channels.
4722 */
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004723 int
4724set_ref_in_channel(int copyID)
4725{
Bram Moolenaar77073442016-02-13 23:23:53 +01004726 int abort = FALSE;
4727 channel_T *channel;
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004728 typval_T tv;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004729
Bram Moolenaar75a1a942019-06-20 03:45:36 +02004730 for (channel = first_channel; !abort && channel != NULL;
4731 channel = channel->ch_next)
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004732 if (channel_still_useful(channel))
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004733 {
Bram Moolenaarb8d49052016-05-01 14:22:16 +02004734 tv.v_type = VAR_CHANNEL;
4735 tv.vval.v_channel = channel;
4736 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004737 }
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +01004738 return abort;
4739}
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004740
4741/*
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004742 * Return the "part" to write to for "channel".
4743 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004744 static ch_part_T
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004745channel_part_send(channel_T *channel)
4746{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004747 if (channel->CH_SOCK_FD == INVALID_FD)
4748 return PART_IN;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004749 return PART_SOCK;
4750}
4751
4752/*
4753 * Return the default "part" to read from for "channel".
4754 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004755 static ch_part_T
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004756channel_part_read(channel_T *channel)
4757{
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004758 if (channel->CH_SOCK_FD == INVALID_FD)
4759 return PART_OUT;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004760 return PART_SOCK;
4761}
4762
4763/*
4764 * Return the mode of "channel"/"part"
Bram Moolenaar77073442016-02-13 23:23:53 +01004765 * If "channel" is invalid returns MODE_JSON.
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004766 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004767 static ch_mode_T
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004768channel_get_mode(channel_T *channel, ch_part_T part)
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004769{
Bram Moolenaar77073442016-02-13 23:23:53 +01004770 if (channel == NULL)
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004771 return MODE_JSON;
Bram Moolenaar42d38a22016-02-20 18:18:59 +01004772 return channel->ch_part[part].ch_mode;
Bram Moolenaarae8eb3c2016-02-07 21:59:26 +01004773}
4774
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01004775/*
4776 * Return the timeout of "channel"/"part"
4777 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004778 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004779channel_get_timeout(channel_T *channel, ch_part_T part)
Bram Moolenaar6f3a5442016-02-20 19:56:13 +01004780{
4781 return channel->ch_part[part].ch_timeout;
4782}
4783
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004784 static int
4785handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
4786{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004787 char_u *val = tv_get_string(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004788
4789 opt->jo_set |= jo;
4790 if (STRCMP(val, "nl") == 0)
4791 *modep = MODE_NL;
4792 else if (STRCMP(val, "raw") == 0)
4793 *modep = MODE_RAW;
4794 else if (STRCMP(val, "js") == 0)
4795 *modep = MODE_JS;
4796 else if (STRCMP(val, "json") == 0)
4797 *modep = MODE_JSON;
4798 else
4799 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004800 semsg(_(e_invarg2), val);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004801 return FAIL;
4802 }
4803 return OK;
4804}
4805
4806 static int
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004807handle_io(typval_T *item, ch_part_T part, jobopt_T *opt)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004808{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004809 char_u *val = tv_get_string(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004810
4811 opt->jo_set |= JO_OUT_IO << (part - PART_OUT);
4812 if (STRCMP(val, "null") == 0)
4813 opt->jo_io[part] = JIO_NULL;
4814 else if (STRCMP(val, "pipe") == 0)
4815 opt->jo_io[part] = JIO_PIPE;
4816 else if (STRCMP(val, "file") == 0)
4817 opt->jo_io[part] = JIO_FILE;
4818 else if (STRCMP(val, "buffer") == 0)
4819 opt->jo_io[part] = JIO_BUFFER;
4820 else if (STRCMP(val, "out") == 0 && part == PART_ERR)
4821 opt->jo_io[part] = JIO_OUT;
4822 else
4823 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004824 semsg(_(e_invarg2), val);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004825 return FAIL;
4826 }
4827 return OK;
4828}
4829
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004830/*
4831 * Clear a jobopt_T before using it.
4832 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004833 void
4834clear_job_options(jobopt_T *opt)
4835{
Bram Moolenaara80faa82020-04-12 19:37:17 +02004836 CLEAR_POINTER(opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004837}
4838
4839/*
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004840 * Free any members of a jobopt_T.
4841 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02004842 static void
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004843free_job_options(jobopt_T *opt)
4844{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02004845 if (opt->jo_callback.cb_partial != NULL)
4846 partial_unref(opt->jo_callback.cb_partial);
4847 else if (opt->jo_callback.cb_name != NULL)
4848 func_unref(opt->jo_callback.cb_name);
4849 if (opt->jo_out_cb.cb_partial != NULL)
4850 partial_unref(opt->jo_out_cb.cb_partial);
4851 else if (opt->jo_out_cb.cb_name != NULL)
4852 func_unref(opt->jo_out_cb.cb_name);
4853 if (opt->jo_err_cb.cb_partial != NULL)
4854 partial_unref(opt->jo_err_cb.cb_partial);
4855 else if (opt->jo_err_cb.cb_name != NULL)
4856 func_unref(opt->jo_err_cb.cb_name);
4857 if (opt->jo_close_cb.cb_partial != NULL)
4858 partial_unref(opt->jo_close_cb.cb_partial);
4859 else if (opt->jo_close_cb.cb_name != NULL)
4860 func_unref(opt->jo_close_cb.cb_name);
4861 if (opt->jo_exit_cb.cb_partial != NULL)
4862 partial_unref(opt->jo_exit_cb.cb_partial);
4863 else if (opt->jo_exit_cb.cb_name != NULL)
4864 func_unref(opt->jo_exit_cb.cb_name);
Bram Moolenaar05aafed2017-08-11 19:12:11 +02004865 if (opt->jo_env != NULL)
4866 dict_unref(opt->jo_env);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02004867}
4868
4869/*
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004870 * Get the PART_ number from the first character of an option name.
4871 */
4872 static int
4873part_from_char(int c)
4874{
4875 return c == 'i' ? PART_IN : c == 'o' ? PART_OUT: PART_ERR;
4876}
4877
4878/*
4879 * Get the option entries from the dict in "tv", parse them and put the result
4880 * in "opt".
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004881 * Only accept JO_ options in "supported" and JO2_ options in "supported2".
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004882 * If an option value is invalid return FAIL.
4883 */
4884 int
Bram Moolenaar08d384f2017-08-11 21:51:23 +02004885get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004886{
4887 typval_T *item;
4888 char_u *val;
4889 dict_T *dict;
4890 int todo;
4891 hashitem_T *hi;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02004892 ch_part_T part;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004893
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004894 if (tv->v_type == VAR_UNKNOWN)
4895 return OK;
4896 if (tv->v_type != VAR_DICT)
4897 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004898 emsg(_(e_dictreq));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004899 return FAIL;
4900 }
4901 dict = tv->vval.v_dict;
4902 if (dict == NULL)
4903 return OK;
4904
4905 todo = (int)dict->dv_hashtab.ht_used;
4906 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
4907 if (!HASHITEM_EMPTY(hi))
4908 {
4909 item = &dict_lookup(hi)->di_tv;
4910
4911 if (STRCMP(hi->hi_key, "mode") == 0)
4912 {
4913 if (!(supported & JO_MODE))
4914 break;
4915 if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
4916 return FAIL;
4917 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004918 else if (STRCMP(hi->hi_key, "in_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004919 {
4920 if (!(supported & JO_IN_MODE))
4921 break;
4922 if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
4923 == FAIL)
4924 return FAIL;
4925 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004926 else if (STRCMP(hi->hi_key, "out_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004927 {
4928 if (!(supported & JO_OUT_MODE))
4929 break;
4930 if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
4931 == FAIL)
4932 return FAIL;
4933 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004934 else if (STRCMP(hi->hi_key, "err_mode") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004935 {
4936 if (!(supported & JO_ERR_MODE))
4937 break;
4938 if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
4939 == FAIL)
4940 return FAIL;
4941 }
Bram Moolenaar0b146882018-09-06 16:27:24 +02004942 else if (STRCMP(hi->hi_key, "noblock") == 0)
4943 {
4944 if (!(supported & JO_MODE))
4945 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004946 opt->jo_noblock = tv_get_number(item);
Bram Moolenaar0b146882018-09-06 16:27:24 +02004947 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004948 else if (STRCMP(hi->hi_key, "in_io") == 0
4949 || STRCMP(hi->hi_key, "out_io") == 0
4950 || STRCMP(hi->hi_key, "err_io") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004951 {
4952 if (!(supported & JO_OUT_IO))
4953 break;
4954 if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
4955 return FAIL;
4956 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004957 else if (STRCMP(hi->hi_key, "in_name") == 0
4958 || STRCMP(hi->hi_key, "out_name") == 0
4959 || STRCMP(hi->hi_key, "err_name") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004960 {
4961 part = part_from_char(*hi->hi_key);
4962
4963 if (!(supported & JO_OUT_IO))
4964 break;
4965 opt->jo_set |= JO_OUT_NAME << (part - PART_OUT);
Bram Moolenaar21109272020-01-30 16:27:20 +01004966 opt->jo_io_name[part] = tv_get_string_buf_chk(item,
4967 opt->jo_io_name_buf[part]);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004968 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004969 else if (STRCMP(hi->hi_key, "pty") == 0)
4970 {
4971 if (!(supported & JO_MODE))
4972 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004973 opt->jo_pty = tv_get_number(item);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004974 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01004975 else if (STRCMP(hi->hi_key, "in_buf") == 0
4976 || STRCMP(hi->hi_key, "out_buf") == 0
4977 || STRCMP(hi->hi_key, "err_buf") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004978 {
4979 part = part_from_char(*hi->hi_key);
4980
4981 if (!(supported & JO_OUT_IO))
4982 break;
4983 opt->jo_set |= JO_OUT_BUF << (part - PART_OUT);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004984 opt->jo_io_buf[part] = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004985 if (opt->jo_io_buf[part] <= 0)
4986 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004987 semsg(_(e_invargNval), hi->hi_key, tv_get_string(item));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004988 return FAIL;
4989 }
4990 if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
4991 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004992 semsg(_(e_nobufnr), (long)opt->jo_io_buf[part]);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01004993 return FAIL;
4994 }
4995 }
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02004996 else if (STRCMP(hi->hi_key, "out_modifiable") == 0
4997 || STRCMP(hi->hi_key, "err_modifiable") == 0)
4998 {
4999 part = part_from_char(*hi->hi_key);
5000
5001 if (!(supported & JO_OUT_IO))
5002 break;
5003 opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005004 opt->jo_modifiable[part] = tv_get_number(item);
Bram Moolenaar9f5842e2016-05-29 16:17:08 +02005005 }
Bram Moolenaar169ebb02016-09-07 23:32:23 +02005006 else if (STRCMP(hi->hi_key, "out_msg") == 0
5007 || STRCMP(hi->hi_key, "err_msg") == 0)
5008 {
5009 part = part_from_char(*hi->hi_key);
5010
5011 if (!(supported & JO_OUT_IO))
5012 break;
5013 opt->jo_set2 |= JO2_OUT_MSG << (part - PART_OUT);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005014 opt->jo_message[part] = tv_get_number(item);
Bram Moolenaar169ebb02016-09-07 23:32:23 +02005015 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005016 else if (STRCMP(hi->hi_key, "in_top") == 0
5017 || STRCMP(hi->hi_key, "in_bot") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005018 {
5019 linenr_T *lp;
5020
5021 if (!(supported & JO_OUT_IO))
5022 break;
5023 if (hi->hi_key[3] == 't')
5024 {
5025 lp = &opt->jo_in_top;
5026 opt->jo_set |= JO_IN_TOP;
5027 }
5028 else
5029 {
5030 lp = &opt->jo_in_bot;
5031 opt->jo_set |= JO_IN_BOT;
5032 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005033 *lp = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005034 if (*lp < 0)
5035 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005036 semsg(_(e_invargNval), hi->hi_key, tv_get_string(item));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005037 return FAIL;
5038 }
5039 }
5040 else if (STRCMP(hi->hi_key, "channel") == 0)
5041 {
5042 if (!(supported & JO_OUT_IO))
5043 break;
5044 opt->jo_set |= JO_CHANNEL;
5045 if (item->v_type != VAR_CHANNEL)
5046 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005047 semsg(_(e_invargval), "channel");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005048 return FAIL;
5049 }
5050 opt->jo_channel = item->vval.v_channel;
5051 }
5052 else if (STRCMP(hi->hi_key, "callback") == 0)
5053 {
5054 if (!(supported & JO_CALLBACK))
5055 break;
5056 opt->jo_set |= JO_CALLBACK;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005057 opt->jo_callback = get_callback(item);
5058 if (opt->jo_callback.cb_name == NULL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005059 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005060 semsg(_(e_invargval), "callback");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005061 return FAIL;
5062 }
5063 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005064 else if (STRCMP(hi->hi_key, "out_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005065 {
5066 if (!(supported & JO_OUT_CALLBACK))
5067 break;
5068 opt->jo_set |= JO_OUT_CALLBACK;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005069 opt->jo_out_cb = get_callback(item);
5070 if (opt->jo_out_cb.cb_name == NULL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005071 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005072 semsg(_(e_invargval), "out_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005073 return FAIL;
5074 }
5075 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005076 else if (STRCMP(hi->hi_key, "err_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005077 {
5078 if (!(supported & JO_ERR_CALLBACK))
5079 break;
5080 opt->jo_set |= JO_ERR_CALLBACK;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005081 opt->jo_err_cb = get_callback(item);
5082 if (opt->jo_err_cb.cb_name == NULL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005083 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005084 semsg(_(e_invargval), "err_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005085 return FAIL;
5086 }
5087 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005088 else if (STRCMP(hi->hi_key, "close_cb") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005089 {
5090 if (!(supported & JO_CLOSE_CALLBACK))
5091 break;
5092 opt->jo_set |= JO_CLOSE_CALLBACK;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005093 opt->jo_close_cb = get_callback(item);
5094 if (opt->jo_close_cb.cb_name == NULL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005095 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005096 semsg(_(e_invargval), "close_cb");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005097 return FAIL;
5098 }
5099 }
Bram Moolenaar958dc692016-12-01 15:34:12 +01005100 else if (STRCMP(hi->hi_key, "drop") == 0)
5101 {
5102 int never = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005103 val = tv_get_string(item);
Bram Moolenaar958dc692016-12-01 15:34:12 +01005104
5105 if (STRCMP(val, "never") == 0)
5106 never = TRUE;
5107 else if (STRCMP(val, "auto") != 0)
5108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005109 semsg(_(e_invargNval), "drop", val);
Bram Moolenaar958dc692016-12-01 15:34:12 +01005110 return FAIL;
5111 }
5112 opt->jo_drop_never = never;
5113 }
Bram Moolenaaref3abc62016-05-29 16:44:26 +02005114 else if (STRCMP(hi->hi_key, "exit_cb") == 0)
5115 {
5116 if (!(supported & JO_EXIT_CB))
5117 break;
5118 opt->jo_set |= JO_EXIT_CB;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005119 opt->jo_exit_cb = get_callback(item);
5120 if (opt->jo_exit_cb.cb_name == NULL)
Bram Moolenaaref3abc62016-05-29 16:44:26 +02005121 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005122 semsg(_(e_invargval), "exit_cb");
Bram Moolenaaref3abc62016-05-29 16:44:26 +02005123 return FAIL;
5124 }
5125 }
Bram Moolenaar8456ea82017-08-05 15:02:05 +02005126#ifdef FEAT_TERMINAL
Bram Moolenaar78712a72017-08-05 14:50:12 +02005127 else if (STRCMP(hi->hi_key, "term_name") == 0)
5128 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005129 if (!(supported2 & JO2_TERM_NAME))
Bram Moolenaar78712a72017-08-05 14:50:12 +02005130 break;
5131 opt->jo_set2 |= JO2_TERM_NAME;
Bram Moolenaar21109272020-01-30 16:27:20 +01005132 opt->jo_term_name = tv_get_string_buf_chk(item,
5133 opt->jo_term_name_buf);
Bram Moolenaar78712a72017-08-05 14:50:12 +02005134 if (opt->jo_term_name == NULL)
5135 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005136 semsg(_(e_invargval), "term_name");
Bram Moolenaar78712a72017-08-05 14:50:12 +02005137 return FAIL;
5138 }
5139 }
Bram Moolenaardd693ce2017-08-10 23:15:19 +02005140 else if (STRCMP(hi->hi_key, "term_finish") == 0)
5141 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005142 if (!(supported2 & JO2_TERM_FINISH))
Bram Moolenaardd693ce2017-08-10 23:15:19 +02005143 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005144 val = tv_get_string(item);
Bram Moolenaardd693ce2017-08-10 23:15:19 +02005145 if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
5146 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005147 semsg(_(e_invargNval), "term_finish", val);
Bram Moolenaardd693ce2017-08-10 23:15:19 +02005148 return FAIL;
5149 }
5150 opt->jo_set2 |= JO2_TERM_FINISH;
5151 opt->jo_term_finish = *val;
5152 }
Bram Moolenaar37c45832017-08-12 16:01:04 +02005153 else if (STRCMP(hi->hi_key, "term_opencmd") == 0)
5154 {
5155 char_u *p;
5156
5157 if (!(supported2 & JO2_TERM_OPENCMD))
5158 break;
5159 opt->jo_set2 |= JO2_TERM_OPENCMD;
Bram Moolenaar21109272020-01-30 16:27:20 +01005160 p = opt->jo_term_opencmd = tv_get_string_buf_chk(item,
5161 opt->jo_term_opencmd_buf);
Bram Moolenaar37c45832017-08-12 16:01:04 +02005162 if (p != NULL)
5163 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005164 // Must have %d and no other %.
Bram Moolenaar37c45832017-08-12 16:01:04 +02005165 p = vim_strchr(p, '%');
5166 if (p != NULL && (p[1] != 'd'
5167 || vim_strchr(p + 2, '%') != NULL))
5168 p = NULL;
5169 }
5170 if (p == NULL)
5171 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005172 semsg(_(e_invargval), "term_opencmd");
Bram Moolenaar37c45832017-08-12 16:01:04 +02005173 return FAIL;
5174 }
5175 }
Bram Moolenaar3346cc42017-09-02 14:54:21 +02005176 else if (STRCMP(hi->hi_key, "eof_chars") == 0)
5177 {
Bram Moolenaar3346cc42017-09-02 14:54:21 +02005178 if (!(supported2 & JO2_EOF_CHARS))
5179 break;
5180 opt->jo_set2 |= JO2_EOF_CHARS;
Bram Moolenaar21109272020-01-30 16:27:20 +01005181 opt->jo_eof_chars = tv_get_string_buf_chk(item,
5182 opt->jo_eof_chars_buf);
5183 if (opt->jo_eof_chars == NULL)
Bram Moolenaar3346cc42017-09-02 14:54:21 +02005184 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005185 semsg(_(e_invargval), "eof_chars");
Bram Moolenaar3346cc42017-09-02 14:54:21 +02005186 return FAIL;
5187 }
Bram Moolenaar3346cc42017-09-02 14:54:21 +02005188 }
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005189 else if (STRCMP(hi->hi_key, "term_rows") == 0)
5190 {
5191 if (!(supported2 & JO2_TERM_ROWS))
5192 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005193 opt->jo_set2 |= JO2_TERM_ROWS;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005194 opt->jo_term_rows = tv_get_number(item);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005195 }
5196 else if (STRCMP(hi->hi_key, "term_cols") == 0)
5197 {
5198 if (!(supported2 & JO2_TERM_COLS))
5199 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005200 opt->jo_set2 |= JO2_TERM_COLS;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005201 opt->jo_term_cols = tv_get_number(item);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005202 }
5203 else if (STRCMP(hi->hi_key, "vertical") == 0)
5204 {
5205 if (!(supported2 & JO2_VERTICAL))
5206 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005207 opt->jo_set2 |= JO2_VERTICAL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005208 opt->jo_vertical = tv_get_number(item);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005209 }
Bram Moolenaarda43b612017-08-11 22:27:50 +02005210 else if (STRCMP(hi->hi_key, "curwin") == 0)
5211 {
5212 if (!(supported2 & JO2_CURWIN))
5213 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005214 opt->jo_set2 |= JO2_CURWIN;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005215 opt->jo_curwin = tv_get_number(item);
Bram Moolenaarda43b612017-08-11 22:27:50 +02005216 }
Bram Moolenaar87abab92019-06-03 21:14:59 +02005217 else if (STRCMP(hi->hi_key, "bufnr") == 0)
5218 {
5219 int nr;
5220
5221 if (!(supported2 & JO2_CURWIN))
5222 break;
5223 opt->jo_set2 |= JO2_BUFNR;
5224 nr = tv_get_number(item);
5225 if (nr <= 0)
5226 {
5227 semsg(_(e_invargNval), hi->hi_key, tv_get_string(item));
5228 return FAIL;
5229 }
5230 opt->jo_bufnr_buf = buflist_findnr(nr);
5231 if (opt->jo_bufnr_buf == NULL)
5232 {
5233 semsg(_(e_nobufnr), (long)nr);
5234 return FAIL;
5235 }
5236 if (opt->jo_bufnr_buf->b_nwindows == 0
5237 || opt->jo_bufnr_buf->b_term == NULL)
5238 {
5239 semsg(_(e_invarg2), "bufnr");
5240 return FAIL;
5241 }
5242 }
Bram Moolenaar8cad9302017-08-12 14:32:32 +02005243 else if (STRCMP(hi->hi_key, "hidden") == 0)
5244 {
5245 if (!(supported2 & JO2_HIDDEN))
5246 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005247 opt->jo_set2 |= JO2_HIDDEN;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005248 opt->jo_hidden = tv_get_number(item);
Bram Moolenaar8cad9302017-08-12 14:32:32 +02005249 }
Bram Moolenaar4d8bac82018-03-09 21:33:34 +01005250 else if (STRCMP(hi->hi_key, "norestore") == 0)
5251 {
5252 if (!(supported2 & JO2_NORESTORE))
5253 break;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005254 opt->jo_set2 |= JO2_NORESTORE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005255 opt->jo_term_norestore = tv_get_number(item);
Bram Moolenaar4d8bac82018-03-09 21:33:34 +01005256 }
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005257 else if (STRCMP(hi->hi_key, "term_kill") == 0)
5258 {
5259 if (!(supported2 & JO2_TERM_KILL))
5260 break;
5261 opt->jo_set2 |= JO2_TERM_KILL;
Bram Moolenaar21109272020-01-30 16:27:20 +01005262 opt->jo_term_kill = tv_get_string_buf_chk(item,
5263 opt->jo_term_kill_buf);
5264 if (opt->jo_term_kill == NULL)
5265 {
5266 semsg(_(e_invargval), "term_kill");
5267 return FAIL;
5268 }
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005269 }
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005270 else if (STRCMP(hi->hi_key, "tty_type") == 0)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005271 {
5272 char_u *p;
5273
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005274 if (!(supported2 & JO2_TTY_TYPE))
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005275 break;
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005276 opt->jo_set2 |= JO2_TTY_TYPE;
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005277 p = tv_get_string_chk(item);
5278 if (p == NULL)
5279 {
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005280 semsg(_(e_invargval), "tty_type");
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005281 return FAIL;
5282 }
5283 // Allow empty string, "winpty", "conpty".
5284 if (!(*p == NUL || STRCMP(p, "winpty") == 0
5285 || STRCMP(p, "conpty") == 0))
5286 {
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005287 semsg(_(e_invargval), "tty_type");
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005288 return FAIL;
5289 }
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005290 opt->jo_tty_type = p[0];
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005291 }
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005292# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
5293 else if (STRCMP(hi->hi_key, "ansi_colors") == 0)
5294 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005295 int n = 0;
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005296 listitem_T *li;
5297 long_u rgb[16];
5298
5299 if (!(supported2 & JO2_ANSI_COLORS))
5300 break;
5301
5302 if (item == NULL || item->v_type != VAR_LIST
5303 || item->vval.v_list == NULL)
5304 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005305 semsg(_(e_invargval), "ansi_colors");
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005306 return FAIL;
5307 }
5308
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005309 CHECK_LIST_MATERIALIZE(item->vval.v_list);
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005310 li = item->vval.v_list->lv_first;
5311 for (; li != NULL && n < 16; li = li->li_next, n++)
5312 {
5313 char_u *color_name;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005314 guicolor_T guicolor;
Bram Moolenaar87202262020-05-24 17:23:45 +02005315 int called_emsg_before = called_emsg;
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005317 color_name = tv_get_string_chk(&li->li_tv);
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005318 if (color_name == NULL)
5319 return FAIL;
5320
5321 guicolor = GUI_GET_COLOR(color_name);
5322 if (guicolor == INVALCOLOR)
Bram Moolenaar87202262020-05-24 17:23:45 +02005323 {
5324 if (called_emsg_before == called_emsg)
5325 // may not get the error if the GUI didn't start
5326 semsg(_(e_alloc_color), color_name);
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005327 return FAIL;
Bram Moolenaar87202262020-05-24 17:23:45 +02005328 }
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005329
5330 rgb[n] = GUI_MCH_GET_RGB(guicolor);
5331 }
5332
5333 if (n != 16 || li != NULL)
5334 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005335 semsg(_(e_invargval), "ansi_colors");
Bram Moolenaarf59c6e82018-04-10 15:59:11 +02005336 return FAIL;
5337 }
5338
5339 opt->jo_set2 |= JO2_ANSI_COLORS;
5340 memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
5341 }
5342# endif
Bram Moolenaar83d47902020-03-26 20:34:00 +01005343 else if (STRCMP(hi->hi_key, "term_highlight") == 0)
5344 {
5345 char_u *p;
5346
5347 if (!(supported2 & JO2_TERM_HIGHLIGHT))
5348 break;
5349 opt->jo_set2 |= JO2_TERM_HIGHLIGHT;
5350 p = tv_get_string_buf_chk(item, opt->jo_term_highlight_buf);
5351 if (p == NULL || *p == NUL)
5352 {
5353 semsg(_(e_invargval), "term_highlight");
5354 return FAIL;
5355 }
5356 opt->jo_term_highlight = p;
5357 }
Bram Moolenaard2842ea2019-09-26 23:08:54 +02005358 else if (STRCMP(hi->hi_key, "term_api") == 0)
5359 {
5360 if (!(supported2 & JO2_TERM_API))
5361 break;
5362 opt->jo_set2 |= JO2_TERM_API;
5363 opt->jo_term_api = tv_get_string_buf_chk(item,
Bram Moolenaar21109272020-01-30 16:27:20 +01005364 opt->jo_term_api_buf);
5365 if (opt->jo_term_api == NULL)
5366 {
5367 semsg(_(e_invargval), "term_api");
5368 return FAIL;
5369 }
Bram Moolenaard2842ea2019-09-26 23:08:54 +02005370 }
Bram Moolenaar8456ea82017-08-05 15:02:05 +02005371#endif
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005372 else if (STRCMP(hi->hi_key, "env") == 0)
5373 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005374 if (!(supported2 & JO2_ENV))
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005375 break;
Bram Moolenaar22efba42018-04-07 13:22:21 +02005376 if (item->v_type != VAR_DICT)
5377 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005378 semsg(_(e_invargval), "env");
Bram Moolenaar22efba42018-04-07 13:22:21 +02005379 return FAIL;
5380 }
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005381 opt->jo_set2 |= JO2_ENV;
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005382 opt->jo_env = item->vval.v_dict;
Bram Moolenaar22efba42018-04-07 13:22:21 +02005383 if (opt->jo_env != NULL)
5384 ++opt->jo_env->dv_refcount;
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005385 }
5386 else if (STRCMP(hi->hi_key, "cwd") == 0)
5387 {
Bram Moolenaar08d384f2017-08-11 21:51:23 +02005388 if (!(supported2 & JO2_CWD))
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005389 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005390 opt->jo_cwd = tv_get_string_buf_chk(item, opt->jo_cwd_buf);
Bram Moolenaar839e81e2018-10-19 16:53:39 +02005391 if (opt->jo_cwd == NULL || !mch_isdir(opt->jo_cwd)
Bram Moolenaar4f974752019-02-17 17:44:42 +01005392#ifndef MSWIN // Win32 directories don't have the concept of "executable"
Bram Moolenaar42a4ea12018-10-19 17:36:01 +02005393 || mch_access((char *)opt->jo_cwd, X_OK) != 0
5394#endif
5395 )
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005396 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005397 semsg(_(e_invargval), "cwd");
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005398 return FAIL;
5399 }
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01005400 opt->jo_set2 |= JO2_CWD;
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005401 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005402 else if (STRCMP(hi->hi_key, "waittime") == 0)
5403 {
5404 if (!(supported & JO_WAITTIME))
5405 break;
5406 opt->jo_set |= JO_WAITTIME;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005407 opt->jo_waittime = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005408 }
5409 else if (STRCMP(hi->hi_key, "timeout") == 0)
5410 {
5411 if (!(supported & JO_TIMEOUT))
5412 break;
5413 opt->jo_set |= JO_TIMEOUT;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005414 opt->jo_timeout = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005415 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005416 else if (STRCMP(hi->hi_key, "out_timeout") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005417 {
5418 if (!(supported & JO_OUT_TIMEOUT))
5419 break;
5420 opt->jo_set |= JO_OUT_TIMEOUT;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005421 opt->jo_out_timeout = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005422 }
Bram Moolenaard6c2f052016-03-14 23:22:59 +01005423 else if (STRCMP(hi->hi_key, "err_timeout") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005424 {
5425 if (!(supported & JO_ERR_TIMEOUT))
5426 break;
5427 opt->jo_set |= JO_ERR_TIMEOUT;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005428 opt->jo_err_timeout = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005429 }
5430 else if (STRCMP(hi->hi_key, "part") == 0)
5431 {
5432 if (!(supported & JO_PART))
5433 break;
5434 opt->jo_set |= JO_PART;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005435 val = tv_get_string(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005436 if (STRCMP(val, "err") == 0)
5437 opt->jo_part = PART_ERR;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02005438 else if (STRCMP(val, "out") == 0)
5439 opt->jo_part = PART_OUT;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005440 else
5441 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005442 semsg(_(e_invargNval), "part", val);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005443 return FAIL;
5444 }
5445 }
5446 else if (STRCMP(hi->hi_key, "id") == 0)
5447 {
5448 if (!(supported & JO_ID))
5449 break;
5450 opt->jo_set |= JO_ID;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005451 opt->jo_id = tv_get_number(item);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005452 }
5453 else if (STRCMP(hi->hi_key, "stoponexit") == 0)
5454 {
5455 if (!(supported & JO_STOPONEXIT))
5456 break;
5457 opt->jo_set |= JO_STOPONEXIT;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005458 opt->jo_stoponexit = tv_get_string_buf_chk(item,
Bram Moolenaar21109272020-01-30 16:27:20 +01005459 opt->jo_stoponexit_buf);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005460 if (opt->jo_stoponexit == NULL)
5461 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005462 semsg(_(e_invargval), "stoponexit");
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005463 return FAIL;
5464 }
5465 }
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005466 else if (STRCMP(hi->hi_key, "block_write") == 0)
5467 {
5468 if (!(supported & JO_BLOCK_WRITE))
5469 break;
5470 opt->jo_set |= JO_BLOCK_WRITE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005471 opt->jo_block_write = tv_get_number(item);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005472 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005473 else
5474 break;
5475 --todo;
5476 }
5477 if (todo > 0)
5478 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005479 semsg(_(e_invarg2), hi->hi_key);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005480 return FAIL;
5481 }
5482
5483 return OK;
5484}
5485
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005486static job_T *first_job = NULL;
5487
5488 static void
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005489job_free_contents(job_T *job)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005490{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02005491 int i;
5492
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005493 ch_log(job->jv_channel, "Freeing job");
5494 if (job->jv_channel != NULL)
5495 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005496 // The link from the channel to the job doesn't count as a reference,
5497 // thus don't decrement the refcount of the job. The reference from
5498 // the job to the channel does count the reference, decrement it and
5499 // NULL the reference. We don't set ch_job_killed, unreferencing the
5500 // job doesn't mean it stops running.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005501 job->jv_channel->ch_job = NULL;
5502 channel_unref(job->jv_channel);
5503 }
5504 mch_clear_job(job);
5505
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005506 vim_free(job->jv_tty_in);
5507 vim_free(job->jv_tty_out);
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005508 vim_free(job->jv_stoponexit);
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005509#ifdef UNIX
5510 vim_free(job->jv_termsig);
5511#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005512#ifdef MSWIN
Bram Moolenaarc6ddce32019-02-08 12:47:03 +01005513 vim_free(job->jv_tty_type);
5514#endif
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005515 free_callback(&job->jv_exit_cb);
Bram Moolenaar20608922018-04-21 22:30:08 +02005516 if (job->jv_argv != NULL)
Bram Moolenaare1fc5152018-04-21 19:49:08 +02005517 {
Bram Moolenaar20608922018-04-21 22:30:08 +02005518 for (i = 0; job->jv_argv[i] != NULL; i++)
5519 vim_free(job->jv_argv[i]);
5520 vim_free(job->jv_argv);
Bram Moolenaare1fc5152018-04-21 19:49:08 +02005521 }
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005522}
5523
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005524/*
5525 * Remove "job" from the list of jobs.
5526 */
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005527 static void
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005528job_unlink(job_T *job)
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005529{
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005530 if (job->jv_next != NULL)
5531 job->jv_next->jv_prev = job->jv_prev;
5532 if (job->jv_prev == NULL)
5533 first_job = job->jv_next;
5534 else
5535 job->jv_prev->jv_next = job->jv_next;
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005536}
5537
5538 static void
5539job_free_job(job_T *job)
5540{
5541 job_unlink(job);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005542 vim_free(job);
5543}
5544
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005545 static void
5546job_free(job_T *job)
5547{
5548 if (!in_free_unref_items)
5549 {
5550 job_free_contents(job);
5551 job_free_job(job);
5552 }
5553}
5554
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02005555static job_T *jobs_to_free = NULL;
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005556
5557/*
5558 * Put "job" in a list to be freed later, when it's no longer referenced.
5559 */
5560 static void
5561job_free_later(job_T *job)
5562{
5563 job_unlink(job);
5564 job->jv_next = jobs_to_free;
5565 jobs_to_free = job;
5566}
5567
5568 static void
5569free_jobs_to_free_later(void)
5570{
5571 job_T *job;
5572
5573 while (jobs_to_free != NULL)
5574 {
5575 job = jobs_to_free;
5576 jobs_to_free = job->jv_next;
5577 job_free_contents(job);
5578 vim_free(job);
5579 }
5580}
5581
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005582#if defined(EXITFREE) || defined(PROTO)
5583 void
5584job_free_all(void)
5585{
5586 while (first_job != NULL)
5587 job_free(first_job);
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005588 free_jobs_to_free_later();
5589
5590# ifdef FEAT_TERMINAL
5591 free_unused_terminals();
5592# endif
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005593}
5594#endif
5595
5596/*
5597 * Return TRUE if we need to check if the process of "job" has ended.
5598 */
5599 static int
5600job_need_end_check(job_T *job)
5601{
5602 return job->jv_status == JOB_STARTED
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005603 && (job->jv_stoponexit != NULL || job->jv_exit_cb.cb_name != NULL);
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005604}
5605
5606/*
5607 * Return TRUE if the channel of "job" is still useful.
5608 */
5609 static int
5610job_channel_still_useful(job_T *job)
5611{
5612 return job->jv_channel != NULL && channel_still_useful(job->jv_channel);
5613}
5614
5615/*
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005616 * Return TRUE if the channel of "job" is closeable.
5617 */
5618 static int
5619job_channel_can_close(job_T *job)
5620{
5621 return job->jv_channel != NULL && channel_can_close(job->jv_channel);
5622}
5623
5624/*
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005625 * Return TRUE if the job should not be freed yet. Do not free the job when
5626 * it has not ended yet and there is a "stoponexit" flag, an exit callback
5627 * or when the associated channel will do something with the job output.
5628 */
5629 static int
5630job_still_useful(job_T *job)
5631{
5632 return job_need_end_check(job) || job_channel_still_useful(job);
5633}
5634
Bram Moolenaarafde13b2019-04-28 19:46:49 +02005635#if defined(GUI_MAY_FORK) || defined(GUI_MAY_SPAWN) || defined(PROTO)
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005636/*
5637 * Return TRUE when there is any running job that we care about.
5638 */
5639 int
5640job_any_running()
5641{
5642 job_T *job;
5643
Bram Moolenaaraeea7212020-04-02 18:50:46 +02005644 FOR_ALL_JOBS(job)
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005645 if (job_still_useful(job))
Bram Moolenaare65fffd2018-05-13 14:40:15 +02005646 {
5647 ch_log(NULL, "GUI not forking because a job is running");
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005648 return TRUE;
Bram Moolenaare65fffd2018-05-13 14:40:15 +02005649 }
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005650 return FALSE;
5651}
5652#endif
5653
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005654#if !defined(USE_ARGV) || defined(PROTO)
5655/*
5656 * Escape one argument for an external command.
5657 * Returns the escaped string in allocated memory. NULL when out of memory.
5658 */
5659 static char_u *
5660win32_escape_arg(char_u *arg)
5661{
5662 int slen, dlen;
5663 int escaping = 0;
5664 int i;
5665 char_u *s, *d;
5666 char_u *escaped_arg;
5667 int has_spaces = FALSE;
5668
Bram Moolenaarc667da52019-11-30 20:52:27 +01005669 // First count the number of extra bytes required.
Bram Moolenaare85928a2017-08-27 13:10:10 +02005670 slen = (int)STRLEN(arg);
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005671 dlen = slen;
5672 for (s = arg; *s != NUL; MB_PTR_ADV(s))
5673 {
5674 if (*s == '"' || *s == '\\')
5675 ++dlen;
5676 if (*s == ' ' || *s == '\t')
5677 has_spaces = TRUE;
5678 }
5679
5680 if (has_spaces)
5681 dlen += 2;
5682
5683 if (dlen == slen)
5684 return vim_strsave(arg);
5685
Bram Moolenaarc667da52019-11-30 20:52:27 +01005686 // Allocate memory for the result and fill it.
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005687 escaped_arg = alloc(dlen + 1);
5688 if (escaped_arg == NULL)
5689 return NULL;
5690 memset(escaped_arg, 0, dlen+1);
5691
5692 d = escaped_arg;
5693
5694 if (has_spaces)
5695 *d++ = '"';
5696
5697 for (s = arg; *s != NUL;)
5698 {
5699 switch (*s)
5700 {
5701 case '"':
5702 for (i = 0; i < escaping; i++)
5703 *d++ = '\\';
5704 escaping = 0;
5705 *d++ = '\\';
5706 *d++ = *s++;
5707 break;
5708 case '\\':
5709 escaping++;
5710 *d++ = *s++;
5711 break;
5712 default:
5713 escaping = 0;
5714 MB_COPY_CHAR(s, d);
5715 break;
5716 }
5717 }
5718
Bram Moolenaarc667da52019-11-30 20:52:27 +01005719 // add terminating quote and finish with a NUL
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005720 if (has_spaces)
5721 {
5722 for (i = 0; i < escaping; i++)
5723 *d++ = '\\';
5724 *d++ = '"';
5725 }
5726 *d = NUL;
5727
5728 return escaped_arg;
5729}
5730
5731/*
5732 * Build a command line from a list, taking care of escaping.
5733 * The result is put in gap->ga_data.
5734 * Returns FAIL when out of memory.
5735 */
5736 int
5737win32_build_cmd(list_T *l, garray_T *gap)
5738{
5739 listitem_T *li;
5740 char_u *s;
5741
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005742 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02005743 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005744 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005745 s = tv_get_string_chk(&li->li_tv);
Bram Moolenaardcaa6132017-08-13 17:13:09 +02005746 if (s == NULL)
5747 return FAIL;
5748 s = win32_escape_arg(s);
5749 if (s == NULL)
5750 return FAIL;
5751 ga_concat(gap, s);
5752 vim_free(s);
5753 if (li->li_next != NULL)
5754 ga_append(gap, ' ');
5755 }
5756 return OK;
5757}
5758#endif
5759
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005760/*
5761 * NOTE: Must call job_cleanup() only once right after the status of "job"
5762 * changed to JOB_ENDED (i.e. after job_status() returned "dead" first or
5763 * mch_detect_ended_job() returned non-NULL).
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005764 * If the job is no longer used it will be removed from the list of jobs, and
5765 * deleted a bit later.
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005766 */
Bram Moolenaar8f84c3a2017-07-22 16:14:44 +02005767 void
Bram Moolenaar97792de2016-10-15 18:36:49 +02005768job_cleanup(job_T *job)
5769{
5770 if (job->jv_status != JOB_ENDED)
5771 return;
5772
Bram Moolenaarc667da52019-11-30 20:52:27 +01005773 // Ready to cleanup the job.
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005774 job->jv_status = JOB_FINISHED;
5775
Bram Moolenaarc667da52019-11-30 20:52:27 +01005776 // When only channel-in is kept open, close explicitly.
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005777 if (job->jv_channel != NULL)
5778 ch_close_part(job->jv_channel, PART_IN);
5779
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005780 if (job->jv_exit_cb.cb_name != NULL)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005781 {
5782 typval_T argv[3];
5783 typval_T rettv;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005784
Bram Moolenaarc667da52019-11-30 20:52:27 +01005785 // Invoke the exit callback. Make sure the refcount is > 0.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005786 ch_log(job->jv_channel, "Invoking exit callback %s",
5787 job->jv_exit_cb.cb_name);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005788 ++job->jv_refcount;
5789 argv[0].v_type = VAR_JOB;
5790 argv[0].vval.v_job = job;
5791 argv[1].v_type = VAR_NUMBER;
5792 argv[1].vval.v_number = job->jv_exitval;
Bram Moolenaarc6538bc2019-08-03 18:17:11 +02005793 call_callback(&job->jv_exit_cb, -1, &rettv, 2, argv);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005794 clear_tv(&rettv);
5795 --job->jv_refcount;
5796 channel_need_redraw = TRUE;
5797 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005798
Bram Moolenaar8caa43d2019-02-20 22:45:06 +01005799 if (job->jv_channel != NULL && job->jv_channel->ch_anonymous_pipe)
5800 job->jv_channel->ch_killing = TRUE;
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005801
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005802 // Do not free the job in case the close callback of the associated channel
5803 // isn't invoked yet and may get information by job_info().
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005804 if (job->jv_refcount == 0 && !job_channel_still_useful(job))
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01005805 // The job was already unreferenced and the associated channel was
5806 // detached, now that it ended it can be freed. However, a caller might
5807 // still use it, thus free it a bit later.
5808 job_free_later(job);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005809}
5810
Bram Moolenaarb8d49052016-05-01 14:22:16 +02005811/*
5812 * Mark references in jobs that are still useful.
5813 */
5814 int
5815set_ref_in_job(int copyID)
5816{
5817 int abort = FALSE;
5818 job_T *job;
5819 typval_T tv;
5820
Bram Moolenaar75a1a942019-06-20 03:45:36 +02005821 for (job = first_job; !abort && job != NULL; job = job->jv_next)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005822 if (job_still_useful(job))
Bram Moolenaarb8d49052016-05-01 14:22:16 +02005823 {
5824 tv.v_type = VAR_JOB;
5825 tv.vval.v_job = job;
5826 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
5827 }
5828 return abort;
5829}
5830
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005831/*
5832 * Dereference "job". Note that after this "job" may have been freed.
5833 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005834 void
5835job_unref(job_T *job)
5836{
5837 if (job != NULL && --job->jv_refcount <= 0)
5838 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005839 // Do not free the job if there is a channel where the close callback
5840 // may get the job info.
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005841 if (!job_channel_still_useful(job))
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005842 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005843 // Do not free the job when it has not ended yet and there is a
5844 // "stoponexit" flag or an exit callback.
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005845 if (!job_need_end_check(job))
5846 {
5847 job_free(job);
5848 }
5849 else if (job->jv_channel != NULL)
5850 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005851 // Do remove the link to the channel, otherwise it hangs
5852 // around until Vim exits. See job_free() for refcount.
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005853 ch_log(job->jv_channel, "detaching channel from job");
5854 job->jv_channel->ch_job = NULL;
5855 channel_unref(job->jv_channel);
5856 job->jv_channel = NULL;
5857 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005858 }
5859 }
5860}
5861
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005862 int
5863free_unused_jobs_contents(int copyID, int mask)
5864{
5865 int did_free = FALSE;
5866 job_T *job;
5867
Bram Moolenaaraeea7212020-04-02 18:50:46 +02005868 FOR_ALL_JOBS(job)
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +02005869 if ((job->jv_copyID & mask) != (copyID & mask)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005870 && !job_still_useful(job))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005871 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005872 // Free the channel and ordinary items it contains, but don't
5873 // recurse into Lists, Dictionaries etc.
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005874 job_free_contents(job);
5875 did_free = TRUE;
Bram Moolenaar36e0f7d2016-05-08 13:21:12 +02005876 }
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005877 return did_free;
5878}
5879
5880 void
5881free_unused_jobs(int copyID, int mask)
5882{
5883 job_T *job;
5884 job_T *job_next;
5885
5886 for (job = first_job; job != NULL; job = job_next)
5887 {
5888 job_next = job->jv_next;
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +02005889 if ((job->jv_copyID & mask) != (copyID & mask)
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005890 && !job_still_useful(job))
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005891 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01005892 // Free the job struct itself.
Bram Moolenaar107e1ee2016-04-08 17:07:19 +02005893 job_free_job(job);
5894 }
5895 }
5896}
5897
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005898/*
5899 * Allocate a job. Sets the refcount to one and sets options default.
5900 */
Bram Moolenaar8f84c3a2017-07-22 16:14:44 +02005901 job_T *
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005902job_alloc(void)
5903{
5904 job_T *job;
5905
Bram Moolenaarc799fe22019-05-28 23:08:19 +02005906 job = ALLOC_CLEAR_ONE(job_T);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005907 if (job != NULL)
5908 {
5909 job->jv_refcount = 1;
5910 job->jv_stoponexit = vim_strsave((char_u *)"term");
5911
5912 if (first_job != NULL)
5913 {
5914 first_job->jv_prev = job;
5915 job->jv_next = first_job;
5916 }
5917 first_job = job;
5918 }
5919 return job;
5920}
5921
5922 void
5923job_set_options(job_T *job, jobopt_T *opt)
5924{
5925 if (opt->jo_set & JO_STOPONEXIT)
5926 {
5927 vim_free(job->jv_stoponexit);
5928 if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
5929 job->jv_stoponexit = NULL;
5930 else
5931 job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
5932 }
5933 if (opt->jo_set & JO_EXIT_CB)
5934 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005935 free_callback(&job->jv_exit_cb);
5936 if (opt->jo_exit_cb.cb_name == NULL || *opt->jo_exit_cb.cb_name == NUL)
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005937 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005938 job->jv_exit_cb.cb_name = NULL;
5939 job->jv_exit_cb.cb_partial = NULL;
Bram Moolenaar1735bc92016-03-14 23:05:14 +01005940 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005941 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02005942 copy_callback(&job->jv_exit_cb, &opt->jo_exit_cb);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005943 }
5944}
5945
5946/*
5947 * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
5948 */
5949 void
Bram Moolenaarcf089462016-06-12 21:18:43 +02005950job_stop_on_exit(void)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005951{
5952 job_T *job;
5953
Bram Moolenaaraeea7212020-04-02 18:50:46 +02005954 FOR_ALL_JOBS(job)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005955 if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005956 mch_signal_job(job, job->jv_stoponexit);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005957}
5958
5959/*
Bram Moolenaar01688ad2016-10-27 20:00:07 +02005960 * Return TRUE when there is any job that has an exit callback and might exit,
5961 * which means job_check_ended() should be called more often.
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005962 */
5963 int
Bram Moolenaarcf089462016-06-12 21:18:43 +02005964has_pending_job(void)
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005965{
5966 job_T *job;
5967
Bram Moolenaaraeea7212020-04-02 18:50:46 +02005968 FOR_ALL_JOBS(job)
Bram Moolenaarc667da52019-11-30 20:52:27 +01005969 // Only should check if the channel has been closed, if the channel is
5970 // open the job won't exit.
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005971 if ((job->jv_status == JOB_STARTED && !job_channel_still_useful(job))
5972 || (job->jv_status == JOB_FINISHED
5973 && job_channel_can_close(job)))
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005974 return TRUE;
5975 return FALSE;
5976}
5977
Bram Moolenaar97792de2016-10-15 18:36:49 +02005978#define MAX_CHECK_ENDED 8
5979
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02005980/*
Bram Moolenaar36e0f7d2016-05-08 13:21:12 +02005981 * Called once in a while: check if any jobs that seem useful have ended.
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005982 * Returns TRUE if a job did end.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005983 */
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005984 int
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005985job_check_ended(void)
5986{
Bram Moolenaar97792de2016-10-15 18:36:49 +02005987 int i;
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005988 int did_end = FALSE;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005989
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005990 // be quick if there are no jobs to check
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005991 if (first_job == NULL)
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005992 return did_end;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005993
Bram Moolenaar97792de2016-10-15 18:36:49 +02005994 for (i = 0; i < MAX_CHECK_ENDED; ++i)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01005995 {
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01005996 // NOTE: mch_detect_ended_job() must only return a job of which the
5997 // status was just set to JOB_ENDED.
Bram Moolenaar97792de2016-10-15 18:36:49 +02005998 job_T *job = mch_detect_ended_job(first_job);
5999
6000 if (job == NULL)
6001 break;
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01006002 did_end = TRUE;
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01006003 job_cleanup(job); // may add "job" to jobs_to_free
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006004 }
Bram Moolenaar97792de2016-10-15 18:36:49 +02006005
Bram Moolenaar2a4857a2019-01-29 22:29:07 +01006006 // Actually free jobs that were cleaned up.
6007 free_jobs_to_free_later();
6008
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02006009 if (channel_need_redraw)
6010 {
6011 channel_need_redraw = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02006012 redraw_after_callback(TRUE);
Bram Moolenaarcf7c11a2016-06-02 20:05:26 +02006013 }
Bram Moolenaarcd1a62d2018-12-14 21:32:02 +01006014 return did_end;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006015}
6016
6017/*
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006018 * Create a job and return it. Implements job_start().
Bram Moolenaar13568252018-03-16 20:46:58 +01006019 * "argv_arg" is only for Unix.
6020 * When "argv_arg" is NULL then "argvars" is used.
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006021 * The returned job has a refcount of one.
6022 * Returns NULL when out of memory.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006023 */
6024 job_T *
Bram Moolenaar493359e2018-06-12 20:25:52 +02006025job_start(
6026 typval_T *argvars,
Bram Moolenaarbd67aac2019-09-21 23:09:04 +02006027 char **argv_arg UNUSED,
Bram Moolenaar493359e2018-06-12 20:25:52 +02006028 jobopt_T *opt_arg,
Bram Moolenaar21109272020-01-30 16:27:20 +01006029 job_T **term_job)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006030{
6031 job_T *job;
6032 char_u *cmd = NULL;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006033 char **argv = NULL;
6034 int argc = 0;
Bram Moolenaar538feb52020-01-20 21:59:39 +01006035 int i;
Bram Moolenaar20608922018-04-21 22:30:08 +02006036#if defined(UNIX)
6037# define USE_ARGV
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006038#else
6039 garray_T ga;
6040#endif
6041 jobopt_T opt;
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02006042 ch_part_T part;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006043
6044 job = job_alloc();
6045 if (job == NULL)
6046 return NULL;
6047
6048 job->jv_status = JOB_FAILED;
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006049#ifndef USE_ARGV
6050 ga_init2(&ga, (int)sizeof(char*), 20);
6051#endif
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006052
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006053 if (opt_arg != NULL)
6054 opt = *opt_arg;
6055 else
6056 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01006057 // Default mode is NL.
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006058 clear_job_options(&opt);
6059 opt.jo_mode = MODE_NL;
6060 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar8ed54002017-08-11 22:22:36 +02006061 JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
6062 + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE,
6063 JO2_ENV + JO2_CWD) == FAIL)
Bram Moolenaar3c3a80d2017-08-03 17:06:45 +02006064 goto theend;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006065 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006066
Bram Moolenaarc667da52019-11-30 20:52:27 +01006067 // Check that when io is "file" that there is a file name.
Bram Moolenaardc0ccae2016-10-09 17:28:01 +02006068 for (part = PART_OUT; part < PART_COUNT; ++part)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006069 if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
6070 && opt.jo_io[part] == JIO_FILE
6071 && (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
6072 || *opt.jo_io_name[part] == NUL))
6073 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006074 emsg(_("E920: _io file requires _name to be set"));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006075 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006076 }
6077
6078 if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
6079 {
6080 buf_T *buf = NULL;
6081
Bram Moolenaarc667da52019-11-30 20:52:27 +01006082 // check that we can find the buffer before starting the job
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006083 if (opt.jo_set & JO_IN_BUF)
6084 {
6085 buf = buflist_findnr(opt.jo_io_buf[PART_IN]);
6086 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006087 semsg(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006088 }
6089 else if (!(opt.jo_set & JO_IN_NAME))
6090 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006091 emsg(_("E915: in_io buffer requires in_buf or in_name to be set"));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006092 }
6093 else
6094 buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
6095 if (buf == NULL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006096 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006097 if (buf->b_ml.ml_mfp == NULL)
6098 {
6099 char_u numbuf[NUMBUFLEN];
6100 char_u *s;
6101
6102 if (opt.jo_set & JO_IN_BUF)
6103 {
6104 sprintf((char *)numbuf, "%d", opt.jo_io_buf[PART_IN]);
6105 s = numbuf;
6106 }
6107 else
6108 s = opt.jo_io_name[PART_IN];
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006109 semsg(_("E918: buffer must be loaded: %s"), s);
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006110 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006111 }
6112 job->jv_in_buf = buf;
6113 }
6114
6115 job_set_options(job, &opt);
6116
Bram Moolenaar13568252018-03-16 20:46:58 +01006117#ifdef USE_ARGV
6118 if (argv_arg != NULL)
6119 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01006120 // Make a copy of argv_arg for job->jv_argv.
Bram Moolenaar20608922018-04-21 22:30:08 +02006121 for (i = 0; argv_arg[i] != NULL; i++)
6122 argc++;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006123 argv = ALLOC_MULT(char *, argc + 1);
Bram Moolenaar20608922018-04-21 22:30:08 +02006124 if (argv == NULL)
6125 goto theend;
6126 for (i = 0; i < argc; i++)
6127 argv[i] = (char *)vim_strsave((char_u *)argv_arg[i]);
6128 argv[argc] = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01006129 }
6130 else
6131#endif
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006132 if (argvars[0].v_type == VAR_STRING)
6133 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01006134 // Command is a string.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006135 cmd = argvars[0].vval.v_string;
Bram Moolenaar7c2a2f82019-12-22 18:28:51 +01006136 if (cmd == NULL || *skipwhite(cmd) == NUL)
Bram Moolenaar80385682016-03-27 19:13:35 +02006137 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006138 emsg(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006139 goto theend;
Bram Moolenaar80385682016-03-27 19:13:35 +02006140 }
Bram Moolenaarebe74b72018-04-21 23:34:43 +02006141
6142 if (build_argv_from_string(cmd, &argv, &argc) == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006143 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006144 }
6145 else if (argvars[0].v_type != VAR_LIST
6146 || argvars[0].vval.v_list == NULL
6147 || argvars[0].vval.v_list->lv_len < 1)
6148 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006149 emsg(_(e_invarg));
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006150 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006151 }
6152 else
6153 {
Bram Moolenaarebe74b72018-04-21 23:34:43 +02006154 list_T *l = argvars[0].vval.v_list;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006155
Bram Moolenaarebe74b72018-04-21 23:34:43 +02006156 if (build_argv_from_list(l, &argv, &argc) == FAIL)
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006157 goto theend;
Bram Moolenaarba0a7472019-12-22 16:09:06 +01006158
6159 // Empty command is invalid.
Bram Moolenaarba0a7472019-12-22 16:09:06 +01006160 if (argc == 0 || *skipwhite((char_u *)argv[0]) == NUL)
6161 {
6162 emsg(_(e_invarg));
6163 goto theend;
6164 }
Bram Moolenaar7c2a2f82019-12-22 18:28:51 +01006165#ifndef USE_ARGV
Bram Moolenaardcaa6132017-08-13 17:13:09 +02006166 if (win32_build_cmd(l, &ga) == FAIL)
6167 goto theend;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006168 cmd = ga.ga_data;
Bram Moolenaarba0a7472019-12-22 16:09:06 +01006169 if (cmd == NULL || *skipwhite(cmd) == NUL)
Bram Moolenaara27655e2019-12-21 22:22:01 +01006170 {
6171 emsg(_(e_invarg));
6172 goto theend;
6173 }
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006174#endif
6175 }
6176
Bram Moolenaarc667da52019-11-30 20:52:27 +01006177 // Save the command used to start the job.
Bram Moolenaarb2ed6802018-05-13 14:05:18 +02006178 job->jv_argv = argv;
Bram Moolenaare1fc5152018-04-21 19:49:08 +02006179
Bram Moolenaar21109272020-01-30 16:27:20 +01006180 if (term_job != NULL)
6181 *term_job = job;
6182
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006183#ifdef USE_ARGV
6184 if (ch_log_active())
6185 {
6186 garray_T ga;
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006187
6188 ga_init2(&ga, (int)sizeof(char), 200);
6189 for (i = 0; i < argc; ++i)
6190 {
6191 if (i > 0)
6192 ga_concat(&ga, (char_u *)" ");
6193 ga_concat(&ga, (char_u *)argv[i]);
6194 }
Bram Moolenaar04af1962019-04-12 21:19:04 +02006195 ga_append(&ga, NUL);
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02006196 ch_log(NULL, "Starting job: %s", (char *)ga.ga_data);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006197 ga_clear(&ga);
6198 }
Bram Moolenaar21109272020-01-30 16:27:20 +01006199 mch_job_start(argv, job, &opt, term_job != NULL);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006200#else
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02006201 ch_log(NULL, "Starting job: %s", (char *)cmd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02006202 mch_job_start((char *)cmd, job, &opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006203#endif
6204
Bram Moolenaarc667da52019-11-30 20:52:27 +01006205 // If the channel is reading from a buffer, write lines now.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006206 if (job->jv_channel != NULL)
6207 channel_write_in(job->jv_channel);
6208
6209theend:
Bram Moolenaar20608922018-04-21 22:30:08 +02006210#ifndef USE_ARGV
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006211 vim_free(ga.ga_data);
6212#endif
Bram Moolenaar81c3ea72020-01-23 15:48:42 +01006213 if (argv != NULL && argv != job->jv_argv)
Bram Moolenaar538feb52020-01-20 21:59:39 +01006214 {
6215 for (i = 0; argv[i] != NULL; i++)
6216 vim_free(argv[i]);
Bram Moolenaar20608922018-04-21 22:30:08 +02006217 vim_free(argv);
Bram Moolenaar538feb52020-01-20 21:59:39 +01006218 }
Bram Moolenaar0e4c1de2016-04-07 21:40:38 +02006219 free_job_options(&opt);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006220 return job;
6221}
6222
6223/*
6224 * Get the status of "job" and invoke the exit callback when needed.
6225 * The returned string is not allocated.
6226 */
6227 char *
6228job_status(job_T *job)
6229{
6230 char *result;
6231
Bram Moolenaar7df915d2016-11-17 17:25:32 +01006232 if (job->jv_status >= JOB_ENDED)
Bram Moolenaarc667da52019-11-30 20:52:27 +01006233 // No need to check, dead is dead.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006234 result = "dead";
6235 else if (job->jv_status == JOB_FAILED)
6236 result = "fail";
6237 else
6238 {
6239 result = mch_job_status(job);
6240 if (job->jv_status == JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02006241 job_cleanup(job);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006242 }
6243 return result;
6244}
6245
Bram Moolenaar8950a562016-03-12 15:22:55 +01006246/*
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006247 * Send a signal to "job". Implements job_stop().
6248 * When "type" is not NULL use this for the type.
6249 * Otherwise use argvars[1] for the type.
6250 */
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006251 int
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006252job_stop(job_T *job, typval_T *argvars, char *type)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006253{
6254 char_u *arg;
6255
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006256 if (type != NULL)
6257 arg = (char_u *)type;
6258 else if (argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006259 arg = (char_u *)"";
6260 else
6261 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006262 arg = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006263 if (arg == NULL)
6264 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006265 emsg(_(e_invarg));
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006266 return 0;
6267 }
6268 }
Bram Moolenaar61a66052017-07-22 18:39:00 +02006269 if (job->jv_status == JOB_FAILED)
6270 {
6271 ch_log(job->jv_channel, "Job failed to start, job_stop() skipped");
6272 return 0;
6273 }
Bram Moolenaar1a9020d2017-04-29 16:24:38 +02006274 if (job->jv_status == JOB_ENDED)
6275 {
6276 ch_log(job->jv_channel, "Job has already ended, job_stop() skipped");
6277 return 0;
6278 }
Bram Moolenaar2f3a90a2017-08-03 14:49:29 +02006279 ch_log(job->jv_channel, "Stopping job with '%s'", (char *)arg);
Bram Moolenaar2d33e902017-08-11 16:31:54 +02006280 if (mch_signal_job(job, arg) == FAIL)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006281 return 0;
6282
Bram Moolenaarc667da52019-11-30 20:52:27 +01006283 // Assume that only "kill" will kill the job.
Bram Moolenaar1a9020d2017-04-29 16:24:38 +02006284 if (job->jv_channel != NULL && STRCMP(arg, "kill") == 0)
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006285 job->jv_channel->ch_job_killed = TRUE;
6286
Bram Moolenaarc667da52019-11-30 20:52:27 +01006287 // We don't try freeing the job, obviously the caller still has a
6288 // reference to it.
Bram Moolenaar8e2c9422016-03-12 13:43:33 +01006289 return 1;
6290}
6291
Bram Moolenaarf2732452018-06-03 14:47:35 +02006292 void
6293invoke_prompt_callback(void)
6294{
6295 typval_T rettv;
Bram Moolenaarf2732452018-06-03 14:47:35 +02006296 typval_T argv[2];
6297 char_u *text;
6298 char_u *prompt;
6299 linenr_T lnum = curbuf->b_ml.ml_line_count;
6300
6301 // Add a new line for the prompt before invoking the callback, so that
6302 // text can always be inserted above the last line.
6303 ml_append(lnum, (char_u *)"", 0, FALSE);
6304 curwin->w_cursor.lnum = lnum + 1;
6305 curwin->w_cursor.col = 0;
6306
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02006307 if (curbuf->b_prompt_callback.cb_name == NULL
6308 || *curbuf->b_prompt_callback.cb_name == NUL)
Bram Moolenaarf2732452018-06-03 14:47:35 +02006309 return;
6310 text = ml_get(lnum);
6311 prompt = prompt_text();
6312 if (STRLEN(text) >= STRLEN(prompt))
6313 text += STRLEN(prompt);
6314 argv[0].v_type = VAR_STRING;
6315 argv[0].vval.v_string = vim_strsave(text);
6316 argv[1].v_type = VAR_UNKNOWN;
6317
Bram Moolenaarc6538bc2019-08-03 18:17:11 +02006318 call_callback(&curbuf->b_prompt_callback, -1, &rettv, 1, argv);
Bram Moolenaarf2732452018-06-03 14:47:35 +02006319 clear_tv(&argv[0]);
6320 clear_tv(&rettv);
6321}
6322
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02006323/*
6324 * Return TRUE when the interrupt callback was invoked.
6325 */
6326 int
6327invoke_prompt_interrupt(void)
6328{
6329 typval_T rettv;
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02006330 typval_T argv[1];
6331
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02006332 if (curbuf->b_prompt_interrupt.cb_name == NULL
6333 || *curbuf->b_prompt_interrupt.cb_name == NUL)
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02006334 return FALSE;
6335 argv[0].v_type = VAR_UNKNOWN;
6336
6337 got_int = FALSE; // don't skip executing commands
Bram Moolenaarc6538bc2019-08-03 18:17:11 +02006338 call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02006339 clear_tv(&rettv);
6340 return TRUE;
6341}
6342
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02006343/*
6344 * "prompt_setcallback({buffer}, {callback})" function
6345 */
6346 void
6347f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
6348{
6349 buf_T *buf;
6350 callback_T callback;
6351
6352 if (check_secure())
6353 return;
6354 buf = tv_get_buf(&argvars[0], FALSE);
6355 if (buf == NULL)
6356 return;
6357
6358 callback = get_callback(&argvars[1]);
6359 if (callback.cb_name == NULL)
6360 return;
6361
6362 free_callback(&buf->b_prompt_callback);
6363 set_callback(&buf->b_prompt_callback, &callback);
6364}
6365
6366/*
6367 * "prompt_setinterrupt({buffer}, {callback})" function
6368 */
6369 void
6370f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
6371{
6372 buf_T *buf;
6373 callback_T callback;
6374
6375 if (check_secure())
6376 return;
6377 buf = tv_get_buf(&argvars[0], FALSE);
6378 if (buf == NULL)
6379 return;
6380
6381 callback = get_callback(&argvars[1]);
6382 if (callback.cb_name == NULL)
6383 return;
6384
6385 free_callback(&buf->b_prompt_interrupt);
6386 set_callback(&buf->b_prompt_interrupt, &callback);
6387}
6388
6389/*
6390 * "prompt_setprompt({buffer}, {text})" function
6391 */
6392 void
6393f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
6394{
6395 buf_T *buf;
6396 char_u *text;
6397
6398 if (check_secure())
6399 return;
6400 buf = tv_get_buf(&argvars[0], FALSE);
6401 if (buf == NULL)
6402 return;
6403
6404 text = tv_get_string(&argvars[1]);
6405 vim_free(buf->b_prompt_text);
6406 buf->b_prompt_text = vim_strsave(text);
6407}
6408
6409/*
6410 * "ch_canread()" function
6411 */
6412 void
6413f_ch_canread(typval_T *argvars, typval_T *rettv)
6414{
6415 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6416
6417 rettv->vval.v_number = 0;
6418 if (channel != NULL)
6419 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
6420 || channel_has_readahead(channel, PART_OUT)
6421 || channel_has_readahead(channel, PART_ERR);
6422}
6423
6424/*
6425 * "ch_close()" function
6426 */
6427 void
6428f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
6429{
6430 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
6431
6432 if (channel != NULL)
6433 {
6434 channel_close(channel, FALSE);
6435 channel_clear(channel);
6436 }
6437}
6438
6439/*
6440 * "ch_close()" function
6441 */
6442 void
6443f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
6444{
6445 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
6446
6447 if (channel != NULL)
6448 channel_close_in(channel);
6449}
6450
6451/*
6452 * "ch_getbufnr()" function
6453 */
6454 void
6455f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
6456{
6457 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6458
6459 rettv->vval.v_number = -1;
6460 if (channel != NULL)
6461 {
6462 char_u *what = tv_get_string(&argvars[1]);
6463 int part;
6464
6465 if (STRCMP(what, "err") == 0)
6466 part = PART_ERR;
6467 else if (STRCMP(what, "out") == 0)
6468 part = PART_OUT;
6469 else if (STRCMP(what, "in") == 0)
6470 part = PART_IN;
6471 else
6472 part = PART_SOCK;
6473 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
6474 rettv->vval.v_number =
6475 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
6476 }
6477}
6478
6479/*
6480 * "ch_getjob()" function
6481 */
6482 void
6483f_ch_getjob(typval_T *argvars, typval_T *rettv)
6484{
6485 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6486
6487 if (channel != NULL)
6488 {
6489 rettv->v_type = VAR_JOB;
6490 rettv->vval.v_job = channel->ch_job;
6491 if (channel->ch_job != NULL)
6492 ++channel->ch_job->jv_refcount;
6493 }
6494}
6495
6496/*
6497 * "ch_info()" function
6498 */
6499 void
6500f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
6501{
6502 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6503
6504 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
6505 channel_info(channel, rettv->vval.v_dict);
6506}
6507
6508/*
6509 * "ch_log()" function
6510 */
6511 void
6512f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
6513{
6514 char_u *msg = tv_get_string(&argvars[0]);
6515 channel_T *channel = NULL;
6516
6517 if (argvars[1].v_type != VAR_UNKNOWN)
6518 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
6519
6520 ch_log(channel, "%s", msg);
6521}
6522
6523/*
6524 * "ch_logfile()" function
6525 */
6526 void
6527f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
6528{
6529 char_u *fname;
6530 char_u *opt = (char_u *)"";
6531 char_u buf[NUMBUFLEN];
6532
Bram Moolenaarc667da52019-11-30 20:52:27 +01006533 // Don't open a file in restricted mode.
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02006534 if (check_restricted() || check_secure())
6535 return;
6536 fname = tv_get_string(&argvars[0]);
6537 if (argvars[1].v_type == VAR_STRING)
6538 opt = tv_get_string_buf(&argvars[1], buf);
6539 ch_logfile(fname, opt);
6540}
6541
6542/*
6543 * "ch_open()" function
6544 */
6545 void
6546f_ch_open(typval_T *argvars, typval_T *rettv)
6547{
6548 rettv->v_type = VAR_CHANNEL;
6549 if (check_restricted() || check_secure())
6550 return;
6551 rettv->vval.v_channel = channel_open_func(argvars);
6552}
6553
6554/*
6555 * "ch_read()" function
6556 */
6557 void
6558f_ch_read(typval_T *argvars, typval_T *rettv)
6559{
6560 common_channel_read(argvars, rettv, FALSE, FALSE);
6561}
6562
6563/*
6564 * "ch_readblob()" function
6565 */
6566 void
6567f_ch_readblob(typval_T *argvars, typval_T *rettv)
6568{
6569 common_channel_read(argvars, rettv, TRUE, TRUE);
6570}
6571
6572/*
6573 * "ch_readraw()" function
6574 */
6575 void
6576f_ch_readraw(typval_T *argvars, typval_T *rettv)
6577{
6578 common_channel_read(argvars, rettv, TRUE, FALSE);
6579}
6580
6581/*
6582 * "ch_evalexpr()" function
6583 */
6584 void
6585f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
6586{
6587 ch_expr_common(argvars, rettv, TRUE);
6588}
6589
6590/*
6591 * "ch_sendexpr()" function
6592 */
6593 void
6594f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
6595{
6596 ch_expr_common(argvars, rettv, FALSE);
6597}
6598
6599/*
6600 * "ch_evalraw()" function
6601 */
6602 void
6603f_ch_evalraw(typval_T *argvars, typval_T *rettv)
6604{
6605 ch_raw_common(argvars, rettv, TRUE);
6606}
6607
6608/*
6609 * "ch_sendraw()" function
6610 */
6611 void
6612f_ch_sendraw(typval_T *argvars, typval_T *rettv)
6613{
6614 ch_raw_common(argvars, rettv, FALSE);
6615}
6616
6617/*
6618 * "ch_setoptions()" function
6619 */
6620 void
6621f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6622{
6623 channel_T *channel;
6624 jobopt_T opt;
6625
6626 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6627 if (channel == NULL)
6628 return;
6629 clear_job_options(&opt);
6630 if (get_job_options(&argvars[1], &opt,
6631 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
6632 channel_set_options(channel, &opt);
6633 free_job_options(&opt);
6634}
6635
6636/*
6637 * "ch_status()" function
6638 */
6639 void
6640f_ch_status(typval_T *argvars, typval_T *rettv)
6641{
6642 channel_T *channel;
6643 jobopt_T opt;
6644 int part = -1;
6645
Bram Moolenaarc667da52019-11-30 20:52:27 +01006646 // return an empty string by default
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02006647 rettv->v_type = VAR_STRING;
6648 rettv->vval.v_string = NULL;
6649
6650 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6651
6652 if (argvars[1].v_type != VAR_UNKNOWN)
6653 {
6654 clear_job_options(&opt);
6655 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
6656 && (opt.jo_set & JO_PART))
6657 part = opt.jo_part;
6658 }
6659
6660 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
6661}
6662
6663/*
6664 * Get the job from the argument.
6665 * Returns NULL if the job is invalid.
6666 */
6667 static job_T *
6668get_job_arg(typval_T *tv)
6669{
6670 job_T *job;
6671
6672 if (tv->v_type != VAR_JOB)
6673 {
6674 semsg(_(e_invarg2), tv_get_string(tv));
6675 return NULL;
6676 }
6677 job = tv->vval.v_job;
6678
6679 if (job == NULL)
6680 emsg(_("E916: not a valid job"));
6681 return job;
6682}
6683
6684/*
6685 * "job_getchannel()" function
6686 */
6687 void
6688f_job_getchannel(typval_T *argvars, typval_T *rettv)
6689{
6690 job_T *job = get_job_arg(&argvars[0]);
6691
6692 if (job != NULL)
6693 {
6694 rettv->v_type = VAR_CHANNEL;
6695 rettv->vval.v_channel = job->jv_channel;
6696 if (job->jv_channel != NULL)
6697 ++job->jv_channel->ch_refcount;
6698 }
6699}
6700
6701/*
6702 * Implementation of job_info().
6703 */
6704 static void
6705job_info(job_T *job, dict_T *dict)
6706{
6707 dictitem_T *item;
6708 varnumber_T nr;
6709 list_T *l;
6710 int i;
6711
6712 dict_add_string(dict, "status", (char_u *)job_status(job));
6713
6714 item = dictitem_alloc((char_u *)"channel");
6715 if (item == NULL)
6716 return;
6717 item->di_tv.v_type = VAR_CHANNEL;
6718 item->di_tv.vval.v_channel = job->jv_channel;
6719 if (job->jv_channel != NULL)
6720 ++job->jv_channel->ch_refcount;
6721 if (dict_add(dict, item) == FAIL)
6722 dictitem_free(item);
6723
6724#ifdef UNIX
6725 nr = job->jv_pid;
6726#else
6727 nr = job->jv_proc_info.dwProcessId;
6728#endif
6729 dict_add_number(dict, "process", nr);
6730 dict_add_string(dict, "tty_in", job->jv_tty_in);
6731 dict_add_string(dict, "tty_out", job->jv_tty_out);
6732
6733 dict_add_number(dict, "exitval", job->jv_exitval);
6734 dict_add_string(dict, "exit_cb", job->jv_exit_cb.cb_name);
6735 dict_add_string(dict, "stoponexit", job->jv_stoponexit);
6736#ifdef UNIX
6737 dict_add_string(dict, "termsig", job->jv_termsig);
6738#endif
6739#ifdef MSWIN
6740 dict_add_string(dict, "tty_type", job->jv_tty_type);
6741#endif
6742
6743 l = list_alloc();
6744 if (l != NULL)
6745 {
6746 dict_add_list(dict, "cmd", l);
6747 if (job->jv_argv != NULL)
6748 for (i = 0; job->jv_argv[i] != NULL; i++)
6749 list_append_string(l, (char_u *)job->jv_argv[i], -1);
6750 }
6751}
6752
6753/*
6754 * Implementation of job_info() to return info for all jobs.
6755 */
6756 static void
6757job_info_all(list_T *l)
6758{
6759 job_T *job;
6760 typval_T tv;
6761
Bram Moolenaaraeea7212020-04-02 18:50:46 +02006762 FOR_ALL_JOBS(job)
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02006763 {
6764 tv.v_type = VAR_JOB;
6765 tv.vval.v_job = job;
6766
6767 if (list_append_tv(l, &tv) != OK)
6768 return;
6769 }
6770}
6771
6772/*
6773 * "job_info()" function
6774 */
6775 void
6776f_job_info(typval_T *argvars, typval_T *rettv)
6777{
6778 if (argvars[0].v_type != VAR_UNKNOWN)
6779 {
6780 job_T *job = get_job_arg(&argvars[0]);
6781
6782 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6783 job_info(job, rettv->vval.v_dict);
6784 }
6785 else if (rettv_list_alloc(rettv) == OK)
6786 job_info_all(rettv->vval.v_list);
6787}
6788
6789/*
6790 * "job_setoptions()" function
6791 */
6792 void
6793f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6794{
6795 job_T *job = get_job_arg(&argvars[0]);
6796 jobopt_T opt;
6797
6798 if (job == NULL)
6799 return;
6800 clear_job_options(&opt);
6801 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
6802 job_set_options(job, &opt);
6803 free_job_options(&opt);
6804}
6805
6806/*
6807 * "job_start()" function
6808 */
6809 void
6810f_job_start(typval_T *argvars, typval_T *rettv)
6811{
6812 rettv->v_type = VAR_JOB;
6813 if (check_restricted() || check_secure())
6814 return;
Bram Moolenaar21109272020-01-30 16:27:20 +01006815 rettv->vval.v_job = job_start(argvars, NULL, NULL, NULL);
Bram Moolenaar0a1f56f2019-06-24 00:43:35 +02006816}
6817
6818/*
6819 * "job_status()" function
6820 */
6821 void
6822f_job_status(typval_T *argvars, typval_T *rettv)
6823{
6824 job_T *job = get_job_arg(&argvars[0]);
6825
6826 if (job != NULL)
6827 {
6828 rettv->v_type = VAR_STRING;
6829 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6830 }
6831}
6832
6833/*
6834 * "job_stop()" function
6835 */
6836 void
6837f_job_stop(typval_T *argvars, typval_T *rettv)
6838{
6839 job_T *job = get_job_arg(&argvars[0]);
6840
6841 if (job != NULL)
6842 rettv->vval.v_number = job_stop(job, argvars, NULL);
6843}
6844
Bram Moolenaarc667da52019-11-30 20:52:27 +01006845#endif // FEAT_JOB_CHANNEL