Mercurial > vim
view src/if_sniff.c @ 4608:a1d3d9db4340
Added tag v7-3-1051 for changeset 70600448f9e7
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 29 May 2013 22:49:26 +0200 |
parents | ee138f29259e |
children | 2ebc20378f68 |
line wrap: on
line source
/* 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; }