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