3520 lines · 81.3 KB · C
RawDownload
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved	by Bram Moolenaar *			Netbeans integration by David Weatherford *			Adopted for Win32 by Sergey Khorev * * Do ":help uganda"  in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. */ /* * Implements client side of org.netbeans.modules.emacs editor * integration protocol.  Be careful!  The protocol uses offsets * which are *between* characters, whereas vim uses line number * and column number which are *on* characters. * See ":help netbeans-protocol" for explanation. */ #include "vim.h" #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) /* Note: when making changes here also adjust configure.in. */# include <fcntl.h>#ifdef WIN32# ifdef DEBUG#  include <tchar.h>	/* for _T definition for TRACEn macros */# endif# include "vimio.h"/* WinSock API is separated from C API, thus we can't use read(), write(), * errno... */# define sock_errno WSAGetLastError()# 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 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" #define INET_SOCKETS #define GUARDED		10000 /* typenr for "guarded" annotation */#define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */ /* The first implementation (working only with Netbeans) returned "1.1".  The * protocol implemented here also supports A-A-P. */static char *ExtEdProtocolVersion = "2.4"; static long pos2off __ARGS((buf_T *, pos_T *));static pos_T *off2pos __ARGS((buf_T *, long));static pos_T *get_off_or_lnum __ARGS((buf_T *buf, char_u **argp));static long get_buf_size __ARGS((buf_T *));static void netbeans_keystring __ARGS((int key, char *keystr));static void special_keys __ARGS((char_u *args)); static void netbeans_connect __ARGS((void));static int getConnInfo __ARGS((char *file, char **host, char **port, char **password)); 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_MOTIFstatic void messageFromNetbeans __ARGS((XtPointer, int *, XtInputId *));#endif#ifdef FEAT_GUI_GTKstatic void messageFromNetbeans __ARGS((gpointer, gint, GdkInputCondition));#endifstatic 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)); #ifdef WIN64typedef __int64 NBSOCK;#elsetypedef int NBSOCK;#endif static NBSOCK sd = -1;			/* socket fd for Netbeans connection */#ifdef FEAT_GUI_MOTIFstatic XtInputId inputHandler;		/* Cookie for input */#endif#ifdef FEAT_GUI_GTKstatic gint inputHandler;		/* Cookie for input */#endif#ifdef FEAT_GUI_W32static int  inputHandler = -1;		/* simply ret.value of WSAAsyncSelect() */extern HWND s_hwnd;			/* Gvim's Window handle */#endifstatic int r_cmdno;			/* current command number for reply */static int haveConnection = FALSE;	/* socket is connected and					   initialization is done */#ifdef FEAT_GUI_MOTIFstatic void netbeans_Xt_connect __ARGS((void *context));#endif#ifdef FEAT_GUI_GTKstatic void netbeans_gtk_connect __ARGS((void));#endif#ifdef FEAT_GUI_W32static void netbeans_w32_connect __ARGS((void));#endif static int dosetvisible = FALSE; /* * Include the debugging code if wanted. */#ifdef NBDEBUG# include "nbdebug.c"#endif /* Connect back to Netbeans process */#ifdef FEAT_GUI_MOTIF    static voidnetbeans_Xt_connect(void *context){    netbeans_connect();    if (sd > 0)    {	/* tell notifier we are interested in being called	 * when there is input on the editor connection socket	 */	inputHandler = XtAppAddInput((XtAppContext)context, sd,			     (XtPointer)(XtInputReadMask + XtInputExceptMask),						   messageFromNetbeans, NULL);    }}     static voidnetbeans_disconnect(void){    if (inputHandler != (XtInputId)NULL)    {	XtRemoveInput(inputHandler);	inputHandler = (XtInputId)NULL;    }    sd = -1;    haveConnection = FALSE;# ifdef FEAT_BEVAL    bevalServers &= ~BEVAL_NETBEANS;# endif}#endif /* FEAT_MOTIF_GUI */ #ifdef FEAT_GUI_GTK    static voidnetbeans_gtk_connect(void){    netbeans_connect();    if (sd > 0)    {	/*	 * Tell gdk we are interested in being called when there	 * is input on the editor connection socket	 */	inputHandler = gdk_input_add((gint)sd, (GdkInputCondition)		((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),						   messageFromNetbeans, NULL);    }}     static voidnetbeans_disconnect(void){    if (inputHandler != 0)    {	gdk_input_remove(inputHandler);	inputHandler = 0;    }    sd = -1;    haveConnection = FALSE;# ifdef FEAT_BEVAL    bevalServers &= ~BEVAL_NETBEANS;# endif}#endif /* FEAT_GUI_GTK */ #if defined(FEAT_GUI_W32) || defined(PROTO)    static voidnetbeans_w32_connect(void){    netbeans_connect();    if (sd > 0)    {	/*	 * Tell Windows we are interested in receiving message when there	 * is input on the editor connection socket	 */	inputHandler = WSAAsyncSelect(sd, s_hwnd, WM_NETBEANS, FD_READ);    }}     static voidnetbeans_disconnect(void){    if (inputHandler == 0)    {	WSAAsyncSelect(sd, s_hwnd, 0, 0);	inputHandler = -1;    }    sd = -1;    haveConnection = FALSE;# ifdef FEAT_BEVAL    bevalServers &= ~BEVAL_NETBEANS;# endif}#endif /* FEAT_GUI_W32 */ #define NB_DEF_HOST "localhost"#define NB_DEF_ADDR "3219"#define NB_DEF_PASS "changeme"     static voidnetbeans_connect(void){#ifdef INET_SOCKETS    struct sockaddr_in	server;    struct hostent *	host;# ifdef FEAT_GUI_W32    u_short		port;# else    int			port;#endif#else    struct sockaddr_un	server;#endif    char	buf[32];    char	*hostname = NULL;    char	*address = NULL;    char	*password = NULL;    char	*fname;    char	*arg = NULL;     if (netbeansArg[3] == '=')    {	/* "-nb=fname": Read info from specified file. */	if (getConnInfo(netbeansArg + 4, &hostname, &address, &password)								      == FAIL)	    return;    }    else    {	if (netbeansArg[3] == ':')	    /* "-nb:<host>:<addr>:<password>": get info from argument */	    arg = netbeansArg + 4;	if (arg == NULL && (fname = getenv("__NETBEANS_CONINFO")) != NULL)	{	    /* "-nb": get info from file specified in environment */	    if (getConnInfo(fname, &hostname, &address, &password) == FAIL)		return;	}	else	{	    if (arg != NULL)	    {		/* "-nb:<host>:<addr>:<password>": get info from argument */		hostname = arg;		address = strchr(hostname, ':');		if (address != NULL)		{		    *address++ = '\0';		    password = strchr(address, ':');		    if (password != NULL)			*password++ = '\0';		}	    } 	    /* Get the missing values from the environment. */	    if (hostname == NULL || *hostname == '\0')		hostname = getenv("__NETBEANS_HOST");	    if (address == NULL)		address = getenv("__NETBEANS_SOCKET");	    if (password == NULL)		password = getenv("__NETBEANS_VIM_PASSWORD"); 	    /* Move values to allocated memory. */	    if (hostname != NULL)		hostname = (char *)vim_strsave((char_u *)hostname);	    if (address != NULL)		address = (char *)vim_strsave((char_u *)address);	    if (password != NULL)		password = (char *)vim_strsave((char_u *)password);	}    }     /* Use the default when a value is missing. */    if (hostname == NULL || *hostname == '\0')    {	vim_free(hostname);	hostname = (char *)vim_strsave((char_u *)NB_DEF_HOST);    }    if (address == NULL || *address == '\0')    {	vim_free(address);	address = (char *)vim_strsave((char_u *)NB_DEF_ADDR);    }    if (password == NULL || *password == '\0')    {	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 INET_SOCKETS    port = atoi(address);     if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)    {	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 */    memset((char *)&server, '\0', sizeof(server));    server.sin_family = AF_INET;    server.sin_port = htons(port);    if ((host = gethostbyname(hostname)) == NULL)    {	if (mch_access(hostname, R_OK) >= 0)	{	    /* DEBUG: input file */	    sd = mch_open(hostname, O_RDONLY, 0);	    goto theend;	}	PERROR("gethostbyname() in netbeans_connect()");	sd = -1;	goto theend;    }    memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);#else    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)    {	PERROR("socket()");	goto theend;    }     server.sun_family = AF_UNIX;    strcpy(server.sun_path, address);#endif    /* Connect to server */    if (connect(sd, (struct sockaddr *)&server, sizeof(server)))    {	nbdebug(("netbeans_connect: Connect failed with errno %d\n", sock_errno));	if (sock_errno == ECONNREFUSED)	{	    sock_close(sd);#ifdef INET_SOCKETS	    if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)	    {		PERROR("socket()#2 in netbeans_connect()");		goto theend;	    }#else	    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)	    {		PERROR("socket()#2 in netbeans_connect()");		goto theend;	    }#endif	    if (connect(sd, (struct sockaddr *)&server, sizeof(server)))	    {		int retries = 36;		int success = FALSE;		while (retries--			     && ((sock_errno == ECONNREFUSED) || (sock_errno == EINTR)))		{		    nbdebug(("retrying...\n"));		    sleep(5);		    if (connect(sd, (struct sockaddr *)&server,				sizeof(server)) == 0)		    {			success = TRUE;			break;		    }		}		if (!success)		{		    /* Get here when the server can't be found. */		    PERROR(_("Cannot connect to Netbeans #2"));		    getout(1);		}	    } 	}	else	{	    PERROR(_("Cannot connect to Netbeans"));	    getout(1);	}    }     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"); /*    nb_init_graphics();  delay until needed */     haveConnection = TRUE; theend:    vim_free(hostname);    vim_free(address);    vim_free(password);    return;} /* * Obtain the NetBeans hostname, port address and password from a file. * Return the strings in allocated memory. * Return FAIL if the file could not be read, OK otherwise (no matter what it * contains). */    static intgetConnInfo(char *file, char **host, char **port, char **auth){    FILE *fp;    char_u buf[BUFSIZ];    char_u *lp;    char_u *nl;#ifdef UNIX    struct stat	st;     /*     * For Unix only accept the file when it's not accessible by others.     * The open will then fail if we don't own the file.     */    if (mch_stat(file, &st) == 0 && (st.st_mode & 0077) != 0)    {	EMSG2(_("E668: Wrong access mode for NetBeans connection info file: \"%s\""),									file);	return FAIL;    }#endif     fp = mch_fopen(file, "r");    if (fp == NULL)    {	PERROR("E660: Cannot open NetBeans connection info file");	return FAIL;    }     /* Read the file. There should be one of each parameter */    while ((lp = (char_u *)fgets((char *)buf, BUFSIZ, fp)) != NULL)    {	if ((nl = vim_strchr(lp, '\n')) != NULL)	    *nl = 0;	    /* strip off the trailing newline */ 	if (STRNCMP(lp, "host=", 5) == 0)	{	    vim_free(*host);	    *host = (char *)vim_strsave(&buf[5]);	}	else if (STRNCMP(lp, "port=", 5) == 0)	{	    vim_free(*port);	    *port = (char *)vim_strsave(&buf[5]);	}	else if (STRNCMP(lp, "auth=", 5) == 0)	{	    vim_free(*auth);	    *auth = (char *)vim_strsave(&buf[5]);	}    }    fclose(fp);     return OK;}  struct keyqueue{    int		     key;    struct keyqueue *next;    struct keyqueue *prev;}; typedef struct keyqueue keyQ_T; static keyQ_T keyHead; /* dummy node, header for circular queue */ 

Lines 1–500 of 3520.