Patch 7.4.1182
Problem: Still socket code intertwined with netbeans.
Solution: Move code from netbeans.c to channel.c
Files: src/channel.c, src/netbeans.c, src/proto/channel.pro,
src/proto/netbeans.pro, src/gui.c, src/gui_w48.c
*** ../vim-7.4.1181/src/channel.c 2016-01-24 20:36:18.850082515 +0100
--- src/channel.c 2016-01-26 23:20:41.536676106 +0100
***************
*** 14,30 ****
#if defined(FEAT_CHANNEL) || defined(PROTO)
typedef struct {
! sock_T ch_fd;
! int ch_idx;
} channel_T;
static channel_T *channels = NULL;
static int channel_count = 0;
/*
* Add a new channel slot, return the index.
! * Returns -1 if out of space.
*/
static int
add_channel(void)
--- 14,119 ----
#if defined(FEAT_CHANNEL) || defined(PROTO)
+ /*
+ * Change the zero to 1 to enable debugging.
+ * This will write a file "channel_debug.log".
+ */
+ #if 0
+ # define CHERROR(fmt, arg) cherror(fmt, arg)
+ # define CHLOG(idx, send, buf) chlog(idx, send, buf)
+ # define CHFILE "channel_debug.log"
+
+ static void cherror(char *fmt, char *arg);
+ static void chlog(int send, char_u *buf);
+ #else
+ # define CHERROR(fmt, arg)
+ # define CHLOG(idx, send, buf)
+ #endif
+
+ /* TRUE when netbeans is running with a GUI. */
+ #ifdef FEAT_GUI
+ # define CH_HAS_GUI (gui.in_use || gui.starting)
+ #endif
+
+ /* Note: when making changes here also adjust configure.in. */
+ #ifdef WIN32
+ /* WinSock API is separated from C API, thus we can't use read(), write(),
+ * errno... */
+ # define SOCK_ERRNO errno = WSAGetLastError()
+ # undef ECONNREFUSED
+ # define ECONNREFUSED WSAECONNREFUSED
+ # ifdef EINTR
+ # undef EINTR
+ # endif
+ # define EINTR WSAEINTR
+ # define sock_write(sd, buf, len) send(sd, buf, len, 0)
+ # define sock_read(sd, buf, len) recv(sd, buf, len, 0)
+ # define sock_close(sd) closesocket(sd)
+ # define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
+ #else
+ # include <netdb.h>
+ # include <netinet/in.h>
+
+ # include <sys/socket.h>
+ # ifdef HAVE_LIBGEN_H
+ # include <libgen.h>
+ # endif
+ # define SOCK_ERRNO
+ # define sock_write(sd, buf, len) write(sd, buf, len)
+ # define sock_read(sd, buf, len) read(sd, buf, len)
+ # define sock_close(sd) close(sd)
+ #endif
+
+ #ifdef FEAT_GUI_W32
+ extern HWND s_hwnd; /* Gvim's Window handle */
+ #endif
+
+ struct readqueue
+ {
+ char_u *buffer;
+ struct readqueue *next;
+ struct readqueue *prev;
+ };
+ typedef struct readqueue queue_T;
+
typedef struct {
! sock_T ch_fd; /* the socket, -1 for a closed channel */
! int ch_idx; /* used by channel_poll_setup() */
! queue_T ch_head; /* dummy node, header for circular queue */
!
! int ch_error; /* When TRUE an error was reported. Avoids
giving
! * pages full of error messages when the other side
! * has exited, only mention the first error until the
! * connection works again. */
! #ifdef FEAT_GUI_X11
! XtInputId ch_inputHandler; /* Cookie for input */
! #endif
! #ifdef FEAT_GUI_GTK
! gint ch_inputHandler; /* Cookie for input */
! #endif
! #ifdef FEAT_GUI_W32
! int ch_inputHandler = -1; /* simply ret.value of WSAAsyncSelect()
*/
! #endif
!
! void (*ch_close_cb)(void); /* callback invoked when channel is
closed */
} channel_T;
+ /*
+ * Information about all channels.
+ * There can be gaps for closed channels, they will be reused later.
+ */
static channel_T *channels = NULL;
static int channel_count = 0;
/*
+ * TODO: open debug file when desired.
+ */
+ FILE *debugfd = NULL;
+
+ /*
* Add a new channel slot, return the index.
! * The channel isn't actually used into ch_fd is set >= 0;
! * Returns -1 if all channels are in use.
*/
static int
add_channel(void)
***************
*** 39,97 ****
return idx;
if (channel_count == MAX_OPEN_CHANNELS)
return -1;
! new_channels = (channel_T *)alloc(sizeof(channel_T) * channel_count + 1);
if (new_channels == NULL)
return -1;
if (channels != NULL)
mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
channels = new_channels;
channels[channel_count].ch_fd = (sock_T)-1;
return channel_count++;
}
! #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
! static int netbeans_channel = -1;
/*
! * Add the netbeans socket to the channels.
! * Return the channel index.
*/
int
! channel_add_netbeans(sock_T fd)
{
! int idx = add_channel();
! if (idx >= 0)
{
! channels[idx].ch_fd = fd;
! netbeans_channel = idx;
}
return idx;
}
! void
! channel_remove_netbeans()
{
! channels[netbeans_channel].ch_fd = (sock_T)-1;
! netbeans_channel = -1;
}
#endif
! static void
channel_read(int idx)
{
! # ifdef FEAT_NETBEANS_INTG
! if (idx == netbeans_channel)
! netbeans_read();
! else
# endif
{
! ; /* TODO: read */
}
}
! #if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
/*
* Add open channels to the poll struct.
* Return the adjusted struct index.
--- 128,686 ----
return idx;
if (channel_count == MAX_OPEN_CHANNELS)
return -1;
! new_channels = (channel_T *)alloc(sizeof(channel_T) * (channel_count +
1));
if (new_channels == NULL)
return -1;
if (channels != NULL)
mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
channels = new_channels;
+ (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T));
+
channels[channel_count].ch_fd = (sock_T)-1;
+ #ifdef FEAT_GUI_X11
+ channels[channel_count].ch_inputHandler = (XtInputId)NULL;
+ #endif
+ #ifdef FEAT_GUI_GTK
+ channels[channel_count].ch_inputHandler = 0;
+ #endif
+ #ifdef FEAT_GUI_W32
+ channels[channel_count].ch_inputHandler = -1;
+ #endif
return channel_count++;
}
! #if defined(FEAT_GUI) || defined(PROTO)
! /*
! * Read a command from netbeans.
! */
! #ifdef FEAT_GUI_X11
! static void
! messageFromNetbeans(XtPointer clientData,
! int *unused1 UNUSED,
! XtInputId *unused2 UNUSED)
! {
! channel_read((int)(long)clientData);
! }
! #endif
!
! #ifdef FEAT_GUI_GTK
! static void
! messageFromNetbeans(gpointer clientData,
! gint unused1 UNUSED,
! GdkInputCondition unused2 UNUSED)
! {
! channel_read((int)(long)clientData);
! }
! #endif
!
! static void
! channel_gui_register(int idx)
! {
! channel_T *channel = &channels[idx];
!
! if (!CH_HAS_GUI)
! return;
!
! # ifdef FEAT_GUI_X11
! /* tell notifier we are interested in being called
! * when there is input on the editor connection socket
! */
! if (channel->ch_inputHandler == (XtInputId)NULL)
! channel->ch_inputHandler =
! XtAppAddInput((XtAppContext)app_context, channel->ch_fd,
! (XtPointer)(XtInputReadMask + XtInputExceptMask),
! messageFromNetbeans, (XtPointer)idx);
! # else
! # ifdef FEAT_GUI_GTK
! /*
! * Tell gdk we are interested in being called when there
! * is input on the editor connection socket
! */
! if (channel->ch_inputHandler == 0)
! channel->ch_inputHandler =
! gdk_input_add((gint)channel->ch_fd, (GdkInputCondition)
! ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
! messageFromNetbeans, (gpointer)(long)idx);
! # else
! # ifdef FEAT_GUI_W32
! /*
! * Tell Windows we are interested in receiving message when there
! * is input on the editor connection socket.
! * TODO: change WM_NETBEANS to something related to the channel index.
! */
! if (channel->ch_inputHandler == -1)
! channel->ch_inputHandler =
! WSAAsyncSelect(channel->ch_fd, s_hwnd, WM_NETBEANS, FD_READ);
! # endif
! # endif
! # endif
! }
!
! /*
! * Register any of our file descriptors with the GUI event handling system.
! * Called when the GUI has started.
! */
! void
! channel_gui_register_all(void)
! {
! int i;
!
! for (i = 0; i < channel_count; ++i)
! if (channels[i].ch_fd >= 0)
! channel_gui_register(i);
! }
!
! static void
! channel_gui_unregister(int idx)
! {
! channel_T *channel = &channels[idx];
!
! # ifdef FEAT_GUI_X11
! if (channel->ch_inputHandler != (XtInputId)NULL)
! {
! XtRemoveInput(channel->ch_inputHandler);
! channel->ch_inputHandler = (XtInputId)NULL;
! }
! # else
! # ifdef FEAT_GUI_GTK
! if (channel->ch_inputHandler != 0)
! {
! gdk_input_remove(channel->ch_inputHandler);
! channel->ch_inputHandler = 0;
! }
! # else
! # ifdef FEAT_GUI_W32
! if (channel->ch_inputHandler == 0)
! {
! WSAAsyncSelect(nbsock, s_hwnd, 0, 0);
! channel->ch_inputHandler = -1;
! }
! # endif
! # endif
! # endif
! }
!
! #endif
/*
! * Open a channel to "hostname":"port".
! * Returns the channel number for success.
! * Returns a negative number for failure.
*/
int
! channel_open(char *hostname, int port_in, void (*close_cb)(void))
{
! int sd;
! struct sockaddr_in server;
! struct hostent * host;
! #ifdef FEAT_GUI_W32
! u_short port = port_in;
! #else
! int port = port_in;
! #endif
! int idx;
!
! #ifdef FEAT_GUI_W32
! channel_init_winsock();
! #endif
! idx = add_channel();
! if (idx < 0)
{
! CHERROR("All channels are in use\n", "");
! EMSG(_("E999: All channels are in use"));
! return -1;
! }
!
! if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
! {
! CHERROR("error in socket() in channel_open()\n", "");
! PERROR("E999: socket() in channel_open()");
! return -1;
! }
!
! /* Get the server internet address and put into addr structure */
! /* fill in the socket address structure and connect to server */
! vim_memset((char *)&server, 0, sizeof(server));
! server.sin_family = AF_INET;
! server.sin_port = htons(port);
! if ((host = gethostbyname(hostname)) == NULL)
! {
! CHERROR("error in gethostbyname() in channel_open()\n", "");
! PERROR("E999: gethostbyname() in channel_open()");
! sock_close(sd);
! return -1;
! }
! memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
!
! /* Connect to server */
! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
! {
! SOCK_ERRNO;
! CHERROR("channel_open: Connect failed with errno %d\n", errno);
! if (errno == ECONNREFUSED)
! {
! sock_close(sd);
! if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
! {
! SOCK_ERRNO;
! CHERROR("socket() retry in channel_open()\n", "");
! PERROR("E999: socket() retry in channel_open()");
! return -1;
! }
! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
! {
! int retries = 36;
! int success = FALSE;
!
! SOCK_ERRNO;
! while (retries-- && ((errno == ECONNREFUSED)
! || (errno == EINTR)))
! {
! CHERROR("retrying...\n", "");
! mch_delay(3000L, TRUE);
! ui_breakcheck();
! if (got_int)
! {
! errno = EINTR;
! break;
! }
! if (connect(sd, (struct sockaddr *)&server,
! sizeof(server)) == 0)
! {
! success = TRUE;
! break;
! }
! SOCK_ERRNO;
! }
! if (!success)
! {
! /* Get here when the server can't be found. */
! CHERROR("Cannot connect to port after retry\n", "");
! PERROR(_("E999: Cannot connect to port after retry2"));
! sock_close(sd);
! return -1;
! }
! }
! }
! else
! {
! CHERROR("Cannot connect to port\n", "");
! PERROR(_("E999: Cannot connect to port"));
! sock_close(sd);
! return -1;
! }
}
+
+ channels[idx].ch_fd = sd;
+ channels[idx].ch_close_cb = close_cb;
+
+ #ifdef FEAT_GUI
+ channel_gui_register(idx);
+ #endif
+
return idx;
}
! /*
! * Return TRUE when channel "idx" is open.
! */
! int
! channel_is_open(int idx)
{
! return channels[idx].ch_fd >= 0;
}
+
+ /*
+ * Close channel "idx".
+ * This does not trigger the close callback.
+ */
+ void
+ channel_close(int idx)
+ {
+ channel_T *channel = &channels[idx];
+
+ if (channel->ch_fd >= 0)
+ {
+ sock_close(channel->ch_fd);
+ channel->ch_fd = -1;
+ #ifdef FEAT_GUI
+ channel_gui_unregister(idx);
#endif
+ }
+ }
! /*
! * Store "buf[len]" on channel "idx".
! */
! void
! channel_save(int idx, char_u *buf, int len)
! {
! queue_T *node;
! queue_T *head = &channels[idx].ch_head;
!
! node = (queue_T *)alloc(sizeof(queue_T));
! if (node == NULL)
! return; /* out of memory */
! node->buffer = alloc(len + 1);
! if (node->buffer == NULL)
! {
! vim_free(node);
! return; /* out of memory */
! }
! mch_memmove(node->buffer, buf, (size_t)len);
! node->buffer[len] = NUL;
!
! if (head->next == NULL) /* initialize circular queue */
! {
! head->next = head;
! head->prev = head;
! }
!
! /* insert node at tail of queue */
! node->next = head;
! node->prev = head->prev;
! head->prev->next = node;
! head->prev = node;
!
! if (debugfd != NULL)
! {
! fprintf(debugfd, "RECV on %d: ", idx);
! fwrite(buf, len, 1, debugfd);
! fprintf(debugfd, "\n");
! }
! }
!
! /*
! * Return the first buffer from the channel without removing it.
! * Returns NULL if there is nothing.
! */
! char_u *
! channel_peek(int idx)
! {
! queue_T *head = &channels[idx].ch_head;
!
! if (head->next == head || head->next == NULL)
! return NULL;
! return head->next->buffer;
! }
!
! /*
! * Return the first buffer from the channel and remove it.
! * The caller must free it.
! * Returns NULL if there is nothing.
! */
! char_u *
! channel_get(int idx)
! {
! queue_T *head = &channels[idx].ch_head;
! queue_T *node;
! char_u *p;
!
! if (head->next == head || head->next == NULL)
! return NULL;
! node = head->next;
! /* dispose of the node but keep the buffer */
! p = node->buffer;
! head->next = node->next;
! node->next->prev = node->prev;
! vim_free(node);
! return p;
! }
!
! /*
! * Collapses the first and second buffer in the channel "idx".
! * Returns FAIL if that is not possible.
! */
! int
! channel_collapse(int idx)
! {
! queue_T *head = &channels[idx].ch_head;
! queue_T *node = head->next;
! char_u *p;
!
! if (node == head || node == NULL || node->next == head)
! return FAIL;
!
! p = alloc((unsigned)(STRLEN(node->buffer)
! + STRLEN(node->next->buffer) + 1));
! if (p == NULL)
! return FAIL; /* out of memory */
! STRCPY(p, node->buffer);
! STRCAT(p, node->next->buffer);
! vim_free(node->next->buffer);
! node->next->buffer = p;
!
! /* dispose of the node and buffer */
! head->next = node->next;
! node->next->prev = node->prev;
! vim_free(node->buffer);
! vim_free(node);
! return OK;
! }
!
! /*
! * Clear the read buffer on channel "idx".
! */
! void
! channel_clear(int idx)
! {
! queue_T *head = &channels[idx].ch_head;
! queue_T *node = head->next;
! queue_T *next;
!
! while (node != NULL && node != head)
! {
! next = node->next;
! vim_free(node->buffer);
! vim_free(node);
! if (next == head)
! {
! head->next = head;
! head->prev = head;
! break;
! }
! node = next;
! }
! }
!
! /* Sent when the channel is found closed when reading. */
! #define DETACH_MSG "\"DETACH\"\n"
!
! /* Buffer size for reading incoming messages. */
! #define MAXMSGSIZE 4096
!
! /*
! * Read from channel "idx". The data is put in the read queue.
! */
! void
channel_read(int idx)
{
! static char_u *buf = NULL;
! int len = 0;
! int readlen = 0;
! #ifdef HAVE_SELECT
! struct timeval tval;
! fd_set rfds;
! #else
! # ifdef HAVE_POLL
! struct pollfd fds;
# endif
+ #endif
+ channel_T *channel = &channels[idx];
+
+ if (channel->ch_fd < 0)
+ {
+ CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
+ return;
+ }
+
+ /* Allocate a buffer to read into. */
+ if (buf == NULL)
{
! buf = alloc(MAXMSGSIZE);
! if (buf == NULL)
! return; /* out of memory! */
}
+
+ /* Keep on reading for as long as there is something to read.
+ * Use select() or poll() to avoid blocking on a message that is exactly
+ * MAXMSGSIZE long. */
+ for (;;)
+ {
+ #ifdef HAVE_SELECT
+ FD_ZERO(&rfds);
+ FD_SET(channel->ch_fd, &rfds);
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+ if (select(channel->ch_fd + 1, &rfds, NULL, NULL, &tval) <= 0)
+ break;
+ #else
+ # ifdef HAVE_POLL
+ fds.fd = channel->ch_fd;
+ fds.events = POLLIN;
+ if (poll(&fds, 1, 0) <= 0)
+ break;
+ # endif
+ #endif
+ len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
+ if (len <= 0)
+ break; /* error or nothing more to read */
+
+ /* Store the read message in the queue. */
+ channel_save(idx, buf, len);
+ readlen += len;
+ if (len < MAXMSGSIZE)
+ break; /* did read everything that's available */
+ }
+
+ /* Reading a socket disconnection (readlen == 0), or a socket error. */
+ if (readlen <= 0)
+ {
+ /* Queue a "DETACH" netbeans message in the command queue in order to
+ * terminate the netbeans session later. Do not end the session here
+ * directly as we may be running in the context of a call to
+ * netbeans_parse_messages():
+ * netbeans_parse_messages
+ * -> autocmd triggered while processing the netbeans cmd
+ * -> ui_breakcheck
+ * -> gui event loop or select loop
+ * -> channel_read()
+ */
+ channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
+
+ channel_close(idx);
+ if (channel->ch_close_cb != NULL)
+ (*channel->ch_close_cb)();
+
+ if (len < 0)
+ {
+ /* Todo: which channel? */
+ CHERROR("%s(): cannot from channel\n", "channel_read");
+ PERROR(_("E999: read from channel"));
+ }
+ }
+
+ #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
+ if (CH_HAS_GUI && gtk_main_level() > 0)
+ gtk_main_quit();
+ #endif
+ }
+
+ /*
+ * Write "buf" (NUL terminated string) to channel "idx".
+ * When "fun" is not NULL an error message might be given.
+ */
+ void
+ channel_send(int idx, char_u *buf, char *fun)
+ {
+ channel_T *channel = &channels[idx];
+ int len = (int)STRLEN(buf);
+
+ if (channel->ch_fd < 0)
+ {
+ if (!channel->ch_error && fun != NULL)
+ {
+ CHERROR(" %s(): write while not connected\n", fun);
+ EMSG2("E630: %s(): write while not connected", fun);
+ }
+ channel->ch_error = TRUE;
+ }
+ else if (sock_write(channel->ch_fd, buf, len) != len)
+ {
+ if (!channel->ch_error && fun != NULL)
+ {
+ CHERROR(" %s(): write failed\n", fun);
+ EMSG2("E631: %s(): write failed", fun);
+ }
+ channel->ch_error = TRUE;
+ }
+ else
+ channel->ch_error = FALSE;
}
! # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
/*
* Add open channels to the poll struct.
* Return the adjusted struct index.
***************
*** 138,146 ****
return ret;
}
! #endif /* UNIX && !HAVE_SELECT */
! #if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO)
/*
* The type of "rfds" is hidden to avoid problems with the function proto.
*/
--- 727,735 ----
return ret;
}
! # endif /* UNIX && !HAVE_SELECT */
! # if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO)
/*
* The type of "rfds" is hidden to avoid problems with the function proto.
*/
***************
*** 182,187 ****
return ret;
}
! #endif /* UNIX && HAVE_SELECT */
#endif /* FEAT_CHANNEL */
--- 771,776 ----
return ret;
}
! # endif /* UNIX && HAVE_SELECT */
#endif /* FEAT_CHANNEL */
*** ../vim-7.4.1181/src/netbeans.c 2016-01-24 22:16:58.462876040 +0100
--- src/netbeans.c 2016-01-26 23:25:14.061818941 +0100
***************
*** 27,62 ****
#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
! /* Note: when making changes here also adjust configure.in. */
! #ifdef WIN32
! # ifdef DEBUG
! # include <tchar.h> /* for _T definition for TRACEn macros */
! # endif
! /* WinSock API is separated from C API, thus we can't use read(), write(),
! * errno... */
! # define SOCK_ERRNO errno = WSAGetLastError()
! # undef ECONNREFUSED
! # define ECONNREFUSED WSAECONNREFUSED
! # ifdef EINTR
! # undef EINTR
! # endif
! # define EINTR WSAEINTR
! # define sock_write(sd, buf, len) send(sd, buf, len, 0)
! # define sock_read(sd, buf, len) recv(sd, buf, len, 0)
! # define sock_close(sd) closesocket(sd)
! # define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
! #else
# include <netdb.h>
- # include <netinet/in.h>
-
- # include <sys/socket.h>
# ifdef HAVE_LIBGEN_H
# include <libgen.h>
# endif
- # define SOCK_ERRNO
- # define sock_write(sd, buf, len) write(sd, buf, len)
- # define sock_read(sd, buf, len) read(sd, buf, len)
- # define sock_close(sd) close(sd)
#endif
#include "version.h"
--- 27,37 ----
#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
! #ifndef WIN32
# include <netdb.h>
# ifdef HAVE_LIBGEN_H
# include <libgen.h>
# endif
#endif
#include "version.h"
***************
*** 83,117 ****
static void nb_init_graphics __ARGS((void));
static void coloncmd __ARGS((char *cmd, ...));
static void nb_set_curbuf __ARGS((buf_T *buf));
- #ifdef FEAT_GUI_X11
- static void messageFromNetbeans __ARGS((XtPointer, int *, XtInputId *));
- #endif
- #ifdef FEAT_GUI_GTK
- static void messageFromNetbeans __ARGS((gpointer, gint, GdkInputCondition));
- #endif
static void nb_parse_cmd __ARGS((char_u *));
static int nb_do_cmd __ARGS((int, char_u *, int, int, char_u *));
static void nb_send __ARGS((char *buf, char *fun));
static void nb_free __ARGS((void));
! /* TRUE when netbeans is running with a GUI. */
! #ifdef FEAT_GUI
! # define NB_HAS_GUI (gui.in_use || gui.starting)
! #endif
- static sock_T nbsock = -1; /* socket fd for Netbeans connection */
- #define NETBEANS_OPEN (nbsock != -1)
-
- #ifdef FEAT_GUI_X11
- static XtInputId inputHandler = (XtInputId)NULL; /* Cookie for input */
- #endif
- #ifdef FEAT_GUI_GTK
- static gint inputHandler = 0; /* Cookie for input */
- #endif
- #ifdef FEAT_GUI_W32
- static int inputHandler = -1; /* simply ret.value of
WSAAsyncSelect() */
- extern HWND s_hwnd; /* Gvim's Window handle */
- #endif
static int r_cmdno; /* current command number for reply */
static int dosetvisible = FALSE;
--- 58,71 ----
static void nb_init_graphics __ARGS((void));
static void coloncmd __ARGS((char *cmd, ...));
static void nb_set_curbuf __ARGS((buf_T *buf));
static void nb_parse_cmd __ARGS((char_u *));
static int nb_do_cmd __ARGS((int, char_u *, int, int, char_u *));
static void nb_send __ARGS((char *buf, char *fun));
static void nb_free __ARGS((void));
! #define NETBEANS_OPEN (nb_channel_idx >= 0 && channel_is_open(nb_channel_idx))
! static int nb_channel_idx = -1;
static int r_cmdno; /* current command number for reply */
static int dosetvisible = FALSE;
***************
*** 126,173 ****
static int inAtomic = 0;
/*
! * Close the socket and remove the input handlers.
*/
static void
! nb_close_socket(void)
{
! buf_T *buf;
!
! for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! buf->b_has_sign_column = FALSE;
!
! #ifdef FEAT_GUI_X11
! if (inputHandler != (XtInputId)NULL)
! {
! XtRemoveInput(inputHandler);
! inputHandler = (XtInputId)NULL;
! }
! #else
! # ifdef FEAT_GUI_GTK
! if (inputHandler != 0)
! {
! gdk_input_remove(inputHandler);
! inputHandler = 0;
! }
! # else
! # ifdef FEAT_GUI_W32
! if (inputHandler == 0)
! {
! WSAAsyncSelect(nbsock, s_hwnd, 0, 0);
! inputHandler = -1;
! }
! # endif
! # endif
! #endif
!
! sock_close(nbsock);
! nbsock = -1;
! channel_remove_netbeans();
}
/*
* Close the connection and cleanup.
! * May be called when nb_close_socket() was called earlier.
*/
static void
netbeans_close(void)
--- 80,96 ----
static int inAtomic = 0;
/*
! * Callback invoked when the channel is closed.
*/
static void
! nb_channel_closed(void)
{
! nb_channel_idx = -1;
}
/*
* Close the connection and cleanup.
! * May be called when the socket was closed earlier.
*/
static void
netbeans_close(void)
***************
*** 175,181 ****
if (NETBEANS_OPEN)
{
netbeans_send_disconnect();
! nb_close_socket();
}
#ifdef FEAT_BEVAL
--- 98,107 ----
if (NETBEANS_OPEN)
{
netbeans_send_disconnect();
! if (nb_channel_idx >= 0)
! /* Close the socket and remove the input handlers. */
! channel_close(nb_channel_idx);
! nb_channel_idx = -1;
}
#ifdef FEAT_BEVAL
***************
*** 209,222 ****
static int
netbeans_connect(char *params, int doabort)
{
! struct sockaddr_in server;
! struct hostent * host;
! #ifdef FEAT_GUI_W32
! u_short port;
! #else
! int port;
! #endif
! int sd;
char buf[32];
char *hostname = NULL;
char *address = NULL;
--- 135,141 ----
static int
netbeans_connect(char *params, int doabort)
{
! int port;
char buf[32];
char *hostname = NULL;
char *address = NULL;
***************
*** 291,397 ****
vim_free(password);
password = (char *)vim_strsave((char_u *)NB_DEF_PASS);
}
! if (hostname == NULL || address == NULL || password == NULL)
! goto theend; /* out of memory */
!
! #ifdef FEAT_GUI_W32
! channel_init_winsock();
! #endif
!
! port = atoi(address);
!
! if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
! {
! nbdebug(("error in socket() in netbeans_connect()\n"));
! PERROR("socket() in netbeans_connect()");
! goto theend;
! }
!
! /* Get the server internet address and put into addr structure */
! /* fill in the socket address structure and connect to server */
! vim_memset((char *)&server, '\0', sizeof(server));
! server.sin_family = AF_INET;
! server.sin_port = htons(port);
! if ((host = gethostbyname(hostname)) == NULL)
! {
! nbdebug(("error in gethostbyname() in netbeans_connect()\n"));
! PERROR("gethostbyname() in netbeans_connect()");
! sock_close(sd);
! goto theend;
! }
! memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
! /* Connect to server */
! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
{
! SOCK_ERRNO;
! nbdebug(("netbeans_connect: Connect failed with errno %d\n", errno));
! if (errno == ECONNREFUSED)
{
! sock_close(sd);
! if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
! {
! SOCK_ERRNO;
! nbdebug(("socket()#2 in netbeans_connect()\n"));
! PERROR("socket()#2 in netbeans_connect()");
! goto theend;
! }
! if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
! {
! int retries = 36;
! int success = FALSE;
! SOCK_ERRNO;
! while (retries-- && ((errno == ECONNREFUSED)
! || (errno == EINTR)))
! {
! nbdebug(("retrying...\n"));
! mch_delay(3000L, TRUE);
! ui_breakcheck();
! if (got_int)
! {
! errno = EINTR;
! break;
! }
! if (connect(sd, (struct sockaddr *)&server,
! sizeof(server)) == 0)
! {
! success = TRUE;
! break;
! }
! SOCK_ERRNO;
! }
! if (!success)
! {
! /* Get here when the server can't be found. */
! nbdebug(("Cannot connect to Netbeans #2\n"));
! PERROR(_("Cannot connect to Netbeans #2"));
! sock_close(sd);
! if (doabort)
! getout(1);
! goto theend;
! }
! }
! }
! else
! {
! nbdebug(("Cannot connect to Netbeans\n"));
! PERROR(_("Cannot connect to Netbeans"));
! sock_close(sd);
! if (doabort)
! getout(1);
! goto theend;
}
}
! nbsock = sd;
! channel_add_netbeans(nbsock);
! vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password);
! nb_send(buf, "netbeans_connect");
!
! sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
! nb_send(buf, "externaleditor_version");
- theend:
vim_free(hostname);
vim_free(address);
vim_free(password);
--- 210,238 ----
vim_free(password);
password = (char *)vim_strsave((char_u *)NB_DEF_PASS);
}
! if (hostname != NULL && address != NULL && password != NULL)
{
! port = atoi(address);
! nb_channel_idx = channel_open(hostname, port, nb_channel_closed);
! if (nb_channel_idx >= 0)
{
! /* success */
! # ifdef FEAT_BEVAL
! bevalServers |= BEVAL_NETBEANS;
! # endif
! /* success, login */
! vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password);
! nb_send(buf, "netbeans_connect");
!
! sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
! nb_send(buf, "externaleditor_version");
}
}
! if (nb_channel_idx < 0 && doabort)
! getout(1);
vim_free(hostname);
vim_free(address);
vim_free(password);
***************
*** 532,642 ****
}
- struct cmdqueue
- {
- char_u *buffer;
- struct cmdqueue *next;
- struct cmdqueue *prev;
- };
-
- typedef struct cmdqueue queue_T;
-
- static queue_T head; /* dummy node, header for circular queue */
-
-
- /*
- * Put the buffer on the work queue; possibly save it to a file as well.
- */
- static void
- save(char_u *buf, int len)
- {
- queue_T *node;
-
- node = (queue_T *)alloc(sizeof(queue_T));
- if (node == NULL)
- return; /* out of memory */
- node->buffer = alloc(len + 1);
- if (node->buffer == NULL)
- {
- vim_free(node);
- return; /* out of memory */
- }
- mch_memmove(node->buffer, buf, (size_t)len);
- node->buffer[len] = NUL;
-
- if (head.next == NULL) /* initialize circular queue */
- {
- head.next = &head;
- head.prev = &head;
- }
-
- /* insert node at tail of queue */
- node->next = &head;
- node->prev = head.prev;
- head.prev->next = node;
- head.prev = node;
-
- #ifdef NBDEBUG
- {
- static int outfd = -2;
-
- /* possibly write buffer out to a file */
- if (outfd == -3)
- return;
-
- if (outfd == -2)
- {
- char *file = getenv("__NETBEANS_SAVE");
- if (file == NULL)
- outfd = -3;
- else
- outfd = mch_open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
- }
-
- if (outfd >= 0)
- write(outfd, buf, len);
- }
- #endif
- }
-
-
/*
* While there's still a command in the work queue, parse and execute it.
*/
void
netbeans_parse_messages(void)
{
char_u *p;
- queue_T *node;
int own_node;
! while (head.next != NULL && head.next != &head)
{
! node = head.next;
/* Locate the first line in the first buffer. */
! p = vim_strchr(node->buffer, '\n');
if (p == NULL)
{
/* Command isn't complete. If there is no following buffer,
* return (wait for more). If there is another buffer following,
* prepend the text to that buffer and delete this one. */
! if (node->next == &head)
return;
- p = alloc((unsigned)(STRLEN(node->buffer)
- + STRLEN(node->next->buffer) + 1));
- if (p == NULL)
- return; /* out of memory */
- STRCPY(p, node->buffer);
- STRCAT(p, node->next->buffer);
- vim_free(node->next->buffer);
- node->next->buffer = p;
-
- /* dispose of the node and buffer */
- head.next = node->next;
- node->next->prev = node->prev;
- vim_free(node->buffer);
- vim_free(node);
}
else
{
--- 373,403 ----
}
/*
* While there's still a command in the work queue, parse and execute it.
*/
void
netbeans_parse_messages(void)
{
+ char_u *buffer;
char_u *p;
int own_node;
! while (nb_channel_idx >= 0)
{
! buffer = channel_peek(nb_channel_idx);
! if (buffer == NULL)
! break; /* nothing to read */
/* Locate the first line in the first buffer. */
! p = vim_strchr(buffer, '\n');
if (p == NULL)
{
/* Command isn't complete. If there is no following buffer,
* return (wait for more). If there is another buffer following,
* prepend the text to that buffer and delete this one. */
! if (channel_collapse(nb_channel_idx) == FAIL)
return;
}
else
{
***************
*** 648,794 ****
if (*p == NUL)
{
own_node = TRUE;
! head.next = node->next;
! node->next->prev = node->prev;
}
else
own_node = FALSE;
/* now, parse and execute the commands */
! nb_parse_cmd(node->buffer);
if (own_node)
! {
! /* buffer finished, dispose of the node and buffer */
! vim_free(node->buffer);
! vim_free(node);
! }
! /* Check that "head" wasn't changed under our fingers, e.g. when a
! * DETACH command was handled. */
! else if (head.next == node)
! {
! /* more follows, move to the start */
! STRMOVE(node->buffer, p);
! }
}
}
}
! /* Buffer size for reading incoming messages. */
! #define MAXMSGSIZE 4096
!
! /*
! * Read a command from netbeans.
! */
! #ifdef FEAT_GUI_X11
! static void
! messageFromNetbeans(XtPointer clientData UNUSED,
! int *unused1 UNUSED,
! XtInputId *unused2 UNUSED)
! {
! netbeans_read();
! }
! #endif
!
! #ifdef FEAT_GUI_GTK
! static void
! messageFromNetbeans(gpointer clientData UNUSED,
! gint unused1 UNUSED,
! GdkInputCondition unused2 UNUSED)
! {
! netbeans_read();
! }
! #endif
!
! #define DETACH_MSG "DETACH\n"
!
void
netbeans_read()
{
! static char_u *buf = NULL;
! int len = 0;
! int readlen = 0;
! #ifdef HAVE_SELECT
! struct timeval tval;
! fd_set rfds;
! #else
! # ifdef HAVE_POLL
! struct pollfd fds;
! # endif
! #endif
!
! if (!NETBEANS_OPEN)
! {
! nbdebug(("messageFromNetbeans() called without a socket\n"));
! return;
! }
!
! /* Allocate a buffer to read into. */
! if (buf == NULL)
! {
! buf = alloc(MAXMSGSIZE);
! if (buf == NULL)
! return; /* out of memory! */
! }
!
! /* Keep on reading for as long as there is something to read.
! * Use select() or poll() to avoid blocking on a message that is exactly
! * MAXMSGSIZE long. */
! for (;;)
! {
! #ifdef HAVE_SELECT
! FD_ZERO(&rfds);
! FD_SET(nbsock, &rfds);
! tval.tv_sec = 0;
! tval.tv_usec = 0;
! if (select(nbsock + 1, &rfds, NULL, NULL, &tval) <= 0)
! break;
! #else
! # ifdef HAVE_POLL
! fds.fd = nbsock;
! fds.events = POLLIN;
! if (poll(&fds, 1, 0) <= 0)
! break;
! # endif
! #endif
! len = sock_read(nbsock, buf, MAXMSGSIZE);
! if (len <= 0)
! break; /* error or nothing more to read */
!
! /* Store the read message in the queue. */
! save(buf, len);
! readlen += len;
! if (len < MAXMSGSIZE)
! break; /* did read everything that's available */
! }
!
! /* Reading a socket disconnection (readlen == 0), or a socket error. */
! if (readlen <= 0)
! {
! /* Queue a "DETACH" netbeans message in the command queue in order to
! * terminate the netbeans session later. Do not end the session here
! * directly as we may be running in the context of a call to
! * netbeans_parse_messages():
! * netbeans_parse_messages
! * -> autocmd triggered while processing the netbeans cmd
! * -> ui_breakcheck
! * -> gui event loop or select loop
! * -> netbeans_read()
! */
! save((char_u *)DETACH_MSG, (int)strlen(DETACH_MSG));
! nb_close_socket();
!
! if (len < 0)
! {
! nbdebug(("read from Netbeans socket\n"));
! PERROR(_("read from Netbeans socket"));
! }
! }
!
! #if defined(NB_HAS_GUI) && defined(FEAT_GUI_GTK)
! if (NB_HAS_GUI && gtk_main_level() > 0)
! gtk_main_quit();
! #endif
}
/*
--- 409,438 ----
if (*p == NUL)
{
own_node = TRUE;
! channel_get(nb_channel_idx);
}
else
own_node = FALSE;
/* now, parse and execute the commands */
! nb_parse_cmd(buffer);
if (own_node)
! /* buffer finished, dispose of it */
! vim_free(buffer);
! else
! /* more follows, move it to the start */
! STRMOVE(buffer, p);
}
}
}
! /* TODO: remove */
void
netbeans_read()
{
! if (nb_channel_idx >= 0)
! channel_read(nb_channel_idx);
}
/*
***************
*** 825,832 ****
/* NOTREACHED */
}
! if (STRCMP(cmd, "DETACH") == 0)
{
/* The IDE is breaking the connection. */
netbeans_close();
return;
--- 469,481 ----
/* NOTREACHED */
}
! if (STRCMP(cmd, "\"DETACH\"") == 0)
{
+ buf_T *buf;
+
+ for (buf = firstbuf; buf != NULL; buf = buf->b_next)
+ buf->b_has_sign_column = FALSE;
+
/* The IDE is breaking the connection. */
netbeans_close();
return;
***************
*** 923,929 ****
nb_free()
{
keyQ_T *key_node = keyHead.next;
- queue_T *cmd_node = head.next;
nbbuf_T buf;
int i;
--- 572,577 ----
***************
*** 960,978 ****
}
/* free the queued netbeans commands */
! while (cmd_node != NULL && cmd_node != &head)
! {
! queue_T *next = cmd_node->next;
! vim_free(cmd_node->buffer);
! vim_free(cmd_node);
! if (next == &head)
! {
! head.next = &head;
! head.prev = &head;
! break;
! }
! cmd_node = next;
! }
}
/*
--- 608,615 ----
}
/* free the queued netbeans commands */
! if (nb_channel_idx >= 0)
! channel_clear(nb_channel_idx);
}
/*
***************
*** 1116,1155 ****
sprintf(buf, "%d:killed=%d\n", i, r_cmdno);
nbdebug(("EVT: %s", buf));
/* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
! ignored = sock_write(nbsock, buf, (int)STRLEN(buf));
}
}
/*
* Send a message to netbeans.
*/
static void
nb_send(char *buf, char *fun)
{
! /* Avoid giving pages full of error messages when the other side has
! * exited, only mention the first error until the connection works again.
*/
! static int did_error = FALSE;
!
! if (!NETBEANS_OPEN)
! {
! if (!did_error)
! {
! nbdebug((" %s(): write while not connected\n", fun));
! EMSG2("E630: %s(): write while not connected", fun);
! }
! did_error = TRUE;
! }
! else if (sock_write(nbsock, buf, (int)STRLEN(buf)) != (int)STRLEN(buf))
! {
! if (!did_error)
! {
! nbdebug((" %s(): write failed\n", fun));
! EMSG2("E631: %s(): write failed", fun);
! }
! did_error = TRUE;
! }
! else
! did_error = FALSE;
}
/*
--- 753,771 ----
sprintf(buf, "%d:killed=%d\n", i, r_cmdno);
nbdebug(("EVT: %s", buf));
/* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
! nb_send(buf, NULL);
}
}
/*
* Send a message to netbeans.
+ * When "fun" is NULL no error is given.
*/
static void
nb_send(char *buf, char *fun)
{
! if (nb_channel_idx >= 0)
! channel_send(nb_channel_idx, (char_u *)buf, fun);
}
/*
***************
*** 2924,2975 ****
return NETBEANS_OPEN;
}
- #if defined(FEAT_GUI) || defined(PROTO)
- /*
- * Register our file descriptor with the gui event handling system.
- */
- void
- netbeans_gui_register(void)
- {
- if (!NB_HAS_GUI || !NETBEANS_OPEN)
- return;
-
- # ifdef FEAT_GUI_X11
- /* tell notifier we are interested in being called
- * when there is input on the editor connection socket
- */
- if (inputHandler == (XtInputId)NULL)
- inputHandler = XtAppAddInput((XtAppContext)app_context, nbsock,
- (XtPointer)(XtInputReadMask + XtInputExceptMask),
- messageFromNetbeans, NULL);
- # else
- # ifdef FEAT_GUI_GTK
- /*
- * Tell gdk we are interested in being called when there
- * is input on the editor connection socket
- */
- if (inputHandler == 0)
- inputHandler = gdk_input_add((gint)nbsock, (GdkInputCondition)
- ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
- messageFromNetbeans, NULL);
- # else
- # ifdef FEAT_GUI_W32
- /*
- * Tell Windows we are interested in receiving message when there
- * is input on the editor connection socket
- */
- if (inputHandler == -1)
- inputHandler = WSAAsyncSelect(nbsock, s_hwnd, WM_NETBEANS, FD_READ);
- # endif
- # endif
- # endif
-
- # ifdef FEAT_BEVAL
- bevalServers |= BEVAL_NETBEANS;
- # endif
- }
- #endif
-
/*
* Tell netbeans that the window was opened, ready for commands.
*/
--- 2540,2545 ----
***************
*** 2986,2994 ****
if (netbeans_connect(params, doabort) != OK)
return;
- #ifdef FEAT_GUI
- netbeans_gui_register();
- #endif
nbdebug(("EVT: %s", cmd));
nb_send(cmd, "netbeans_startup_done");
--- 2556,2561 ----
*** ../vim-7.4.1181/src/proto/channel.pro 2016-01-24 20:36:18.854082474
+0100
--- src/proto/channel.pro 2016-01-26 23:17:36.222619137 +0100
***************
*** 1,6 ****
/* channel.c */
! int channel_add_netbeans(sock_T fd);
! void channel_remove_netbeans(void);
int channel_poll_setup(int nfd_in, void *fds_in);
int channel_poll_check(int ret_in, void *fds_in);
int channel_select_setup(int maxfd_in, void *rfds_in);
--- 1,15 ----
/* channel.c */
! void channel_gui_register_all(void);
! int channel_open(char *hostname, int port_in, void (*close_cb)(void));
! int channel_is_open(int idx);
! void channel_close(int idx);
! void channel_save(int idx, char_u *buf, int len);
! char_u *channel_peek(int idx);
! char_u *channel_get(int idx);
! int channel_collapse(int idx);
! void channel_clear(int idx);
! void channel_read(int idx);
! void channel_send(int idx, char_u *buf, char *fun);
int channel_poll_setup(int nfd_in, void *fds_in);
int channel_poll_check(int ret_in, void *fds_in);
int channel_select_setup(int maxfd_in, void *rfds_in);
*** ../vim-7.4.1181/src/proto/netbeans.pro 2016-01-24 20:36:18.854082474
+0100
--- src/proto/netbeans.pro 2016-01-26 23:25:18.129776295 +0100
***************
*** 9,15 ****
void ex_nbstart(exarg_T *eap);
void netbeans_beval_cb(BalloonEval *beval, int state);
int netbeans_active(void);
- void netbeans_gui_register(void);
void netbeans_open(char *params, int doabort);
void netbeans_send_disconnect(void);
void netbeans_frame_moved(int new_x, int new_y);
--- 9,14 ----
*** ../vim-7.4.1181/src/gui.c 2016-01-02 22:25:40.670710107 +0100
--- src/gui.c 2016-01-26 22:21:23.945990461 +0100
***************
*** 5004,5011 ****
* of the argument ending up after the shell prompt. */
msg_clr_eos_force();
gui_start();
! #ifdef FEAT_NETBEANS_INTG
! netbeans_gui_register();
#endif
}
if (!ends_excmd(*eap->arg))
--- 5004,5011 ----
* of the argument ending up after the shell prompt. */
msg_clr_eos_force();
gui_start();
! #ifdef FEAT_CHANNEL
! channel_gui_register_all();
#endif
}
if (!ends_excmd(*eap->arg))
*** ../vim-7.4.1181/src/gui_w48.c 2016-01-17 20:53:07.962014779 +0100
--- src/gui_w48.c 2016-01-26 23:19:51.565200047 +0100
***************
*** 1779,1787 ****
}
#endif
! #ifdef FEAT_NETBEANS_INTG
if (msg.message == WM_NETBEANS)
{
netbeans_read();
return;
}
--- 1779,1788 ----
}
#endif
! #ifdef FEAT_CHANNEL
if (msg.message == WM_NETBEANS)
{
+ /* TODO: channel_read(idx) */
netbeans_read();
return;
}
*** ../vim-7.4.1181/src/version.c 2016-01-26 19:59:04.571324075 +0100
--- src/version.c 2016-01-26 23:21:40.248060546 +0100
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 1182,
/**/
--
hundred-and-one symptoms of being an internet addict:
47. You are so familiar with the WWW that you find the search engines useless.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.