diff options
author | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
commit | 071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch) | |
tree | 221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/if_sniff.c | |
parent | b4210b3bc14e2918f153a7307530fbe6eba659e1 (diff) | |
download | vim-git-071d4279d6ab81b7187b48f3a0fc61e587b6db6c.tar.gz |
updated for version 7.0001v7.0001
Diffstat (limited to 'src/if_sniff.c')
-rw-r--r-- | src/if_sniff.c | 1210 |
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; +} |