| /* vi:set ts=8 sts=4 sw=4: |
| * |
| * if_sniff.c Interface between Vim and SNiFF+ |
| * |
| * See README.txt for an overview of the Vim source code. |
| */ |
| |
| #include "vim.h" |
| |
| #ifdef WIN32 |
| # include <stdio.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]; |
| |
| if (pipe(ToSniffEmacs) != 0) |
| return 1; |
| if (pipe(FromSniffEmacs) != 0) |
| return 1; |
| |
| /* 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) |
| { |
| vim_snprintf(VICommand, sizeof(VICommand), |
| (char *)SelectBuf, file); |
| vi_exec_cmd(VICommand); |
| } |
| if (command == 'o') |
| vi_set_cursor_pos((long)position); |
| else |
| { |
| vim_snprintf(VICommand, sizeof(VICommand), |
| (char *)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 */ |
| { |
| vim_snprintf(VICommand, sizeof(VICommand), |
| (char *)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) |
| { |
| vim_snprintf(VICommand, sizeof(VICommand), |
| (char *)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) |
| { |
| vim_snprintf(VICommand, sizeof(VICommand), |
| (char *)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)) |
| sniff_disconnect(1); /* unexpected disconnection */ |
| break; |
| case 'a' : /* Error msg */ |
| vi_error_msg(arguments); |
| if (!strncmp(arguments, "Cannot connect", 14)) |
| 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) |
| vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s%s%ld%s%s\n", |
| command->cmd_code, |
| buffer_name, |
| sniff_rq_sep, |
| vi_cursor_pos(), |
| sniff_rq_sep, |
| symbol |
| ); |
| else |
| vim_snprintf(cmdstr, sizeof(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)) |
| { |
| vim_snprintf(msgtxt, sizeof(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, |
| curwin); |
| 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; |
| } |