1/* vi:set ts=8 sts=4 sw=4: 2 * 3 * if_sniff.c Interface between Vim and SNiFF+ 4 * 5 * See README.txt for an overview of the Vim source code. 6 */ 7 8#include "vim.h" 9 10#ifdef WIN32 11# include <stdio.h> 12# include "vimio.h" 13# include <process.h> 14# include <string.h> 15# include <assert.h> 16#else 17# ifdef FEAT_GUI_X11 18# include "gui_x11.pro" 19# endif 20# include "os_unixx.h" 21#endif 22 23static int sniffemacs_pid; 24 25int fd_from_sniff; 26int sniff_connected = 0; 27int sniff_request_waiting = 0; 28int want_sniff_request = 0; 29 30#define MAX_REQUEST_LEN 512 31 32#define NEED_SYMBOL 2 33#define EMPTY_SYMBOL 4 34#define NEED_FILE 8 35#define SILENT 16 36#define DISCONNECT 32 37#define CONNECT 64 38 39#define RQ_NONE 0 40#define RQ_SIMPLE 1 41#define RQ_CONTEXT NEED_FILE + NEED_SYMBOL 42#define RQ_SCONTEXT NEED_FILE + NEED_SYMBOL + EMPTY_SYMBOL 43#define RQ_NOSYMBOL NEED_FILE 44#define RQ_SILENT RQ_NOSYMBOL + SILENT 45#define RQ_CONNECT RQ_NONE + CONNECT 46#define RQ_DISCONNECT RQ_SIMPLE + DISCONNECT 47 48struct sn_cmd 49{ 50 char *cmd_name; 51 char cmd_code; 52 char *cmd_msg; 53 int cmd_type; 54}; 55 56struct sn_cmd_list 57{ 58 struct sn_cmd* sniff_cmd; 59 struct sn_cmd_list* next_cmd; 60}; 61 62static struct sn_cmd sniff_cmds[] = 63{ 64 { "toggle", 'e', N_("Toggle implementation/definition"),RQ_SCONTEXT }, 65 { "superclass", 's', N_("Show base class of"), RQ_CONTEXT }, 66 { "overridden", 'm', N_("Show overridden member function"),RQ_SCONTEXT }, 67 { "retrieve-file", 'r', N_("Retrieve from file"), RQ_CONTEXT }, 68 { "retrieve-project",'p', N_("Retrieve from project"), RQ_CONTEXT }, 69 { "retrieve-all-projects", 70 'P', N_("Retrieve from all projects"), RQ_CONTEXT }, 71 { "retrieve-next", 'R', N_("Retrieve"), RQ_CONTEXT }, 72 { "goto-symbol", 'g', N_("Show source of"), RQ_CONTEXT }, 73 { "find-symbol", 'f', N_("Find symbol"), RQ_CONTEXT }, 74 { "browse-class", 'w', N_("Browse class"), RQ_CONTEXT }, 75 { "hierarchy", 't', N_("Show class in hierarchy"), RQ_CONTEXT }, 76 { "restr-hier", 'T', N_("Show class in restricted hierarchy"),RQ_CONTEXT }, 77 { "xref-to", 'x', N_("Xref refers to"), RQ_CONTEXT }, 78 { "xref-by", 'X', N_("Xref referred by"), RQ_CONTEXT }, 79 { "xref-has", 'c', N_("Xref has a"), RQ_CONTEXT }, 80 { "xref-used-by", 'C', N_("Xref used by"), RQ_CONTEXT }, 81 { "show-docu", 'd', N_("Show docu of"), RQ_CONTEXT }, 82 { "gen-docu", 'D', N_("Generate docu for"), RQ_CONTEXT }, 83 { "connect", 'y', NULL, RQ_CONNECT }, 84 { "disconnect", 'q', NULL, RQ_DISCONNECT }, 85 { "font-info", 'z', NULL, RQ_SILENT }, 86 { "update", 'u', NULL, RQ_SILENT }, 87 { NULL, '\0', NULL, 0} 88}; 89 90 91static char *SniffEmacs[2] = {"sniffemacs", (char *)NULL}; /* Yes, Emacs! */ 92static int fd_to_sniff; 93static int sniff_will_disconnect = 0; 94static char msg_sniff_disconnect[] = N_("Cannot connect to SNiFF+. Check environment (sniffemacs must be found in $PATH).\n"); 95static char sniff_rq_sep[] = " "; 96static struct sn_cmd_list *sniff_cmd_ext = NULL; 97 98/* Initializing vim commands 99 * executed each time vim connects to Sniff 100 */ 101static char *init_cmds[]= { 102 "augroup sniff", 103 "autocmd BufWritePost * sniff update", 104 "autocmd BufReadPost * sniff font-info", 105 "autocmd VimLeave * sniff disconnect", 106 "augroup END", 107 108 "let g:sniff_connected = 1", 109 110 "if ! exists('g:sniff_mappings_sourced')|" 111 "if ! exists('g:sniff_mappings')|" 112 "if exists('$SNIFF_DIR4')|" 113 "let g:sniff_mappings='$SNIFF_DIR4/config/integrations/vim/sniff.vim'|" 114 "else|" 115 "let g:sniff_mappings='$SNIFF_DIR/config/sniff.vim'|" 116 "endif|" 117 "endif|" 118 "let g:sniff_mappings=expand(g:sniff_mappings)|" 119 "if filereadable(g:sniff_mappings)|" 120 "execute 'source' g:sniff_mappings|" 121 "let g:sniff_mappings_sourced=1|" 122 "endif|" 123 "endif", 124 125 NULL 126}; 127 128/*-------- Function Prototypes ----------------------------------*/ 129 130static int ConnectToSniffEmacs __ARGS((void)); 131static void sniff_connect __ARGS((void)); 132static void HandleSniffRequest __ARGS((char* buffer)); 133static int get_request __ARGS((int fd, char *buf, int maxlen)); 134static void WriteToSniff __ARGS((char *str)); 135static void SendRequest __ARGS((struct sn_cmd *command, char* symbol)); 136static void vi_msg __ARGS((char *)); 137static void vi_error_msg __ARGS((char *)); 138static char *vi_symbol_under_cursor __ARGS((void)); 139static void vi_open_file __ARGS((char *)); 140static char *vi_buffer_name __ARGS((void)); 141static buf_T *vi_find_buffer __ARGS((char *)); 142static void vi_exec_cmd __ARGS((char *)); 143static void vi_set_cursor_pos __ARGS((long char_nr)); 144static long vi_cursor_pos __ARGS((void)); 145 146/* debug trace */ 147#if 0 148static FILE* _tracefile = NULL; 149#define SNIFF_TRACE_OPEN(file) if (!_tracefile) _tracefile = fopen(file, "w") 150#define SNIFF_TRACE(msg) fprintf(_tracefile, msg); fflush(_tracefile); 151#define SNIFF_TRACE1(msg, arg) fprintf(_tracefile, msg,arg); fflush(_tracefile); 152#define SNIFF_TRACE_CLOSE fclose(_tracefile); _tracefile=NULL; 153#else 154#define SNIFF_TRACE_OPEN(file) 155#define SNIFF_TRACE(msg) 156#define SNIFF_TRACE1(msg, arg) 157#define SNIFF_TRACE_CLOSE 158#endif 159 160/*-------- Windows Only Declarations -----------------------------*/ 161#ifdef WIN32 162 163static int sniff_request_processed=1; 164static HANDLE sniffemacs_handle=NULL; 165static HANDLE readthread_handle=NULL; 166static HANDLE handle_to_sniff=NULL; 167static HANDLE handle_from_sniff=NULL; 168 169struct sniffBufNode 170{ 171 struct sniffBufNode *next; 172 int bufLen; 173 char buf[MAX_REQUEST_LEN]; 174}; 175static struct sniffBufNode *sniffBufStart=NULL; 176static struct sniffBufNode *sniffBufEnd=NULL; 177static HANDLE hBufferMutex=NULL; 178 179# ifdef FEAT_GUI_W32 180 extern HWND s_hwnd; /* gvim's Window handle */ 181# endif 182/* 183 * some helper functions for Windows port only 184 */ 185 186 static HANDLE 187ExecuteDetachedProgram(char *szBinary, char *szCmdLine, 188 HANDLE hStdInput, HANDLE hStdOutput) 189{ 190 BOOL bResult; 191 DWORD nError; 192 PROCESS_INFORMATION aProcessInformation; 193 PROCESS_INFORMATION *pProcessInformation= &aProcessInformation; 194 STARTUPINFO aStartupInfo; 195 STARTUPINFO *pStartupInfo= &aStartupInfo; 196 DWORD dwCreationFlags= 0; 197 char szPath[512]; 198 HINSTANCE hResult; 199 200 hResult = FindExecutable(szBinary, ".", szPath); 201 if ((int)hResult <= 32) 202 { 203 /* can't find the exe file */ 204 return NULL; 205 } 206 207 ZeroMemory(pStartupInfo, sizeof(*pStartupInfo)); 208 pStartupInfo->dwFlags= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 209 pStartupInfo->hStdInput = hStdInput; 210 pStartupInfo->hStdOutput = hStdOutput; 211 pStartupInfo->wShowWindow= SW_HIDE; 212 pStartupInfo->cb = sizeof(STARTUPINFO); 213 214 bResult= CreateProcess( 215 szPath, 216 szCmdLine, 217 NULL, /* security attr for process */ 218 NULL, /* security attr for primary thread */ 219 TRUE, /* DO inherit stdin and stdout */ 220 dwCreationFlags, /* creation flags */ 221 NULL, /* environment */ 222 ".", /* current directory */ 223 pStartupInfo, /* startup info: NULL crashes */ 224 pProcessInformation /* process information: NULL crashes */ 225 ); 226 nError= GetLastError(); 227 if (bResult) 228 { 229 CloseHandle(pProcessInformation->hThread); 230 CloseHandle(hStdInput); 231 CloseHandle(hStdOutput); 232 return(pProcessInformation->hProcess); 233 } 234 else 235 return(NULL); 236} 237 238/* 239 * write to the internal Thread / Thread communications buffer. 240 * Return TRUE if successful, FALSE else. 241 */ 242 static BOOL 243writeToBuffer(char *msg, int len) 244{ 245 DWORD dwWaitResult; /* Request ownership of mutex. */ 246 struct sniffBufNode *bn; 247 int bnSize; 248 249 SNIFF_TRACE1("writeToBuffer %d\n", len); 250 bnSize = sizeof(struct sniffBufNode) - MAX_REQUEST_LEN + len + 1; 251 if (bnSize < 128) bnSize = 128; /* minimum length to avoid fragmentation */ 252 bn = (struct sniffBufNode *)malloc(bnSize); 253 if (!bn) 254 return FALSE; 255 256 memcpy(bn->buf, msg, len); 257 bn->buf[len]='\0'; /* terminate CString for added safety */ 258 bn->next = NULL; 259 bn->bufLen = len; 260 /* now, acquire a Mutex for adding the string to our linked list */ 261 dwWaitResult = WaitForSingleObject( 262 hBufferMutex, /* handle of mutex */ 263 1000L); /* one-second time-out interval */ 264 if (dwWaitResult == WAIT_OBJECT_0) 265 { 266 /* The thread got mutex ownership. */ 267 if (sniffBufEnd) 268 { 269 sniffBufEnd->next = bn; 270 sniffBufEnd = bn; 271 } 272 else 273 sniffBufStart = sniffBufEnd = bn; 274 /* Release ownership of the mutex object. */ 275 if (! ReleaseMutex(hBufferMutex)) 276 { 277 /* Deal with error. */ 278 } 279 return TRUE; 280 } 281 282 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */ 283 free(bn); 284 return FALSE; 285} 286 287/* 288 * read from the internal Thread / Thread communications buffer. 289 * Return TRUE if successful, FALSE else. 290 */ 291 static int 292ReadFromBuffer(char *buf, int maxlen) 293{ 294 DWORD dwWaitResult; /* Request ownership of mutex. */ 295 int theLen; 296 struct sniffBufNode *bn; 297 298 dwWaitResult = WaitForSingleObject( 299 hBufferMutex, /* handle of mutex */ 300 1000L); /* one-second time-out interval */ 301 if (dwWaitResult == WAIT_OBJECT_0) 302 { 303 if (!sniffBufStart) 304 { 305 /* all pending Requests Processed */ 306 theLen = 0; 307 } 308 else 309 { 310 bn = sniffBufStart; 311 theLen = bn->bufLen; 312 SNIFF_TRACE1("ReadFromBuffer %d\n", theLen); 313 if (theLen >= maxlen) 314 { 315 /* notify the user of buffer overflow? */ 316 theLen = maxlen-1; 317 } 318 memcpy(buf, bn->buf, theLen); 319 buf[theLen] = '\0'; 320 if (! (sniffBufStart = bn->next)) 321 { 322 sniffBufEnd = NULL; 323 sniff_request_processed = 1; 324 } 325 free(bn); 326 } 327 if (! ReleaseMutex(hBufferMutex)) 328 { 329 /* Deal with error. */ 330 } 331 return theLen; 332 } 333 334 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */ 335 return -1; 336} 337 338/* on Win32, a separate Thread reads the input pipe. get_request is not needed here. */ 339 static void __cdecl 340SniffEmacsReadThread(void *dummy) 341{ 342 static char ReadThreadBuffer[MAX_REQUEST_LEN]; 343 int ReadThreadLen=0; 344 int result=0; 345 int msgLen=0; 346 char *msgStart, *msgCur; 347 348 SNIFF_TRACE("begin thread\n"); 349 /* Read from the pipe to SniffEmacs */ 350 while (sniff_connected) 351 { 352 if (!ReadFile(handle_from_sniff, 353 ReadThreadBuffer + ReadThreadLen, /* acknowledge rest in buffer */ 354 MAX_REQUEST_LEN - ReadThreadLen, 355 &result, 356 NULL)) 357 { 358 DWORD err = GetLastError(); 359 result = -1; 360 } 361 362 if (result < 0) 363 { 364 /* probably sniffemacs died... log the Error? */ 365 sniff_disconnect(1); 366 } 367 else if (result > 0) 368 { 369 ReadThreadLen += result-1; /* total length of valid chars */ 370 for(msgCur=msgStart=ReadThreadBuffer; ReadThreadLen > 0; msgCur++, ReadThreadLen--) 371 { 372 if (*msgCur == '\0' || *msgCur == '\r' || *msgCur == '\n') 373 { 374 msgLen = msgCur-msgStart; /* don't add the CR/LF chars */ 375 if (msgLen > 0) 376 writeToBuffer(msgStart, msgLen); 377 msgStart = msgCur + 1; /* over-read single CR/LF chars */ 378 } 379 } 380 381 /* move incomplete message to beginning of buffer */ 382 ReadThreadLen = msgCur - msgStart; 383 if (ReadThreadLen > 0) 384 mch_memmove(ReadThreadBuffer, msgStart, ReadThreadLen); 385 386 if (sniff_request_processed) 387 { 388 /* notify others that new data has arrived */ 389 sniff_request_processed = 0; 390 sniff_request_waiting = 1; 391#ifdef FEAT_GUI_W32 392 PostMessage(s_hwnd, WM_USER, (WPARAM)0, (LPARAM)0); 393#endif 394 } 395 } 396 } 397 SNIFF_TRACE("end thread\n"); 398} 399#endif /* WIN32 */ 400/*-------- End of Windows Only Declarations ------------------------*/ 401 402 403/* ProcessSniffRequests 404 * Function that should be called from outside 405 * to process the waiting sniff requests 406 */ 407 void 408ProcessSniffRequests() 409{ 410 static char buf[MAX_REQUEST_LEN]; 411 int len; 412 413 while (sniff_connected) 414 { 415#ifdef WIN32 416 len = ReadFromBuffer(buf, sizeof(buf)); 417#else 418 len = get_request(fd_from_sniff, buf, sizeof(buf)); 419#endif 420 if (len < 0) 421 { 422 vi_error_msg(_("E274: Sniff: Error during read. Disconnected")); 423 sniff_disconnect(1); 424 break; 425 } 426 else if (len > 0) 427 HandleSniffRequest( buf ); 428 else 429 break; 430 } 431 432 if (sniff_will_disconnect) /* Now the last msg has been processed */ 433 sniff_disconnect(1); 434} 435 436 static struct sn_cmd * 437find_sniff_cmd(cmd) 438 char *cmd; 439{ 440 struct sn_cmd *sniff_cmd = NULL; 441 int i; 442 for(i=0; sniff_cmds[i].cmd_name; i++) 443 { 444 if (!strcmp(cmd, sniff_cmds[i].cmd_name)) 445 { 446 sniff_cmd = &sniff_cmds[i]; 447 break; 448 } 449 } 450 if (!sniff_cmd) 451 { 452 struct sn_cmd_list *list = sniff_cmd_ext; 453 while(list) 454 { 455 if (!strcmp(cmd, list->sniff_cmd->cmd_name)) 456 { 457 sniff_cmd = list->sniff_cmd; 458 break; 459 } 460 list = list->next_cmd; 461 } 462 } 463 return sniff_cmd; 464} 465 466 static int 467add_sniff_cmd(cmd, def, msg) 468 char *cmd; 469 char *def; 470 char *msg; 471{ 472 int rc = 0; 473 if (def != NULL && def[0] != NUL && find_sniff_cmd(cmd) == NULL) 474 { 475 struct sn_cmd_list *list = sniff_cmd_ext; 476 struct sn_cmd *sniff_cmd = (struct sn_cmd*)malloc(sizeof(struct sn_cmd)); 477 struct sn_cmd_list *cmd_node = (struct sn_cmd_list*)malloc(sizeof(struct sn_cmd_list)); 478 int rq_type = 0; 479 480 /* unescape message text */ 481 char *p = msg; 482 char *end = p+strlen(msg); 483 while(*p) 484 { 485 if (*p == '\\') 486 mch_memmove(p,p+1,end-p); 487 p++; 488 } 489 SNIFF_TRACE1("request name = %s\n",cmd); 490 SNIFF_TRACE1("request def = %s\n",def); 491 SNIFF_TRACE1("request msg = %s\n",msg); 492 493 while(list && list->next_cmd) 494 list = list->next_cmd; 495 if (!list) 496 sniff_cmd_ext = cmd_node; 497 else 498 list->next_cmd = cmd_node; 499 500 sniff_cmd->cmd_name = cmd; 501 sniff_cmd->cmd_code = def[0]; 502 sniff_cmd->cmd_msg = msg; 503 switch(def[1]) 504 { 505 case 'f': 506 rq_type = RQ_NOSYMBOL; 507 break; 508 case 's': 509 rq_type = RQ_CONTEXT; 510 break; 511 case 'S': 512 rq_type = RQ_SCONTEXT; 513 break; 514 default: 515 rq_type = RQ_SIMPLE; 516 break; 517 } 518 sniff_cmd->cmd_type = rq_type; 519 cmd_node->sniff_cmd = sniff_cmd; 520 cmd_node->next_cmd = NULL; 521 rc = 1; 522 } 523 return rc; 524} 525 526/* ex_sniff 527 * Handle ":sniff" command 528 */ 529 void 530ex_sniff(eap) 531 exarg_T *eap; 532{ 533 char_u *arg = eap->arg; 534 char_u *symbol = NULL; 535 char_u *cmd = NULL; 536 537 SNIFF_TRACE_OPEN("if_sniff.log"); 538 if (ends_excmd(*arg)) /* no request: print available commands */ 539 { 540 int i; 541 msg_start(); 542 msg_outtrans_attr((char_u *)"-- SNiFF+ commands --", hl_attr(HLF_T)); 543 for(i=0; sniff_cmds[i].cmd_name; i++) 544 { 545 msg_putchar('\n'); 546 msg_outtrans((char_u *)":sniff "); 547 msg_outtrans((char_u *)sniff_cmds[i].cmd_name); 548 } 549 msg_putchar('\n'); 550 msg_outtrans((char_u *)_("SNiFF+ is currently ")); 551 if (!sniff_connected) 552 msg_outtrans((char_u *)_("not ")); 553 msg_outtrans((char_u *)_("connected")); 554 msg_end(); 555 } 556 else /* extract command name and symbol if present */ 557 { 558 symbol = skiptowhite(arg); 559 cmd = vim_strnsave(arg, (int)(symbol-arg)); 560 symbol = skipwhite(symbol); 561 if (ends_excmd(*symbol)) 562 symbol = NULL; 563 if (!strcmp((char *)cmd, "addcmd")) 564 { 565 char_u *def = skiptowhite(symbol); 566 char_u *name = vim_strnsave(symbol, (int)(def-symbol)); 567 char_u *msg; 568 def = skipwhite(def); 569 msg = skiptowhite(def); 570 def = vim_strnsave(def, (int)(msg-def)); 571 msg = skipwhite(msg); 572 if (ends_excmd(*msg)) 573 msg = vim_strsave(name); 574 else 575 msg = vim_strnsave(msg, (int)(skiptowhite_esc(msg)-msg)); 576 if (!add_sniff_cmd((char*)name, (char*)def, (char*)msg)) 577 { 578 vim_free(msg); 579 vim_free(def); 580 vim_free(name); 581 } 582 } 583 else 584 { 585 struct sn_cmd* sniff_cmd = find_sniff_cmd((char*)cmd); 586 if (sniff_cmd) 587 SendRequest(sniff_cmd, (char *)symbol); 588 else 589 EMSG2(_("E275: Unknown SNiFF+ request: %s"), cmd); 590 } 591 vim_free(cmd); 592 } 593} 594 595 596 static void 597sniff_connect() 598{ 599 if (sniff_connected) 600 return; 601 if (ConnectToSniffEmacs()) 602 vi_error_msg(_("E276: Error connecting to SNiFF+")); 603 else 604 { 605 int i; 606 607 for (i = 0; init_cmds[i]; i++) 608 vi_exec_cmd(init_cmds[i]); 609 } 610} 611 612 void 613sniff_disconnect(immediately) 614 int immediately; 615{ 616 if (!sniff_connected) 617 return; 618 if (immediately) 619 { 620 vi_exec_cmd("augroup sniff"); 621 vi_exec_cmd("au!"); 622 vi_exec_cmd("augroup END"); 623 vi_exec_cmd("unlet g:sniff_connected"); 624 sniff_connected = 0; 625 want_sniff_request = 0; 626 sniff_will_disconnect = 0; 627#ifdef FEAT_GUI 628 if (gui.in_use) 629 gui_mch_wait_for_chars(0L); 630#endif 631#ifdef WIN32 632 while(sniffBufStart != NULL) 633 { 634 struct sniffBufNode *node = sniffBufStart; 635 sniffBufStart = sniffBufStart->next; 636 free(node); 637 } 638 sniffBufStart = sniffBufEnd = NULL; 639 sniff_request_processed = 1; 640 CloseHandle(handle_to_sniff); 641 CloseHandle(handle_from_sniff); 642 WaitForSingleObject(sniffemacs_handle, 1000L); 643 CloseHandle(sniffemacs_handle); 644 sniffemacs_handle = NULL; 645 WaitForSingleObject(readthread_handle, 1000L); 646 readthread_handle = NULL; 647 CloseHandle(hBufferMutex); 648 hBufferMutex = NULL; 649 SNIFF_TRACE_CLOSE; 650#else 651 close(fd_to_sniff); 652 close(fd_from_sniff); 653 wait(NULL); 654#endif 655 } 656 else 657 { 658#ifdef WIN32 659 _sleep(2); 660 if (!sniff_request_processed) 661 ProcessSniffRequests(); 662#else 663 sleep(2); /* Incoming msg could disturb edit */ 664#endif 665 sniff_will_disconnect = 1; /* We expect disconnect msg in 2 secs */ 666 } 667} 668 669 670/* ConnectToSniffEmacs 671 * Connect to Sniff: returns 1 on error 672 */ 673 static int 674ConnectToSniffEmacs() 675{ 676#ifdef WIN32 /* Windows Version of the Code */ 677 HANDLE ToSniffEmacs[2], FromSniffEmacs[2]; 678 SECURITY_ATTRIBUTES sa; 679 680 sa.nLength = sizeof(sa); 681 sa.lpSecurityDescriptor = NULL; 682 sa.bInheritHandle = TRUE; 683 684 if (! CreatePipe(&ToSniffEmacs[0], &ToSniffEmacs[1], &sa, 0)) 685 return 1; 686 if (! CreatePipe(&FromSniffEmacs[0], &FromSniffEmacs[1], &sa, 0)) 687 return 1; 688 689 sniffemacs_handle = ExecuteDetachedProgram(SniffEmacs[0], SniffEmacs[0], 690 ToSniffEmacs[0], FromSniffEmacs[1]); 691 692 if (sniffemacs_handle) 693 { 694 handle_to_sniff = ToSniffEmacs[1]; 695 handle_from_sniff = FromSniffEmacs[0]; 696 sniff_connected = 1; 697 hBufferMutex = CreateMutex( 698 NULL, /* no security attributes */ 699 FALSE, /* initially not owned */ 700 "SniffReadBufferMutex"); /* name of mutex */ 701 if (hBufferMutex == NULL) 702 { 703 /* Check for error. */ 704 } 705 readthread_handle = (HANDLE)_beginthread(SniffEmacsReadThread, 0, NULL); 706 return 0; 707 } 708 else 709 { 710 /* error in spawn() */ 711 return 1; 712 } 713 714#else /* UNIX Version of the Code */ 715 int ToSniffEmacs[2], FromSniffEmacs[2]; 716 717 if (pipe(ToSniffEmacs) != 0) 718 return 1; 719 if (pipe(FromSniffEmacs) != 0) 720 return 1; 721 722 /* fork */ 723 if ((sniffemacs_pid=fork()) == 0) 724 { 725 /* child */ 726 727 /* prepare communication pipes */ 728 close(ToSniffEmacs[1]); 729 close(FromSniffEmacs[0]); 730 731 dup2(ToSniffEmacs[0],fileno(stdin)); /* write to ToSniffEmacs[1] */ 732 dup2(FromSniffEmacs[1],fileno(stdout));/* read from FromSniffEmacs[0] */ 733 734 close(ToSniffEmacs[0]); 735 close(FromSniffEmacs[1]); 736 737 /* start sniffemacs */ 738 execvp (SniffEmacs[0], SniffEmacs); 739 { 740/* FILE *out = fdopen(FromSniffEmacs[1], "w"); */ 741 sleep(1); 742 fputs(_(msg_sniff_disconnect), stdout); 743 fflush(stdout); 744 sleep(3); 745#ifdef FEAT_GUI 746 if (gui.in_use) 747 gui_exit(1); 748#endif 749 exit(1); 750 } 751 return 1; 752 } 753 else if (sniffemacs_pid > 0) 754 { 755 /* parent process */ 756 close(ToSniffEmacs[0]); 757 fd_to_sniff = ToSniffEmacs[1]; 758 close(FromSniffEmacs[1]); 759 fd_from_sniff = FromSniffEmacs[0]; 760 sniff_connected = 1; 761 return 0; 762 } 763 else /* error in fork() */ 764 return 1; 765#endif /* UNIX Version of the Code */ 766} 767 768 769/* HandleSniffRequest 770 * Handle one request from SNiFF+ 771 */ 772 static void 773HandleSniffRequest(buffer) 774 char *buffer; 775{ 776 char VICommand[MAX_REQUEST_LEN]; 777 char command; 778 char *arguments; 779 char *token; 780 char *argv[3]; 781 int argc = 0; 782 buf_T *buf; 783 784 const char *SetTab = "set tabstop=%d"; 785 const char *SelectBuf = "buf %s"; 786 const char *DeleteBuf = "bd %s"; 787 const char *UnloadBuf = "bun %s"; 788 const char *GotoLine = "%d"; 789 790 command = buffer[0]; 791 arguments = &buffer[1]; 792 token = strtok(arguments, sniff_rq_sep); 793 while(argc <3) 794 { 795 if (token) 796 { 797 argv[argc] = (char*)vim_strsave((char_u *)token); 798 token = strtok(0, sniff_rq_sep); 799 } 800 else 801 argv[argc] = strdup(""); 802 argc++; 803 } 804 805 switch (command) 806 { 807 case 'o' : /* visit file at char pos */ 808 case 'O' : /* visit file at line number */ 809 { 810 char *file = argv[0]; 811 int position = atoi(argv[1]); 812 813 buf = vi_find_buffer(file); 814 setpcmark(); /* insert current pos in jump list [mark.c]*/ 815 if (!buf) 816 vi_open_file(file); 817 else if (buf!=curbuf) 818 { 819 vim_snprintf(VICommand, sizeof(VICommand), 820 (char *)SelectBuf, file); 821 vi_exec_cmd(VICommand); 822 } 823 if (command == 'o') 824 vi_set_cursor_pos((long)position); 825 else 826 { 827 vim_snprintf(VICommand, sizeof(VICommand), 828 (char *)GotoLine, (int)position); 829 vi_exec_cmd(VICommand); 830 } 831 checkpcmark(); /* [mark.c] */ 832#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32) 833 if (gui.in_use && !gui.in_focus) /* Raise Vim Window */ 834 { 835# ifdef FEAT_GUI_W32 836 SetForegroundWindow(s_hwnd); 837# else 838 extern Widget vimShell; 839 840 XSetInputFocus(gui.dpy, XtWindow(vimShell), RevertToNone, 841 CurrentTime); 842 XRaiseWindow(gui.dpy, XtWindow(vimShell)); 843# endif 844 } 845#endif 846 break; 847 } 848 case 'p' : /* path of file has changed */ 849 /* when changing from shared to private WS (checkout) */ 850 { 851 char *file = argv[0]; 852 char *new_path = argv[1]; 853 854 buf = vi_find_buffer(file); 855 if (buf && !buf->b_changed) /* delete buffer only if not modified */ 856 { 857 vim_snprintf(VICommand, sizeof(VICommand), 858 (char *)DeleteBuf, file); 859 vi_exec_cmd(VICommand); 860 } 861 vi_open_file(new_path); 862 break; 863 } 864 case 'w' : /* writability has changed */ 865 /* Sniff sends request twice, 866 * but only the last one is the right one */ 867 { 868 char *file = argv[0]; 869 int writable = atoi(argv[1]); 870 871 buf = vi_find_buffer(file); 872 if (buf) 873 { 874 buf->b_p_ro = !writable; 875 if (buf != curbuf) 876 { 877 buf->b_flags |= BF_CHECK_RO + BF_NEVERLOADED; 878 if (writable && !buf->b_changed) 879 { 880 vim_snprintf(VICommand, sizeof(VICommand), 881 (char *)UnloadBuf, file); 882 vi_exec_cmd(VICommand); 883 } 884 } 885 else if (writable && !buf->b_changed) 886 { 887 vi_exec_cmd("e"); 888 } 889 } 890 break; 891 } 892 case 'h' : /* highlight info */ 893 break; /* not implemented */ 894 895 case 't' : /* Set tab width */ 896 { 897 int tab_width = atoi(argv[1]); 898 899 if (tab_width > 0 && tab_width <= 16) 900 { 901 vim_snprintf(VICommand, sizeof(VICommand), 902 (char *)SetTab, tab_width); 903 vi_exec_cmd(VICommand); 904 } 905 break; 906 } 907 case '|': 908 { 909 /* change the request separator */ 910 sniff_rq_sep[0] = arguments[0]; 911 /* echo the request */ 912 WriteToSniff(buffer); 913 break; 914 } 915 case 'A' : /* Warning/Info msg */ 916 vi_msg(arguments); 917 if (!strncmp(arguments, "Disconnected", 12)) 918 sniff_disconnect(1); /* unexpected disconnection */ 919 break; 920 case 'a' : /* Error msg */ 921 vi_error_msg(arguments); 922 if (!strncmp(arguments, "Cannot connect", 14)) 923 sniff_disconnect(1); 924 break; 925 926 default : 927 break; 928 } 929 while(argc) 930 vim_free(argv[--argc]); 931} 932 933 934#ifndef WIN32 935/* get_request 936 * read string from fd up to next newline (excluding the nl), 937 * returns length of string 938 * 0 if no data available or no complete line 939 * <0 on error 940 */ 941 static int 942get_request(fd, buf, maxlen) 943 int fd; 944 char *buf; 945 int maxlen; 946{ 947 static char inbuf[1024]; 948 static int pos = 0, bytes = 0; 949 int len; 950#ifdef HAVE_SELECT 951 struct timeval tval; 952 fd_set rfds; 953 954 FD_ZERO(&rfds); 955 FD_SET(fd, &rfds); 956 tval.tv_sec = 0; 957 tval.tv_usec = 0; 958#else 959 struct pollfd fds; 960 961 fds.fd = fd; 962 fds.events = POLLIN; 963#endif 964 965 for (len = 0; len < maxlen; len++) 966 { 967 if (pos >= bytes) /* end of buffer reached? */ 968 { 969#ifdef HAVE_SELECT 970 if (select(fd + 1, &rfds, NULL, NULL, &tval) > 0) 971#else 972 if (poll(&fds, 1, 0) > 0) 973#endif 974 { 975 pos = 0; 976 bytes = read(fd, inbuf, sizeof(inbuf)); 977 if (bytes <= 0) 978 return bytes; 979 } 980 else 981 { 982 pos = pos-len; 983 buf[0] = '\0'; 984 return 0; 985 } 986 } 987 if ((buf[len] = inbuf[pos++]) =='\n') 988 break; 989 } 990 buf[len] = '\0'; 991 return len; 992} 993#endif /* WIN32 */ 994 995 996 static void 997SendRequest(command, symbol) 998 struct sn_cmd *command; 999 char *symbol; 1000{ 1001 int cmd_type = command->cmd_type; 1002 static char cmdstr[MAX_REQUEST_LEN]; 1003 static char msgtxt[MAX_REQUEST_LEN]; 1004 char *buffer_name = NULL; 1005 1006 if (cmd_type == RQ_CONNECT) 1007 { 1008 sniff_connect(); 1009 return; 1010 } 1011 if (!sniff_connected && !(cmd_type & SILENT)) 1012 { 1013 vi_error_msg(_("E278: SNiFF+ not connected")); 1014 return; 1015 } 1016 1017 if (cmd_type & NEED_FILE) 1018 { 1019 if (!curbuf->b_sniff) 1020 { 1021 if (!(cmd_type & SILENT)) 1022 vi_error_msg(_("E279: Not a SNiFF+ buffer")); 1023 return; 1024 } 1025 buffer_name = vi_buffer_name(); 1026 if (buffer_name == NULL) 1027 return; 1028 if (cmd_type & NEED_SYMBOL) 1029 { 1030 if (cmd_type & EMPTY_SYMBOL) 1031 symbol = " "; 1032 else if (!symbol && !(symbol = vi_symbol_under_cursor())) 1033 return; /* error msg already displayed */ 1034 } 1035 1036 if (symbol) 1037 vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s%s%ld%s%s\n", 1038 command->cmd_code, 1039 buffer_name, 1040 sniff_rq_sep, 1041 vi_cursor_pos(), 1042 sniff_rq_sep, 1043 symbol 1044 ); 1045 else 1046 vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s\n", 1047 command->cmd_code, buffer_name); 1048 } 1049 else /* simple request */ 1050 { 1051 cmdstr[0] = command->cmd_code; 1052 cmdstr[1] = '\n'; 1053 cmdstr[2] = '\0'; 1054 } 1055 if (command->cmd_msg && !(cmd_type & SILENT)) 1056 { 1057 if ((cmd_type & NEED_SYMBOL) && !(cmd_type & EMPTY_SYMBOL)) 1058 { 1059 vim_snprintf(msgtxt, sizeof(msgtxt), "%s: %s", 1060 _(command->cmd_msg), symbol); 1061 vi_msg(msgtxt); 1062 } 1063 else 1064 vi_msg(_(command->cmd_msg)); 1065 } 1066 WriteToSniff(cmdstr); 1067 if (cmd_type & DISCONNECT) 1068 sniff_disconnect(0); 1069} 1070 1071 1072 1073 static void 1074WriteToSniff(str) 1075 char *str; 1076{ 1077 int bytes; 1078#ifdef WIN32 1079 if (! WriteFile(handle_to_sniff, str, strlen(str), &bytes, NULL)) 1080 { 1081 DWORD err=GetLastError(); 1082 bytes = -1; 1083 } 1084#else 1085 bytes = write(fd_to_sniff, str, strlen(str)); 1086#endif 1087 if (bytes<0) 1088 { 1089 vi_msg(_("Sniff: Error during write. Disconnected")); 1090 sniff_disconnect(1); 1091 } 1092} 1093 1094/*-------- vim helping functions --------------------------------*/ 1095 1096 static void 1097vi_msg(str) 1098 char *str; 1099{ 1100 if (str != NULL && *str != NUL) 1101 MSG((char_u *)str); 1102} 1103 1104 static void 1105vi_error_msg(str) 1106 char *str; 1107{ 1108 if (str != NULL && *str != NUL) 1109 EMSG((char_u *)str); 1110} 1111 1112 static void 1113vi_open_file(fname) 1114 char *fname; 1115{ 1116 ++no_wait_return; 1117 do_ecmd(0, (char_u *)fname, NULL, NULL, ECMD_ONE, ECMD_HIDE+ECMD_OLDBUF, 1118 curwin); 1119 curbuf->b_sniff = TRUE; 1120 --no_wait_return; /* [ex_docmd.c] */ 1121} 1122 1123 static buf_T * 1124vi_find_buffer(fname) 1125 char *fname; 1126{ /* derived from buflist_findname() [buffer.c] */ 1127 buf_T *buf; 1128 1129 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 1130 if (buf->b_sfname != NULL && fnamecmp(fname, buf->b_sfname) == 0) 1131 return (buf); 1132 return NULL; 1133} 1134 1135 1136 static char * 1137vi_symbol_under_cursor() 1138{ 1139 int len; 1140 char *symbolp; 1141 char *p; 1142 static char sniff_symbol[256]; 1143 1144 len = find_ident_under_cursor((char_u **)&symbolp, FIND_IDENT); 1145 /* [normal.c] */ 1146 if (len <= 0) 1147 return NULL; 1148 for (p=sniff_symbol; len; len--) 1149 *p++ = *symbolp++; 1150 *p = '\0'; 1151 return sniff_symbol; 1152} 1153 1154 1155 static char * 1156vi_buffer_name() 1157{ 1158 return (char *)curbuf->b_sfname; 1159} 1160 1161 static void 1162vi_exec_cmd(vicmd) 1163 char *vicmd; 1164{ 1165 do_cmdline_cmd((char_u *)vicmd); /* [ex_docmd.c] */ 1166} 1167 1168/* 1169 * Set cursor on character position 1170 * derived from cursor_pos_info() [buffer.c] 1171 */ 1172 static void 1173vi_set_cursor_pos(char_pos) 1174 long char_pos; 1175{ 1176 linenr_T lnum; 1177 long char_count = 1; /* first position = 1 */ 1178 int line_size; 1179 int eol_size; 1180 1181 if (char_pos == 0) 1182 { 1183 char_pos = 1; 1184 } 1185 if (get_fileformat(curbuf) == EOL_DOS) 1186 eol_size = 2; 1187 else 1188 eol_size = 1; 1189 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) 1190 { 1191 line_size = STRLEN(ml_get(lnum)) + eol_size; 1192 if (char_count+line_size > char_pos) break; 1193 char_count += line_size; 1194 } 1195 curwin->w_cursor.lnum = lnum; 1196 curwin->w_cursor.col = char_pos - char_count; 1197} 1198 1199 static long 1200vi_cursor_pos() 1201{ 1202 linenr_T lnum; 1203 long char_count=1; /* sniff starts with pos 1 */ 1204 int line_size; 1205 int eol_size; 1206 1207 if (curbuf->b_p_tx) 1208 eol_size = 2; 1209 else 1210 eol_size = 1; 1211 for (lnum = 1; lnum < curwin->w_cursor.lnum; ++lnum) 1212 { 1213 line_size = STRLEN(ml_get(lnum)) + eol_size; 1214 char_count += line_size; 1215 } 1216 return char_count + curwin->w_cursor.col; 1217} 1218