Mercurial > vim
comparison src/channel.c @ 7770:42c1a4e63d12 v7.4.1182
commit https://github.com/vim/vim/commit/d04a020a8a8d7a438b091d49218c438880beb50c
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jan 26 23:30:18 2016 +0100
patch 7.4.1182
Problem: Still socket code intertwined with netbeans.
Solution: Move code from netbeans.c to channel.c
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 26 Jan 2016 23:45:05 +0100 |
parents | 6069f43cea4e |
children | 0677c5b880d1 |
comparison
equal
deleted
inserted
replaced
7769:3bdef7bd2244 | 7770:42c1a4e63d12 |
---|---|
12 | 12 |
13 #include "vim.h" | 13 #include "vim.h" |
14 | 14 |
15 #if defined(FEAT_CHANNEL) || defined(PROTO) | 15 #if defined(FEAT_CHANNEL) || defined(PROTO) |
16 | 16 |
17 /* | |
18 * Change the zero to 1 to enable debugging. | |
19 * This will write a file "channel_debug.log". | |
20 */ | |
21 #if 0 | |
22 # define CHERROR(fmt, arg) cherror(fmt, arg) | |
23 # define CHLOG(idx, send, buf) chlog(idx, send, buf) | |
24 # define CHFILE "channel_debug.log" | |
25 | |
26 static void cherror(char *fmt, char *arg); | |
27 static void chlog(int send, char_u *buf); | |
28 #else | |
29 # define CHERROR(fmt, arg) | |
30 # define CHLOG(idx, send, buf) | |
31 #endif | |
32 | |
33 /* TRUE when netbeans is running with a GUI. */ | |
34 #ifdef FEAT_GUI | |
35 # define CH_HAS_GUI (gui.in_use || gui.starting) | |
36 #endif | |
37 | |
38 /* Note: when making changes here also adjust configure.in. */ | |
39 #ifdef WIN32 | |
40 /* WinSock API is separated from C API, thus we can't use read(), write(), | |
41 * errno... */ | |
42 # define SOCK_ERRNO errno = WSAGetLastError() | |
43 # undef ECONNREFUSED | |
44 # define ECONNREFUSED WSAECONNREFUSED | |
45 # ifdef EINTR | |
46 # undef EINTR | |
47 # endif | |
48 # define EINTR WSAEINTR | |
49 # define sock_write(sd, buf, len) send(sd, buf, len, 0) | |
50 # define sock_read(sd, buf, len) recv(sd, buf, len, 0) | |
51 # define sock_close(sd) closesocket(sd) | |
52 # define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */ | |
53 #else | |
54 # include <netdb.h> | |
55 # include <netinet/in.h> | |
56 | |
57 # include <sys/socket.h> | |
58 # ifdef HAVE_LIBGEN_H | |
59 # include <libgen.h> | |
60 # endif | |
61 # define SOCK_ERRNO | |
62 # define sock_write(sd, buf, len) write(sd, buf, len) | |
63 # define sock_read(sd, buf, len) read(sd, buf, len) | |
64 # define sock_close(sd) close(sd) | |
65 #endif | |
66 | |
67 #ifdef FEAT_GUI_W32 | |
68 extern HWND s_hwnd; /* Gvim's Window handle */ | |
69 #endif | |
70 | |
71 struct readqueue | |
72 { | |
73 char_u *buffer; | |
74 struct readqueue *next; | |
75 struct readqueue *prev; | |
76 }; | |
77 typedef struct readqueue queue_T; | |
78 | |
17 typedef struct { | 79 typedef struct { |
18 sock_T ch_fd; | 80 sock_T ch_fd; /* the socket, -1 for a closed channel */ |
19 int ch_idx; | 81 int ch_idx; /* used by channel_poll_setup() */ |
82 queue_T ch_head; /* dummy node, header for circular queue */ | |
83 | |
84 int ch_error; /* When TRUE an error was reported. Avoids giving | |
85 * pages full of error messages when the other side | |
86 * has exited, only mention the first error until the | |
87 * connection works again. */ | |
88 #ifdef FEAT_GUI_X11 | |
89 XtInputId ch_inputHandler; /* Cookie for input */ | |
90 #endif | |
91 #ifdef FEAT_GUI_GTK | |
92 gint ch_inputHandler; /* Cookie for input */ | |
93 #endif | |
94 #ifdef FEAT_GUI_W32 | |
95 int ch_inputHandler = -1; /* simply ret.value of WSAAsyncSelect() */ | |
96 #endif | |
97 | |
98 void (*ch_close_cb)(void); /* callback invoked when channel is closed */ | |
20 } channel_T; | 99 } channel_T; |
21 | 100 |
101 /* | |
102 * Information about all channels. | |
103 * There can be gaps for closed channels, they will be reused later. | |
104 */ | |
22 static channel_T *channels = NULL; | 105 static channel_T *channels = NULL; |
23 static int channel_count = 0; | 106 static int channel_count = 0; |
24 | 107 |
25 /* | 108 /* |
109 * TODO: open debug file when desired. | |
110 */ | |
111 FILE *debugfd = NULL; | |
112 | |
113 /* | |
26 * Add a new channel slot, return the index. | 114 * Add a new channel slot, return the index. |
27 * Returns -1 if out of space. | 115 * The channel isn't actually used into ch_fd is set >= 0; |
116 * Returns -1 if all channels are in use. | |
28 */ | 117 */ |
29 static int | 118 static int |
30 add_channel(void) | 119 add_channel(void) |
31 { | 120 { |
32 int idx; | 121 int idx; |
37 if (channels[idx].ch_fd < 0) | 126 if (channels[idx].ch_fd < 0) |
38 /* re-use a closed channel slot */ | 127 /* re-use a closed channel slot */ |
39 return idx; | 128 return idx; |
40 if (channel_count == MAX_OPEN_CHANNELS) | 129 if (channel_count == MAX_OPEN_CHANNELS) |
41 return -1; | 130 return -1; |
42 new_channels = (channel_T *)alloc(sizeof(channel_T) * channel_count + 1); | 131 new_channels = (channel_T *)alloc(sizeof(channel_T) * (channel_count + 1)); |
43 if (new_channels == NULL) | 132 if (new_channels == NULL) |
44 return -1; | 133 return -1; |
45 if (channels != NULL) | 134 if (channels != NULL) |
46 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count); | 135 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count); |
47 channels = new_channels; | 136 channels = new_channels; |
137 (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T)); | |
138 | |
48 channels[channel_count].ch_fd = (sock_T)-1; | 139 channels[channel_count].ch_fd = (sock_T)-1; |
140 #ifdef FEAT_GUI_X11 | |
141 channels[channel_count].ch_inputHandler = (XtInputId)NULL; | |
142 #endif | |
143 #ifdef FEAT_GUI_GTK | |
144 channels[channel_count].ch_inputHandler = 0; | |
145 #endif | |
146 #ifdef FEAT_GUI_W32 | |
147 channels[channel_count].ch_inputHandler = -1; | |
148 #endif | |
49 | 149 |
50 return channel_count++; | 150 return channel_count++; |
51 } | 151 } |
52 | 152 |
53 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) | 153 #if defined(FEAT_GUI) || defined(PROTO) |
54 static int netbeans_channel = -1; | 154 /* |
55 | 155 * Read a command from netbeans. |
56 /* | 156 */ |
57 * Add the netbeans socket to the channels. | 157 #ifdef FEAT_GUI_X11 |
58 * Return the channel index. | 158 static void |
159 messageFromNetbeans(XtPointer clientData, | |
160 int *unused1 UNUSED, | |
161 XtInputId *unused2 UNUSED) | |
162 { | |
163 channel_read((int)(long)clientData); | |
164 } | |
165 #endif | |
166 | |
167 #ifdef FEAT_GUI_GTK | |
168 static void | |
169 messageFromNetbeans(gpointer clientData, | |
170 gint unused1 UNUSED, | |
171 GdkInputCondition unused2 UNUSED) | |
172 { | |
173 channel_read((int)(long)clientData); | |
174 } | |
175 #endif | |
176 | |
177 static void | |
178 channel_gui_register(int idx) | |
179 { | |
180 channel_T *channel = &channels[idx]; | |
181 | |
182 if (!CH_HAS_GUI) | |
183 return; | |
184 | |
185 # ifdef FEAT_GUI_X11 | |
186 /* tell notifier we are interested in being called | |
187 * when there is input on the editor connection socket | |
188 */ | |
189 if (channel->ch_inputHandler == (XtInputId)NULL) | |
190 channel->ch_inputHandler = | |
191 XtAppAddInput((XtAppContext)app_context, channel->ch_fd, | |
192 (XtPointer)(XtInputReadMask + XtInputExceptMask), | |
193 messageFromNetbeans, (XtPointer)idx); | |
194 # else | |
195 # ifdef FEAT_GUI_GTK | |
196 /* | |
197 * Tell gdk we are interested in being called when there | |
198 * is input on the editor connection socket | |
199 */ | |
200 if (channel->ch_inputHandler == 0) | |
201 channel->ch_inputHandler = | |
202 gdk_input_add((gint)channel->ch_fd, (GdkInputCondition) | |
203 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), | |
204 messageFromNetbeans, (gpointer)(long)idx); | |
205 # else | |
206 # ifdef FEAT_GUI_W32 | |
207 /* | |
208 * Tell Windows we are interested in receiving message when there | |
209 * is input on the editor connection socket. | |
210 * TODO: change WM_NETBEANS to something related to the channel index. | |
211 */ | |
212 if (channel->ch_inputHandler == -1) | |
213 channel->ch_inputHandler = | |
214 WSAAsyncSelect(channel->ch_fd, s_hwnd, WM_NETBEANS, FD_READ); | |
215 # endif | |
216 # endif | |
217 # endif | |
218 } | |
219 | |
220 /* | |
221 * Register any of our file descriptors with the GUI event handling system. | |
222 * Called when the GUI has started. | |
223 */ | |
224 void | |
225 channel_gui_register_all(void) | |
226 { | |
227 int i; | |
228 | |
229 for (i = 0; i < channel_count; ++i) | |
230 if (channels[i].ch_fd >= 0) | |
231 channel_gui_register(i); | |
232 } | |
233 | |
234 static void | |
235 channel_gui_unregister(int idx) | |
236 { | |
237 channel_T *channel = &channels[idx]; | |
238 | |
239 # ifdef FEAT_GUI_X11 | |
240 if (channel->ch_inputHandler != (XtInputId)NULL) | |
241 { | |
242 XtRemoveInput(channel->ch_inputHandler); | |
243 channel->ch_inputHandler = (XtInputId)NULL; | |
244 } | |
245 # else | |
246 # ifdef FEAT_GUI_GTK | |
247 if (channel->ch_inputHandler != 0) | |
248 { | |
249 gdk_input_remove(channel->ch_inputHandler); | |
250 channel->ch_inputHandler = 0; | |
251 } | |
252 # else | |
253 # ifdef FEAT_GUI_W32 | |
254 if (channel->ch_inputHandler == 0) | |
255 { | |
256 WSAAsyncSelect(nbsock, s_hwnd, 0, 0); | |
257 channel->ch_inputHandler = -1; | |
258 } | |
259 # endif | |
260 # endif | |
261 # endif | |
262 } | |
263 | |
264 #endif | |
265 | |
266 /* | |
267 * Open a channel to "hostname":"port". | |
268 * Returns the channel number for success. | |
269 * Returns a negative number for failure. | |
59 */ | 270 */ |
60 int | 271 int |
61 channel_add_netbeans(sock_T fd) | 272 channel_open(char *hostname, int port_in, void (*close_cb)(void)) |
62 { | 273 { |
63 int idx = add_channel(); | 274 int sd; |
64 | 275 struct sockaddr_in server; |
65 if (idx >= 0) | 276 struct hostent * host; |
66 { | 277 #ifdef FEAT_GUI_W32 |
67 channels[idx].ch_fd = fd; | 278 u_short port = port_in; |
68 netbeans_channel = idx; | 279 #else |
69 } | 280 int port = port_in; |
281 #endif | |
282 int idx; | |
283 | |
284 #ifdef FEAT_GUI_W32 | |
285 channel_init_winsock(); | |
286 #endif | |
287 | |
288 idx = add_channel(); | |
289 if (idx < 0) | |
290 { | |
291 CHERROR("All channels are in use\n", ""); | |
292 EMSG(_("E999: All channels are in use")); | |
293 return -1; | |
294 } | |
295 | |
296 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1) | |
297 { | |
298 CHERROR("error in socket() in channel_open()\n", ""); | |
299 PERROR("E999: socket() in channel_open()"); | |
300 return -1; | |
301 } | |
302 | |
303 /* Get the server internet address and put into addr structure */ | |
304 /* fill in the socket address structure and connect to server */ | |
305 vim_memset((char *)&server, 0, sizeof(server)); | |
306 server.sin_family = AF_INET; | |
307 server.sin_port = htons(port); | |
308 if ((host = gethostbyname(hostname)) == NULL) | |
309 { | |
310 CHERROR("error in gethostbyname() in channel_open()\n", ""); | |
311 PERROR("E999: gethostbyname() in channel_open()"); | |
312 sock_close(sd); | |
313 return -1; | |
314 } | |
315 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); | |
316 | |
317 /* Connect to server */ | |
318 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | |
319 { | |
320 SOCK_ERRNO; | |
321 CHERROR("channel_open: Connect failed with errno %d\n", errno); | |
322 if (errno == ECONNREFUSED) | |
323 { | |
324 sock_close(sd); | |
325 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1) | |
326 { | |
327 SOCK_ERRNO; | |
328 CHERROR("socket() retry in channel_open()\n", ""); | |
329 PERROR("E999: socket() retry in channel_open()"); | |
330 return -1; | |
331 } | |
332 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | |
333 { | |
334 int retries = 36; | |
335 int success = FALSE; | |
336 | |
337 SOCK_ERRNO; | |
338 while (retries-- && ((errno == ECONNREFUSED) | |
339 || (errno == EINTR))) | |
340 { | |
341 CHERROR("retrying...\n", ""); | |
342 mch_delay(3000L, TRUE); | |
343 ui_breakcheck(); | |
344 if (got_int) | |
345 { | |
346 errno = EINTR; | |
347 break; | |
348 } | |
349 if (connect(sd, (struct sockaddr *)&server, | |
350 sizeof(server)) == 0) | |
351 { | |
352 success = TRUE; | |
353 break; | |
354 } | |
355 SOCK_ERRNO; | |
356 } | |
357 if (!success) | |
358 { | |
359 /* Get here when the server can't be found. */ | |
360 CHERROR("Cannot connect to port after retry\n", ""); | |
361 PERROR(_("E999: Cannot connect to port after retry2")); | |
362 sock_close(sd); | |
363 return -1; | |
364 } | |
365 } | |
366 } | |
367 else | |
368 { | |
369 CHERROR("Cannot connect to port\n", ""); | |
370 PERROR(_("E999: Cannot connect to port")); | |
371 sock_close(sd); | |
372 return -1; | |
373 } | |
374 } | |
375 | |
376 channels[idx].ch_fd = sd; | |
377 channels[idx].ch_close_cb = close_cb; | |
378 | |
379 #ifdef FEAT_GUI | |
380 channel_gui_register(idx); | |
381 #endif | |
382 | |
70 return idx; | 383 return idx; |
71 } | 384 } |
72 | 385 |
386 /* | |
387 * Return TRUE when channel "idx" is open. | |
388 */ | |
389 int | |
390 channel_is_open(int idx) | |
391 { | |
392 return channels[idx].ch_fd >= 0; | |
393 } | |
394 | |
395 /* | |
396 * Close channel "idx". | |
397 * This does not trigger the close callback. | |
398 */ | |
73 void | 399 void |
74 channel_remove_netbeans() | 400 channel_close(int idx) |
75 { | 401 { |
76 channels[netbeans_channel].ch_fd = (sock_T)-1; | 402 channel_T *channel = &channels[idx]; |
77 netbeans_channel = -1; | 403 |
78 } | 404 if (channel->ch_fd >= 0) |
79 #endif | 405 { |
80 | 406 sock_close(channel->ch_fd); |
81 static void | 407 channel->ch_fd = -1; |
408 #ifdef FEAT_GUI | |
409 channel_gui_unregister(idx); | |
410 #endif | |
411 } | |
412 } | |
413 | |
414 /* | |
415 * Store "buf[len]" on channel "idx". | |
416 */ | |
417 void | |
418 channel_save(int idx, char_u *buf, int len) | |
419 { | |
420 queue_T *node; | |
421 queue_T *head = &channels[idx].ch_head; | |
422 | |
423 node = (queue_T *)alloc(sizeof(queue_T)); | |
424 if (node == NULL) | |
425 return; /* out of memory */ | |
426 node->buffer = alloc(len + 1); | |
427 if (node->buffer == NULL) | |
428 { | |
429 vim_free(node); | |
430 return; /* out of memory */ | |
431 } | |
432 mch_memmove(node->buffer, buf, (size_t)len); | |
433 node->buffer[len] = NUL; | |
434 | |
435 if (head->next == NULL) /* initialize circular queue */ | |
436 { | |
437 head->next = head; | |
438 head->prev = head; | |
439 } | |
440 | |
441 /* insert node at tail of queue */ | |
442 node->next = head; | |
443 node->prev = head->prev; | |
444 head->prev->next = node; | |
445 head->prev = node; | |
446 | |
447 if (debugfd != NULL) | |
448 { | |
449 fprintf(debugfd, "RECV on %d: ", idx); | |
450 fwrite(buf, len, 1, debugfd); | |
451 fprintf(debugfd, "\n"); | |
452 } | |
453 } | |
454 | |
455 /* | |
456 * Return the first buffer from the channel without removing it. | |
457 * Returns NULL if there is nothing. | |
458 */ | |
459 char_u * | |
460 channel_peek(int idx) | |
461 { | |
462 queue_T *head = &channels[idx].ch_head; | |
463 | |
464 if (head->next == head || head->next == NULL) | |
465 return NULL; | |
466 return head->next->buffer; | |
467 } | |
468 | |
469 /* | |
470 * Return the first buffer from the channel and remove it. | |
471 * The caller must free it. | |
472 * Returns NULL if there is nothing. | |
473 */ | |
474 char_u * | |
475 channel_get(int idx) | |
476 { | |
477 queue_T *head = &channels[idx].ch_head; | |
478 queue_T *node; | |
479 char_u *p; | |
480 | |
481 if (head->next == head || head->next == NULL) | |
482 return NULL; | |
483 node = head->next; | |
484 /* dispose of the node but keep the buffer */ | |
485 p = node->buffer; | |
486 head->next = node->next; | |
487 node->next->prev = node->prev; | |
488 vim_free(node); | |
489 return p; | |
490 } | |
491 | |
492 /* | |
493 * Collapses the first and second buffer in the channel "idx". | |
494 * Returns FAIL if that is not possible. | |
495 */ | |
496 int | |
497 channel_collapse(int idx) | |
498 { | |
499 queue_T *head = &channels[idx].ch_head; | |
500 queue_T *node = head->next; | |
501 char_u *p; | |
502 | |
503 if (node == head || node == NULL || node->next == head) | |
504 return FAIL; | |
505 | |
506 p = alloc((unsigned)(STRLEN(node->buffer) | |
507 + STRLEN(node->next->buffer) + 1)); | |
508 if (p == NULL) | |
509 return FAIL; /* out of memory */ | |
510 STRCPY(p, node->buffer); | |
511 STRCAT(p, node->next->buffer); | |
512 vim_free(node->next->buffer); | |
513 node->next->buffer = p; | |
514 | |
515 /* dispose of the node and buffer */ | |
516 head->next = node->next; | |
517 node->next->prev = node->prev; | |
518 vim_free(node->buffer); | |
519 vim_free(node); | |
520 return OK; | |
521 } | |
522 | |
523 /* | |
524 * Clear the read buffer on channel "idx". | |
525 */ | |
526 void | |
527 channel_clear(int idx) | |
528 { | |
529 queue_T *head = &channels[idx].ch_head; | |
530 queue_T *node = head->next; | |
531 queue_T *next; | |
532 | |
533 while (node != NULL && node != head) | |
534 { | |
535 next = node->next; | |
536 vim_free(node->buffer); | |
537 vim_free(node); | |
538 if (next == head) | |
539 { | |
540 head->next = head; | |
541 head->prev = head; | |
542 break; | |
543 } | |
544 node = next; | |
545 } | |
546 } | |
547 | |
548 /* Sent when the channel is found closed when reading. */ | |
549 #define DETACH_MSG "\"DETACH\"\n" | |
550 | |
551 /* Buffer size for reading incoming messages. */ | |
552 #define MAXMSGSIZE 4096 | |
553 | |
554 /* | |
555 * Read from channel "idx". The data is put in the read queue. | |
556 */ | |
557 void | |
82 channel_read(int idx) | 558 channel_read(int idx) |
83 { | 559 { |
84 # ifdef FEAT_NETBEANS_INTG | 560 static char_u *buf = NULL; |
85 if (idx == netbeans_channel) | 561 int len = 0; |
86 netbeans_read(); | 562 int readlen = 0; |
563 #ifdef HAVE_SELECT | |
564 struct timeval tval; | |
565 fd_set rfds; | |
566 #else | |
567 # ifdef HAVE_POLL | |
568 struct pollfd fds; | |
569 # endif | |
570 #endif | |
571 channel_T *channel = &channels[idx]; | |
572 | |
573 if (channel->ch_fd < 0) | |
574 { | |
575 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n"); | |
576 return; | |
577 } | |
578 | |
579 /* Allocate a buffer to read into. */ | |
580 if (buf == NULL) | |
581 { | |
582 buf = alloc(MAXMSGSIZE); | |
583 if (buf == NULL) | |
584 return; /* out of memory! */ | |
585 } | |
586 | |
587 /* Keep on reading for as long as there is something to read. | |
588 * Use select() or poll() to avoid blocking on a message that is exactly | |
589 * MAXMSGSIZE long. */ | |
590 for (;;) | |
591 { | |
592 #ifdef HAVE_SELECT | |
593 FD_ZERO(&rfds); | |
594 FD_SET(channel->ch_fd, &rfds); | |
595 tval.tv_sec = 0; | |
596 tval.tv_usec = 0; | |
597 if (select(channel->ch_fd + 1, &rfds, NULL, NULL, &tval) <= 0) | |
598 break; | |
599 #else | |
600 # ifdef HAVE_POLL | |
601 fds.fd = channel->ch_fd; | |
602 fds.events = POLLIN; | |
603 if (poll(&fds, 1, 0) <= 0) | |
604 break; | |
605 # endif | |
606 #endif | |
607 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE); | |
608 if (len <= 0) | |
609 break; /* error or nothing more to read */ | |
610 | |
611 /* Store the read message in the queue. */ | |
612 channel_save(idx, buf, len); | |
613 readlen += len; | |
614 if (len < MAXMSGSIZE) | |
615 break; /* did read everything that's available */ | |
616 } | |
617 | |
618 /* Reading a socket disconnection (readlen == 0), or a socket error. */ | |
619 if (readlen <= 0) | |
620 { | |
621 /* Queue a "DETACH" netbeans message in the command queue in order to | |
622 * terminate the netbeans session later. Do not end the session here | |
623 * directly as we may be running in the context of a call to | |
624 * netbeans_parse_messages(): | |
625 * netbeans_parse_messages | |
626 * -> autocmd triggered while processing the netbeans cmd | |
627 * -> ui_breakcheck | |
628 * -> gui event loop or select loop | |
629 * -> channel_read() | |
630 */ | |
631 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); | |
632 | |
633 channel_close(idx); | |
634 if (channel->ch_close_cb != NULL) | |
635 (*channel->ch_close_cb)(); | |
636 | |
637 if (len < 0) | |
638 { | |
639 /* Todo: which channel? */ | |
640 CHERROR("%s(): cannot from channel\n", "channel_read"); | |
641 PERROR(_("E999: read from channel")); | |
642 } | |
643 } | |
644 | |
645 #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) | |
646 if (CH_HAS_GUI && gtk_main_level() > 0) | |
647 gtk_main_quit(); | |
648 #endif | |
649 } | |
650 | |
651 /* | |
652 * Write "buf" (NUL terminated string) to channel "idx". | |
653 * When "fun" is not NULL an error message might be given. | |
654 */ | |
655 void | |
656 channel_send(int idx, char_u *buf, char *fun) | |
657 { | |
658 channel_T *channel = &channels[idx]; | |
659 int len = (int)STRLEN(buf); | |
660 | |
661 if (channel->ch_fd < 0) | |
662 { | |
663 if (!channel->ch_error && fun != NULL) | |
664 { | |
665 CHERROR(" %s(): write while not connected\n", fun); | |
666 EMSG2("E630: %s(): write while not connected", fun); | |
667 } | |
668 channel->ch_error = TRUE; | |
669 } | |
670 else if (sock_write(channel->ch_fd, buf, len) != len) | |
671 { | |
672 if (!channel->ch_error && fun != NULL) | |
673 { | |
674 CHERROR(" %s(): write failed\n", fun); | |
675 EMSG2("E631: %s(): write failed", fun); | |
676 } | |
677 channel->ch_error = TRUE; | |
678 } | |
87 else | 679 else |
88 # endif | 680 channel->ch_error = FALSE; |
89 { | 681 } |
90 ; /* TODO: read */ | 682 |
91 } | 683 # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) |
92 } | |
93 | |
94 #if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) | |
95 /* | 684 /* |
96 * Add open channels to the poll struct. | 685 * Add open channels to the poll struct. |
97 * Return the adjusted struct index. | 686 * Return the adjusted struct index. |
98 * The type of "fds" is hidden to avoid problems with the function proto. | 687 * The type of "fds" is hidden to avoid problems with the function proto. |
99 */ | 688 */ |
136 --ret; | 725 --ret; |
137 } | 726 } |
138 | 727 |
139 return ret; | 728 return ret; |
140 } | 729 } |
141 #endif /* UNIX && !HAVE_SELECT */ | 730 # endif /* UNIX && !HAVE_SELECT */ |
142 | 731 |
143 #if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO) | 732 # if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO) |
144 /* | 733 /* |
145 * The type of "rfds" is hidden to avoid problems with the function proto. | 734 * The type of "rfds" is hidden to avoid problems with the function proto. |
146 */ | 735 */ |
147 int | 736 int |
148 channel_select_setup(int maxfd_in, void *rfds_in) | 737 channel_select_setup(int maxfd_in, void *rfds_in) |
180 --ret; | 769 --ret; |
181 } | 770 } |
182 | 771 |
183 return ret; | 772 return ret; |
184 } | 773 } |
185 #endif /* UNIX && HAVE_SELECT */ | 774 # endif /* UNIX && HAVE_SELECT */ |
186 | 775 |
187 #endif /* FEAT_CHANNEL */ | 776 #endif /* FEAT_CHANNEL */ |