summaryrefslogtreecommitdiff
path: root/src/if_sniff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/if_sniff.c')
-rw-r--r--src/if_sniff.c1210
1 files changed, 1210 insertions, 0 deletions
diff --git a/src/if_sniff.c b/src/if_sniff.c
new file mode 100644
index 000000000..4cb0bee24
--- /dev/null
+++ b/src/if_sniff.c
@@ -0,0 +1,1210 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * if_sniff.c Interface between Vim and SNiFF+
+ *
+ * $Id$
+ *
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#include "vim.h"
+
+#ifdef WIN32
+# include <stdio.h>
+# include <fcntl.h>
+# include <io.h>
+# include <process.h>
+# include <string.h>
+# include <assert.h>
+#else
+# ifdef FEAT_GUI_X11
+# include "gui_x11.pro"
+# endif
+# include "os_unixx.h"
+#endif
+
+static int sniffemacs_pid;
+
+int fd_from_sniff;
+int sniff_connected = 0;
+int sniff_request_waiting = 0;
+int want_sniff_request = 0;
+
+#define MAX_REQUEST_LEN 512
+
+#define NEED_SYMBOL 2
+#define EMPTY_SYMBOL 4
+#define NEED_FILE 8
+#define SILENT 16
+#define DISCONNECT 32
+#define CONNECT 64
+
+#define RQ_NONE 0
+#define RQ_SIMPLE 1
+#define RQ_CONTEXT NEED_FILE + NEED_SYMBOL
+#define RQ_SCONTEXT NEED_FILE + NEED_SYMBOL + EMPTY_SYMBOL
+#define RQ_NOSYMBOL NEED_FILE
+#define RQ_SILENT RQ_NOSYMBOL + SILENT
+#define RQ_CONNECT RQ_NONE + CONNECT
+#define RQ_DISCONNECT RQ_SIMPLE + DISCONNECT
+
+struct sn_cmd
+{
+ char *cmd_name;
+ char cmd_code;
+ char *cmd_msg;
+ int cmd_type;
+};
+
+struct sn_cmd_list
+{
+ struct sn_cmd* sniff_cmd;
+ struct sn_cmd_list* next_cmd;
+};
+
+static struct sn_cmd sniff_cmds[] =
+{
+ { "toggle", 'e', N_("Toggle implementation/definition"),RQ_SCONTEXT },
+ { "superclass", 's', N_("Show base class of"), RQ_CONTEXT },
+ { "overridden", 'm', N_("Show overridden member function"),RQ_SCONTEXT },
+ { "retrieve-file", 'r', N_("Retrieve from file"), RQ_CONTEXT },
+ { "retrieve-project",'p', N_("Retrieve from project"), RQ_CONTEXT },
+ { "retrieve-all-projects",
+ 'P', N_("Retrieve from all projects"), RQ_CONTEXT },
+ { "retrieve-next", 'R', N_("Retrieve"), RQ_CONTEXT },
+ { "goto-symbol", 'g', N_("Show source of"), RQ_CONTEXT },
+ { "find-symbol", 'f', N_("Find symbol"), RQ_CONTEXT },
+ { "browse-class", 'w', N_("Browse class"), RQ_CONTEXT },
+ { "hierarchy", 't', N_("Show class in hierarchy"), RQ_CONTEXT },
+ { "restr-hier", 'T', N_("Show class in restricted hierarchy"),RQ_CONTEXT },
+ { "xref-to", 'x', N_("Xref refers to"), RQ_CONTEXT },
+ { "xref-by", 'X', N_("Xref referred by"), RQ_CONTEXT },
+ { "xref-has", 'c', N_("Xref has a"), RQ_CONTEXT },
+ { "xref-used-by", 'C', N_("Xref used by"), RQ_CONTEXT },
+ { "show-docu", 'd', N_("Show docu of"), RQ_CONTEXT },
+ { "gen-docu", 'D', N_("Generate docu for"), RQ_CONTEXT },
+ { "connect", 'y', NULL, RQ_CONNECT },
+ { "disconnect", 'q', NULL, RQ_DISCONNECT },
+ { "font-info", 'z', NULL, RQ_SILENT },
+ { "update", 'u', NULL, RQ_SILENT },
+ { NULL, '\0', NULL, 0}
+};
+
+
+static char *SniffEmacs[2] = {"sniffemacs", (char *)NULL}; /* Yes, Emacs! */
+static int fd_to_sniff;
+static int sniff_will_disconnect = 0;
+static char msg_sniff_disconnect[] = N_("Cannot connect to SNiFF+. Check environment (sniffemacs must be found in $PATH).\n");
+static char sniff_rq_sep[] = " ";
+static struct sn_cmd_list *sniff_cmd_ext = NULL;
+
+/* Initializing vim commands
+ * executed each time vim connects to Sniff
+ */
+static char *init_cmds[]= {
+ "augroup sniff",
+ "autocmd BufWritePost * sniff update",
+ "autocmd BufReadPost * sniff font-info",
+ "autocmd VimLeave * sniff disconnect",
+ "augroup END",
+
+ "let g:sniff_connected = 1",
+
+ "if ! exists('g:sniff_mappings_sourced')|"
+ "if ! exists('g:sniff_mappings')|"
+ "if exists('$SNIFF_DIR4')|"
+ "let g:sniff_mappings='$SNIFF_DIR4/config/integrations/vim/sniff.vim'|"
+ "else|"
+ "let g:sniff_mappings='$SNIFF_DIR/config/sniff.vim'|"
+ "endif|"
+ "endif|"
+ "let g:sniff_mappings=expand(g:sniff_mappings)|"
+ "if filereadable(g:sniff_mappings)|"
+ "execute 'source' g:sniff_mappings|"
+ "let g:sniff_mappings_sourced=1|"
+ "endif|"
+ "endif",
+
+ NULL
+};
+
+/*-------- Function Prototypes ----------------------------------*/
+
+static int ConnectToSniffEmacs __ARGS((void));
+static void sniff_connect __ARGS((void));
+static void HandleSniffRequest __ARGS((char* buffer));
+static int get_request __ARGS((int fd, char *buf, int maxlen));
+static void WriteToSniff __ARGS((char *str));
+static void SendRequest __ARGS((struct sn_cmd *command, char* symbol));
+static void vi_msg __ARGS((char *));
+static void vi_error_msg __ARGS((char *));
+static char *vi_symbol_under_cursor __ARGS((void));
+static void vi_open_file __ARGS((char *));
+static char *vi_buffer_name __ARGS((void));
+static buf_T *vi_find_buffer __ARGS((char *));
+static void vi_exec_cmd __ARGS((char *));
+static void vi_set_cursor_pos __ARGS((long char_nr));
+static long vi_cursor_pos __ARGS((void));
+
+/* debug trace */
+#if 0
+static FILE* _tracefile = NULL;
+#define SNIFF_TRACE_OPEN(file) if (!_tracefile) _tracefile = fopen(file, "w")
+#define SNIFF_TRACE(msg) fprintf(_tracefile, msg); fflush(_tracefile);
+#define SNIFF_TRACE1(msg, arg) fprintf(_tracefile, msg,arg); fflush(_tracefile);
+#define SNIFF_TRACE_CLOSE fclose(_tracefile); _tracefile=NULL;
+#else
+#define SNIFF_TRACE_OPEN(file)
+#define SNIFF_TRACE(msg)
+#define SNIFF_TRACE1(msg, arg)
+#define SNIFF_TRACE_CLOSE
+#endif
+
+/*-------- Windows Only Declarations -----------------------------*/
+#ifdef WIN32
+
+static int sniff_request_processed=1;
+static HANDLE sniffemacs_handle=NULL;
+static HANDLE readthread_handle=NULL;
+static HANDLE handle_to_sniff=NULL;
+static HANDLE handle_from_sniff=NULL;
+
+struct sniffBufNode
+{
+ struct sniffBufNode *next;
+ int bufLen;
+ char buf[MAX_REQUEST_LEN];
+};
+static struct sniffBufNode *sniffBufStart=NULL;
+static struct sniffBufNode *sniffBufEnd=NULL;
+static HANDLE hBufferMutex=NULL;
+
+# ifdef FEAT_GUI_W32
+ extern HWND s_hwnd; /* gvim's Window handle */
+# endif
+/*
+ * some helper functions for Windows port only
+ */
+
+ static HANDLE
+ExecuteDetachedProgram(char *szBinary, char *szCmdLine,
+ HANDLE hStdInput, HANDLE hStdOutput)
+{
+ BOOL bResult;
+ DWORD nError;
+ PROCESS_INFORMATION aProcessInformation;
+ PROCESS_INFORMATION *pProcessInformation= &aProcessInformation;
+ STARTUPINFO aStartupInfo;
+ STARTUPINFO *pStartupInfo= &aStartupInfo;
+ DWORD dwCreationFlags= 0;
+ char szPath[512];
+ HINSTANCE hResult;
+
+ hResult = FindExecutable(szBinary, ".", szPath);
+ if ((int)hResult <= 32)
+ {
+ /* can't find the exe file */
+ return NULL;
+ }
+
+ ZeroMemory(pStartupInfo, sizeof(*pStartupInfo));
+ pStartupInfo->dwFlags= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
+ pStartupInfo->hStdInput = hStdInput;
+ pStartupInfo->hStdOutput = hStdOutput;
+ pStartupInfo->wShowWindow= SW_HIDE;
+ pStartupInfo->cb = sizeof(STARTUPINFO);
+
+ bResult= CreateProcess(
+ szPath,
+ szCmdLine,
+ NULL, /* security attr for process */
+ NULL, /* security attr for primary thread */
+ TRUE, /* DO inherit stdin and stdout */
+ dwCreationFlags, /* creation flags */
+ NULL, /* environment */
+ ".", /* current directory */
+ pStartupInfo, /* startup info: NULL crashes */
+ pProcessInformation /* process information: NULL crashes */
+ );
+ nError= GetLastError();
+ if (bResult)
+ {
+ CloseHandle(pProcessInformation->hThread);
+ CloseHandle(hStdInput);
+ CloseHandle(hStdOutput);
+ return(pProcessInformation->hProcess);
+ }
+ else
+ return(NULL);
+}
+
+/*
+ * write to the internal Thread / Thread communications buffer.
+ * Return TRUE if successful, FALSE else.
+ */
+ static BOOL
+writeToBuffer(char *msg, int len)
+{
+ DWORD dwWaitResult; /* Request ownership of mutex. */
+ struct sniffBufNode *bn;
+ int bnSize;
+
+ SNIFF_TRACE1("writeToBuffer %d\n", len);
+ bnSize = sizeof(struct sniffBufNode) - MAX_REQUEST_LEN + len + 1;
+ if (bnSize < 128) bnSize = 128; /* minimum length to avoid fragmentation */
+ bn = (struct sniffBufNode *)malloc(bnSize);
+ if (!bn)
+ return FALSE;
+
+ memcpy(bn->buf, msg, len);
+ bn->buf[len]='\0'; /* terminate CString for added safety */
+ bn->next = NULL;
+ bn->bufLen = len;
+ /* now, acquire a Mutex for adding the string to our linked list */
+ dwWaitResult = WaitForSingleObject(
+ hBufferMutex, /* handle of mutex */
+ 1000L); /* one-second time-out interval */
+ if (dwWaitResult == WAIT_OBJECT_0)
+ {
+ /* The thread got mutex ownership. */
+ if (sniffBufEnd)
+ {
+ sniffBufEnd->next = bn;
+ sniffBufEnd = bn;
+ }
+ else
+ sniffBufStart = sniffBufEnd = bn;
+ /* Release ownership of the mutex object. */
+ if (! ReleaseMutex(hBufferMutex))
+ {
+ /* Deal with error. */
+ }
+ return TRUE;
+ }
+
+ /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
+ free(bn);
+ return FALSE;
+}
+
+/*
+ * read from the internal Thread / Thread communications buffer.
+ * Return TRUE if successful, FALSE else.
+ */
+ static int
+ReadFromBuffer(char *buf, int maxlen)
+{
+ DWORD dwWaitResult; /* Request ownership of mutex. */
+ int theLen;
+ struct sniffBufNode *bn;
+
+ dwWaitResult = WaitForSingleObject(
+ hBufferMutex, /* handle of mutex */
+ 1000L); /* one-second time-out interval */
+ if (dwWaitResult == WAIT_OBJECT_0)
+ {
+ if (!sniffBufStart)
+ {
+ /* all pending Requests Processed */
+ theLen = 0;
+ }
+ else
+ {
+ bn = sniffBufStart;
+ theLen = bn->bufLen;
+ SNIFF_TRACE1("ReadFromBuffer %d\n", theLen);
+ if (theLen >= maxlen)
+ {
+ /* notify the user of buffer overflow? */
+ theLen = maxlen-1;
+ }
+ memcpy(buf, bn->buf, theLen);
+ buf[theLen] = '\0';
+ if (! (sniffBufStart = bn->next))
+ {
+ sniffBufEnd = NULL;
+ sniff_request_processed = 1;
+ }
+ free(bn);
+ }
+ if (! ReleaseMutex(hBufferMutex))
+ {
+ /* Deal with error. */
+ }
+ return theLen;
+ }
+
+ /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
+ return -1;
+}
+
+/* on Win32, a separate Thread reads the input pipe. get_request is not needed here. */
+ static void __cdecl
+SniffEmacsReadThread(void *dummy)
+{
+ static char ReadThreadBuffer[MAX_REQUEST_LEN];
+ int ReadThreadLen=0;
+ int result=0;
+ int msgLen=0;
+ char *msgStart, *msgCur;
+
+ SNIFF_TRACE("begin thread\n");
+ /* Read from the pipe to SniffEmacs */
+ while (sniff_connected)
+ {
+ if (!ReadFile(handle_from_sniff,
+ ReadThreadBuffer + ReadThreadLen, /* acknowledge rest in buffer */
+ MAX_REQUEST_LEN - ReadThreadLen,
+ &result,
+ NULL))
+ {
+ DWORD err = GetLastError();
+ result = -1;
+ }
+
+ if (result < 0)
+ {
+ /* probably sniffemacs died... log the Error? */
+ sniff_disconnect(1);
+ }
+ else if (result > 0)
+ {
+ ReadThreadLen += result-1; /* total length of valid chars */
+ for(msgCur=msgStart=ReadThreadBuffer; ReadThreadLen > 0; msgCur++, ReadThreadLen--)
+ {
+ if (*msgCur == '\0' || *msgCur == '\r' || *msgCur == '\n')
+ {
+ msgLen = msgCur-msgStart; /* don't add the CR/LF chars */
+ if (msgLen > 0)
+ writeToBuffer(msgStart, msgLen);
+ msgStart = msgCur + 1; /* over-read single CR/LF chars */
+ }
+ }
+
+ /* move incomplete message to beginning of buffer */
+ ReadThreadLen = msgCur - msgStart;
+ if (ReadThreadLen > 0)
+ mch_memmove(ReadThreadBuffer, msgStart, ReadThreadLen);
+
+ if (sniff_request_processed)
+ {
+ /* notify others that new data has arrived */
+ sniff_request_processed = 0;
+ sniff_request_waiting = 1;
+#ifdef FEAT_GUI_W32
+ PostMessage(s_hwnd, WM_USER, (WPARAM)0, (LPARAM)0);
+#endif
+ }
+ }
+ }
+ SNIFF_TRACE("end thread\n");
+}
+#endif /* WIN32 */
+/*-------- End of Windows Only Declarations ------------------------*/
+
+
+/* ProcessSniffRequests
+ * Function that should be called from outside
+ * to process the waiting sniff requests
+ */
+ void
+ProcessSniffRequests()
+{
+ static char buf[MAX_REQUEST_LEN];
+ int len;
+
+ while (sniff_connected)
+ {
+#ifdef WIN32
+ len = ReadFromBuffer(buf, sizeof(buf));
+#else
+ len = get_request(fd_from_sniff, buf, sizeof(buf));
+#endif
+ if (len < 0)
+ {
+ vi_error_msg(_("E274: Sniff: Error during read. Disconnected"));
+ sniff_disconnect(1);
+ break;
+ }
+ else if (len > 0)
+ HandleSniffRequest( buf );
+ else
+ break;
+ }
+
+ if (sniff_will_disconnect) /* Now the last msg has been processed */
+ sniff_disconnect(1);
+}
+
+ static struct sn_cmd *
+find_sniff_cmd(cmd)
+ char *cmd;
+{
+ struct sn_cmd *sniff_cmd = NULL;
+ int i;
+ for(i=0; sniff_cmds[i].cmd_name; i++)
+ {
+ if (!strcmp(cmd, sniff_cmds[i].cmd_name))
+ {
+ sniff_cmd = &sniff_cmds[i];
+ break;
+ }
+ }
+ if (!sniff_cmd)
+ {
+ struct sn_cmd_list *list = sniff_cmd_ext;
+ while(list)
+ {
+ if (!strcmp(cmd, list->sniff_cmd->cmd_name))
+ {
+ sniff_cmd = list->sniff_cmd;
+ break;
+ }
+ list = list->next_cmd;
+ }
+ }
+ return sniff_cmd;
+}
+
+ static int
+add_sniff_cmd(cmd, def, msg)
+ char *cmd;
+ char *def;
+ char *msg;
+{
+ int rc = 0;
+ if (def != NULL && def[0] != NUL && find_sniff_cmd(cmd) == NULL)
+ {
+ struct sn_cmd_list *list = sniff_cmd_ext;
+ struct sn_cmd *sniff_cmd = (struct sn_cmd*)malloc(sizeof(struct sn_cmd));
+ struct sn_cmd_list *cmd_node = (struct sn_cmd_list*)malloc(sizeof(struct sn_cmd_list));
+ int rq_type = 0;
+
+ /* unescape message text */
+ char *p = msg;
+ char *end = p+strlen(msg);
+ while(*p)
+ {
+ if (*p == '\\')
+ mch_memmove(p,p+1,end-p);
+ p++;
+ }
+ SNIFF_TRACE1("request name = %s\n",cmd);
+ SNIFF_TRACE1("request def = %s\n",def);
+ SNIFF_TRACE1("request msg = %s\n",msg);
+
+ while(list && list->next_cmd)
+ list = list->next_cmd;
+ if (!list)
+ sniff_cmd_ext = cmd_node;
+ else
+ list->next_cmd = cmd_node;
+
+ sniff_cmd->cmd_name = cmd;
+ sniff_cmd->cmd_code = def[0];
+ sniff_cmd->cmd_msg = msg;
+ switch(def[1])
+ {
+ case 'f':
+ rq_type = RQ_NOSYMBOL;
+ break;
+ case 's':
+ rq_type = RQ_CONTEXT;
+ break;
+ case 'S':
+ rq_type = RQ_SCONTEXT;
+ break;
+ default:
+ rq_type = RQ_SIMPLE;
+ break;
+ }
+ sniff_cmd->cmd_type = rq_type;
+ cmd_node->sniff_cmd = sniff_cmd;
+ cmd_node->next_cmd = NULL;
+ rc = 1;
+ }
+ return rc;
+}
+
+/* ex_sniff
+ * Handle ":sniff" command
+ */
+ void
+ex_sniff(eap)
+ exarg_T *eap;
+{
+ char_u *arg = eap->arg;
+ char_u *symbol = NULL;
+ char_u *cmd = NULL;
+
+ SNIFF_TRACE_OPEN("if_sniff.log");
+ if (ends_excmd(*arg)) /* no request: print available commands */
+ {
+ int i;
+ msg_start();
+ msg_outtrans_attr((char_u *)"-- SNiFF+ commands --", hl_attr(HLF_T));
+ for(i=0; sniff_cmds[i].cmd_name; i++)
+ {
+ msg_putchar('\n');
+ msg_outtrans((char_u *)":sniff ");
+ msg_outtrans((char_u *)sniff_cmds[i].cmd_name);
+ }
+ msg_putchar('\n');
+ msg_outtrans((char_u *)_("SNiFF+ is currently "));
+ if (!sniff_connected)
+ msg_outtrans((char_u *)_("not "));
+ msg_outtrans((char_u *)_("connected"));
+ msg_end();
+ }
+ else /* extract command name and symbol if present */
+ {
+ symbol = skiptowhite(arg);
+ cmd = vim_strnsave(arg, (int)(symbol-arg));
+ symbol = skipwhite(symbol);
+ if (ends_excmd(*symbol))
+ symbol = NULL;
+ if (!strcmp((char *)cmd, "addcmd"))
+ {
+ char_u *def = skiptowhite(symbol);
+ char_u *name = vim_strnsave(symbol, (int)(def-symbol));
+ char_u *msg;
+ def = skipwhite(def);
+ msg = skiptowhite(def);
+ def = vim_strnsave(def, (int)(msg-def));
+ msg = skipwhite(msg);
+ if (ends_excmd(*msg))
+ msg = vim_strsave(name);
+ else
+ msg = vim_strnsave(msg, (int)(skiptowhite_esc(msg)-msg));
+ if (!add_sniff_cmd((char*)name, (char*)def, (char*)msg))
+ {
+ vim_free(msg);
+ vim_free(def);
+ vim_free(name);
+ }
+ }
+ else
+ {
+ struct sn_cmd* sniff_cmd = find_sniff_cmd((char*)cmd);
+ if (sniff_cmd)
+ SendRequest(sniff_cmd, (char *)symbol);
+ else
+ EMSG2(_("E275: Unknown SNiFF+ request: %s"), cmd);
+ }
+ vim_free(cmd);
+ }
+}
+
+
+ static void
+sniff_connect()
+{
+ if (sniff_connected)
+ return;
+ if (ConnectToSniffEmacs())
+ vi_error_msg(_("E276: Error connecting to SNiFF+"));
+ else
+ {
+ int i;
+
+ for (i = 0; init_cmds[i]; i++)
+ vi_exec_cmd(init_cmds[i]);
+ }
+}
+
+ void
+sniff_disconnect(immediately)
+ int immediately;
+{
+ if (!sniff_connected)
+ return;
+ if (immediately)
+ {
+ vi_exec_cmd("augroup sniff");
+ vi_exec_cmd("au!");
+ vi_exec_cmd("augroup END");
+ vi_exec_cmd("unlet g:sniff_connected");
+ sniff_connected = 0;
+ want_sniff_request = 0;
+ sniff_will_disconnect = 0;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_wait_for_chars(0L);
+#endif
+#ifdef WIN32
+ while(sniffBufStart != NULL)
+ {
+ struct sniffBufNode *node = sniffBufStart;
+ sniffBufStart = sniffBufStart->next;
+ free(node);
+ }
+ sniffBufStart = sniffBufEnd = NULL;
+ sniff_request_processed = 1;
+ CloseHandle(handle_to_sniff);
+ CloseHandle(handle_from_sniff);
+ WaitForSingleObject(sniffemacs_handle, 1000L);
+ CloseHandle(sniffemacs_handle);
+ sniffemacs_handle = NULL;
+ WaitForSingleObject(readthread_handle, 1000L);
+ readthread_handle = NULL;
+ CloseHandle(hBufferMutex);
+ hBufferMutex = NULL;
+ SNIFF_TRACE_CLOSE;
+#else
+ close(fd_to_sniff);
+ close(fd_from_sniff);
+ wait(NULL);
+#endif
+ }
+ else
+ {
+#ifdef WIN32
+ _sleep(2);
+ if (!sniff_request_processed)
+ ProcessSniffRequests();
+#else
+ sleep(2); /* Incoming msg could disturb edit */
+#endif
+ sniff_will_disconnect = 1; /* We expect disconnect msg in 2 secs */
+ }
+}
+
+
+/* ConnectToSniffEmacs
+ * Connect to Sniff: returns 1 on error
+ */
+ static int
+ConnectToSniffEmacs()
+{
+#ifdef WIN32 /* Windows Version of the Code */
+ HANDLE ToSniffEmacs[2], FromSniffEmacs[2];
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ if (! CreatePipe(&ToSniffEmacs[0], &ToSniffEmacs[1], &sa, 0))
+ return 1;
+ if (! CreatePipe(&FromSniffEmacs[0], &FromSniffEmacs[1], &sa, 0))
+ return 1;
+
+ sniffemacs_handle = ExecuteDetachedProgram(SniffEmacs[0], SniffEmacs[0],
+ ToSniffEmacs[0], FromSniffEmacs[1]);
+
+ if (sniffemacs_handle)
+ {
+ handle_to_sniff = ToSniffEmacs[1];
+ handle_from_sniff = FromSniffEmacs[0];
+ sniff_connected = 1;
+ hBufferMutex = CreateMutex(
+ NULL, /* no security attributes */
+ FALSE, /* initially not owned */
+ "SniffReadBufferMutex"); /* name of mutex */
+ if (hBufferMutex == NULL)
+ {
+ /* Check for error. */
+ }
+ readthread_handle = (HANDLE)_beginthread(SniffEmacsReadThread, 0, NULL);
+ return 0;
+ }
+ else
+ {
+ /* error in spawn() */
+ return 1;
+ }
+
+#else /* UNIX Version of the Code */
+ int ToSniffEmacs[2], FromSniffEmacs[2];
+
+ pipe(ToSniffEmacs);
+ pipe(FromSniffEmacs);
+
+ /* fork */
+ if ((sniffemacs_pid=fork()) == 0)
+ {
+ /* child */
+
+ /* prepare communication pipes */
+ close(ToSniffEmacs[1]);
+ close(FromSniffEmacs[0]);
+
+ dup2(ToSniffEmacs[0],fileno(stdin)); /* write to ToSniffEmacs[1] */
+ dup2(FromSniffEmacs[1],fileno(stdout));/* read from FromSniffEmacs[0] */
+
+ close(ToSniffEmacs[0]);
+ close(FromSniffEmacs[1]);
+
+ /* start sniffemacs */
+ execvp (SniffEmacs[0], SniffEmacs);
+ {
+/* FILE *out = fdopen(FromSniffEmacs[1], "w"); */
+ sleep(1);
+ fputs(_(msg_sniff_disconnect), stdout);
+ fflush(stdout);
+ sleep(3);
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_exit(1);
+#endif
+ exit(1);
+ }
+ return 1;
+ }
+ else if (sniffemacs_pid > 0)
+ {
+ /* parent process */
+ close(ToSniffEmacs[0]);
+ fd_to_sniff = ToSniffEmacs[1];
+ close(FromSniffEmacs[1]);
+ fd_from_sniff = FromSniffEmacs[0];
+ sniff_connected = 1;
+ return 0;
+ }
+ else /* error in fork() */
+ return 1;
+#endif /* UNIX Version of the Code */
+}
+
+
+/* HandleSniffRequest
+ * Handle one request from SNiFF+
+ */
+ static void
+HandleSniffRequest(buffer)
+ char *buffer;
+{
+ char VICommand[MAX_REQUEST_LEN];
+ char command;
+ char *arguments;
+ char *token;
+ char *argv[3];
+ int argc = 0;
+ buf_T *buf;
+
+ const char *SetTab = "set tabstop=%d";
+ const char *SelectBuf = "buf %s";
+ const char *DeleteBuf = "bd %s";
+ const char *UnloadBuf = "bun %s";
+ const char *GotoLine = "%d";
+
+ command = buffer[0];
+ arguments = &buffer[1];
+ token = strtok(arguments, sniff_rq_sep);
+ while(argc <3)
+ {
+ if (token)
+ {
+ argv[argc] = (char*)vim_strsave((char_u *)token);
+ token = strtok(0, sniff_rq_sep);
+ }
+ else
+ argv[argc] = strdup("");
+ argc++;
+ }
+
+ switch (command)
+ {
+ case 'o' : /* visit file at char pos */
+ case 'O' : /* visit file at line number */
+ {
+ char *file = argv[0];
+ int position = atoi(argv[1]);
+
+ buf = vi_find_buffer(file);
+ setpcmark(); /* insert current pos in jump list [mark.c]*/
+ if (!buf)
+ vi_open_file(file);
+ else if (buf!=curbuf)
+ {
+ sprintf(VICommand, SelectBuf, file);
+ vi_exec_cmd(VICommand);
+ }
+ if (command == 'o')
+ vi_set_cursor_pos((long)position);
+ else
+ {
+ sprintf(VICommand, GotoLine, (int)position);
+ vi_exec_cmd(VICommand);
+ }
+ checkpcmark(); /* [mark.c] */
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32)
+ if (gui.in_use && !gui.in_focus) /* Raise Vim Window */
+ {
+# ifdef FEAT_GUI_W32
+ SetForegroundWindow(s_hwnd);
+# else
+ extern Widget vimShell;
+
+ XSetInputFocus(gui.dpy, XtWindow(vimShell), RevertToNone,
+ CurrentTime);
+ XRaiseWindow(gui.dpy, XtWindow(vimShell));
+# endif
+ }
+#endif
+ break;
+ }
+ case 'p' : /* path of file has changed */
+ /* when changing from shared to private WS (checkout) */
+ {
+ char *file = argv[0];
+ char *new_path = argv[1];
+
+ buf = vi_find_buffer(file);
+ if (buf && !buf->b_changed) /* delete buffer only if not modified */
+ {
+ sprintf(VICommand, DeleteBuf, file);
+ vi_exec_cmd(VICommand);
+ }
+ vi_open_file(new_path);
+ break;
+ }
+ case 'w' : /* writability has changed */
+ /* Sniff sends request twice,
+ * but only the last one is the right one */
+ {
+ char *file = argv[0];
+ int writable = atoi(argv[1]);
+
+ buf = vi_find_buffer(file);
+ if (buf)
+ {
+ buf->b_p_ro = !writable;
+ if (buf != curbuf)
+ {
+ buf->b_flags |= BF_CHECK_RO + BF_NEVERLOADED;
+ if (writable && !buf->b_changed)
+ {
+ sprintf(VICommand, UnloadBuf, file);
+ vi_exec_cmd(VICommand);
+ }
+ }
+ else if (writable && !buf->b_changed)
+ {
+ vi_exec_cmd("e");
+ }
+ }
+ break;
+ }
+ case 'h' : /* highlight info */
+ break; /* not implemented */
+
+ case 't' : /* Set tab width */
+ {
+ int tab_width = atoi(argv[1]);
+
+ if (tab_width > 0 && tab_width <= 16)
+ {
+ sprintf(VICommand, SetTab, tab_width);
+ vi_exec_cmd(VICommand);
+ }
+ break;
+ }
+ case '|':
+ {
+ /* change the request separator */
+ sniff_rq_sep[0] = arguments[0];
+ /* echo the request */
+ WriteToSniff(buffer);
+ break;
+ }
+ case 'A' : /* Warning/Info msg */
+ vi_msg(arguments);
+ if (!strncmp(arguments, "Disconnected", 12)) /* "Disconnected ..." */
+ sniff_disconnect(1); /* unexpected disconnection */
+ break;
+ case 'a' : /* Error msg */
+ vi_error_msg(arguments);
+ if (!strncmp(arguments, "Cannot connect", 14)) /* "Cannot connect ..." */
+ sniff_disconnect(1);
+ break;
+
+ default :
+ break;
+ }
+ while(argc)
+ vim_free(argv[--argc]);
+}
+
+
+#ifndef WIN32
+/* get_request
+ * read string from fd up to next newline (excluding the nl),
+ * returns length of string
+ * 0 if no data available or no complete line
+ * <0 on error
+ */
+ static int
+get_request(fd, buf, maxlen)
+ int fd;
+ char *buf;
+ int maxlen;
+{
+ static char inbuf[1024];
+ static int pos = 0, bytes = 0;
+ int len;
+#ifdef HAVE_SELECT
+ struct timeval tval;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+#else
+ struct pollfd fds;
+
+ fds.fd = fd;
+ fds.events = POLLIN;
+#endif
+
+ for (len = 0; len < maxlen; len++)
+ {
+ if (pos >= bytes) /* end of buffer reached? */
+ {
+#ifdef HAVE_SELECT
+ if (select(fd + 1, &rfds, NULL, NULL, &tval) > 0)
+#else
+ if (poll(&fds, 1, 0) > 0)
+#endif
+ {
+ pos = 0;
+ bytes = read(fd, inbuf, sizeof(inbuf));
+ if (bytes <= 0)
+ return bytes;
+ }
+ else
+ {
+ pos = pos-len;
+ buf[0] = '\0';
+ return 0;
+ }
+ }
+ if ((buf[len] = inbuf[pos++]) =='\n')
+ break;
+ }
+ buf[len] = '\0';
+ return len;
+}
+#endif /* WIN32 */
+
+
+ static void
+SendRequest(command, symbol)
+ struct sn_cmd *command;
+ char *symbol;
+{
+ int cmd_type = command->cmd_type;
+ static char cmdstr[MAX_REQUEST_LEN];
+ static char msgtxt[MAX_REQUEST_LEN];
+ char *buffer_name = NULL;
+
+ if (cmd_type == RQ_CONNECT)
+ {
+ sniff_connect();
+ return;
+ }
+ if (!sniff_connected && !(cmd_type & SILENT))
+ {
+ vi_error_msg(_("E278: SNiFF+ not connected"));
+ return;
+ }
+
+ if (cmd_type & NEED_FILE)
+ {
+ if (!curbuf->b_sniff)
+ {
+ if (!(cmd_type & SILENT))
+ vi_error_msg(_("E279: Not a SNiFF+ buffer"));
+ return;
+ }
+ buffer_name = vi_buffer_name();
+ if (buffer_name == NULL)
+ return;
+ if (cmd_type & NEED_SYMBOL)
+ {
+ if (cmd_type & EMPTY_SYMBOL)
+ symbol = " ";
+ else if (!symbol && !(symbol = vi_symbol_under_cursor()))
+ return; /* error msg already displayed */
+ }
+
+ if (symbol)
+ sprintf(cmdstr, "%c%s%s%ld%s%s\n",
+ command->cmd_code,
+ buffer_name,
+ sniff_rq_sep,
+ vi_cursor_pos(),
+ sniff_rq_sep,
+ symbol
+ );
+ else
+ sprintf(cmdstr, "%c%s\n", command->cmd_code, buffer_name);
+ }
+ else /* simple request */
+ {
+ cmdstr[0] = command->cmd_code;
+ cmdstr[1] = '\n';
+ cmdstr[2] = '\0';
+ }
+ if (command->cmd_msg && !(cmd_type & SILENT))
+ {
+ if ((cmd_type & NEED_SYMBOL) && !(cmd_type & EMPTY_SYMBOL))
+ {
+ sprintf(msgtxt, "%s: %s", _(command->cmd_msg), symbol);
+ vi_msg(msgtxt);
+ }
+ else
+ vi_msg(_(command->cmd_msg));
+ }
+ WriteToSniff(cmdstr);
+ if (cmd_type & DISCONNECT)
+ sniff_disconnect(0);
+}
+
+
+
+ static void
+WriteToSniff(str)
+ char *str;
+{
+ int bytes;
+#ifdef WIN32
+ if (! WriteFile(handle_to_sniff, str, strlen(str), &bytes, NULL))
+ {
+ DWORD err=GetLastError();
+ bytes = -1;
+ }
+#else
+ bytes = write(fd_to_sniff, str, strlen(str));
+#endif
+ if (bytes<0)
+ {
+ vi_msg(_("Sniff: Error during write. Disconnected"));
+ sniff_disconnect(1);
+ }
+}
+
+/*-------- vim helping functions --------------------------------*/
+
+ static void
+vi_msg(str)
+ char *str;
+{
+ if (str != NULL && *str != NUL)
+ MSG((char_u *)str);
+}
+
+ static void
+vi_error_msg(str)
+ char *str;
+{
+ if (str != NULL && *str != NUL)
+ EMSG((char_u *)str);
+}
+
+ static void
+vi_open_file(fname)
+ char *fname;
+{
+ ++no_wait_return;
+ do_ecmd(0, (char_u *)fname, NULL, NULL, ECMD_ONE, ECMD_HIDE+ECMD_OLDBUF);
+ curbuf->b_sniff = TRUE;
+ --no_wait_return; /* [ex_docmd.c] */
+}
+
+ static buf_T *
+vi_find_buffer(fname)
+ char *fname;
+{ /* derived from buflist_findname() [buffer.c] */
+ buf_T *buf;
+
+ for (buf = firstbuf; buf != NULL; buf = buf->b_next)
+ if (buf->b_sfname != NULL && fnamecmp(fname, buf->b_sfname) == 0)
+ return (buf);
+ return NULL;
+}
+
+
+ static char *
+vi_symbol_under_cursor()
+{
+ int len;
+ char *symbolp;
+ char *p;
+ static char sniff_symbol[256];
+
+ len = find_ident_under_cursor((char_u **)&symbolp, FIND_IDENT);
+ /* [normal.c] */
+ if (len <= 0)
+ return NULL;
+ for (p=sniff_symbol; len; len--)
+ *p++ = *symbolp++;
+ *p = '\0';
+ return sniff_symbol;
+}
+
+
+ static char *
+vi_buffer_name()
+{
+ return (char *)curbuf->b_sfname;
+}
+
+ static void
+vi_exec_cmd(vicmd)
+ char *vicmd;
+{
+ do_cmdline_cmd((char_u *)vicmd); /* [ex_docmd.c] */
+}
+
+/*
+ * Set cursor on character position
+ * derived from cursor_pos_info() [buffer.c]
+ */
+ static void
+vi_set_cursor_pos(char_pos)
+ long char_pos;
+{
+ linenr_T lnum;
+ long char_count = 1; /* first position = 1 */
+ int line_size;
+ int eol_size;
+
+ if (char_pos == 0)
+ {
+ char_pos = 1;
+ }
+ if (get_fileformat(curbuf) == EOL_DOS)
+ eol_size = 2;
+ else
+ eol_size = 1;
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ line_size = STRLEN(ml_get(lnum)) + eol_size;
+ if (char_count+line_size > char_pos) break;
+ char_count += line_size;
+ }
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = char_pos - char_count;
+}
+
+ static long
+vi_cursor_pos()
+{
+ linenr_T lnum;
+ long char_count=1; /* sniff starts with pos 1 */
+ int line_size;
+ int eol_size;
+
+ if (curbuf->b_p_tx)
+ eol_size = 2;
+ else
+ eol_size = 1;
+ for (lnum = 1; lnum < curwin->w_cursor.lnum; ++lnum)
+ {
+ line_size = STRLEN(ml_get(lnum)) + eol_size;
+ char_count += line_size;
+ }
+ return char_count + curwin->w_cursor.col;
+}