1 /* vi:set ts=8 sts=4 sw=4:
3 * if_sniff.c Interface between Vim and SNiFF+
5 * $Id: if_sniff.c,v 1.6 2008/06/25 19:55:22 vimboss Exp $
7 * See README.txt for an overview of the Vim source code.
20 # include "gui_x11.pro"
22 # include "os_unixx.h"
25 static int sniffemacs_pid
;
28 int sniff_connected
= 0;
29 int sniff_request_waiting
= 0;
30 int want_sniff_request
= 0;
32 #define MAX_REQUEST_LEN 512
35 #define EMPTY_SYMBOL 4
43 #define RQ_CONTEXT NEED_FILE + NEED_SYMBOL
44 #define RQ_SCONTEXT NEED_FILE + NEED_SYMBOL + EMPTY_SYMBOL
45 #define RQ_NOSYMBOL NEED_FILE
46 #define RQ_SILENT RQ_NOSYMBOL + SILENT
47 #define RQ_CONNECT RQ_NONE + CONNECT
48 #define RQ_DISCONNECT RQ_SIMPLE + DISCONNECT
60 struct sn_cmd
* sniff_cmd
;
61 struct sn_cmd_list
* next_cmd
;
64 static struct sn_cmd sniff_cmds
[] =
66 { "toggle", 'e', N_("Toggle implementation/definition"),RQ_SCONTEXT
},
67 { "superclass", 's', N_("Show base class of"), RQ_CONTEXT
},
68 { "overridden", 'm', N_("Show overridden member function"),RQ_SCONTEXT
},
69 { "retrieve-file", 'r', N_("Retrieve from file"), RQ_CONTEXT
},
70 { "retrieve-project",'p', N_("Retrieve from project"), RQ_CONTEXT
},
71 { "retrieve-all-projects",
72 'P', N_("Retrieve from all projects"), RQ_CONTEXT
},
73 { "retrieve-next", 'R', N_("Retrieve"), RQ_CONTEXT
},
74 { "goto-symbol", 'g', N_("Show source of"), RQ_CONTEXT
},
75 { "find-symbol", 'f', N_("Find symbol"), RQ_CONTEXT
},
76 { "browse-class", 'w', N_("Browse class"), RQ_CONTEXT
},
77 { "hierarchy", 't', N_("Show class in hierarchy"), RQ_CONTEXT
},
78 { "restr-hier", 'T', N_("Show class in restricted hierarchy"),RQ_CONTEXT
},
79 { "xref-to", 'x', N_("Xref refers to"), RQ_CONTEXT
},
80 { "xref-by", 'X', N_("Xref referred by"), RQ_CONTEXT
},
81 { "xref-has", 'c', N_("Xref has a"), RQ_CONTEXT
},
82 { "xref-used-by", 'C', N_("Xref used by"), RQ_CONTEXT
},
83 { "show-docu", 'd', N_("Show docu of"), RQ_CONTEXT
},
84 { "gen-docu", 'D', N_("Generate docu for"), RQ_CONTEXT
},
85 { "connect", 'y', NULL
, RQ_CONNECT
},
86 { "disconnect", 'q', NULL
, RQ_DISCONNECT
},
87 { "font-info", 'z', NULL
, RQ_SILENT
},
88 { "update", 'u', NULL
, RQ_SILENT
},
89 { NULL
, '\0', NULL
, 0}
93 static char *SniffEmacs
[2] = {"sniffemacs", (char *)NULL
}; /* Yes, Emacs! */
94 static int fd_to_sniff
;
95 static int sniff_will_disconnect
= 0;
96 static char msg_sniff_disconnect
[] = N_("Cannot connect to SNiFF+. Check environment (sniffemacs must be found in $PATH).\n");
97 static char sniff_rq_sep
[] = " ";
98 static struct sn_cmd_list
*sniff_cmd_ext
= NULL
;
100 /* Initializing vim commands
101 * executed each time vim connects to Sniff
103 static char *init_cmds
[]= {
105 "autocmd BufWritePost * sniff update",
106 "autocmd BufReadPost * sniff font-info",
107 "autocmd VimLeave * sniff disconnect",
110 "let g:sniff_connected = 1",
112 "if ! exists('g:sniff_mappings_sourced')|"
113 "if ! exists('g:sniff_mappings')|"
114 "if exists('$SNIFF_DIR4')|"
115 "let g:sniff_mappings='$SNIFF_DIR4/config/integrations/vim/sniff.vim'|"
117 "let g:sniff_mappings='$SNIFF_DIR/config/sniff.vim'|"
120 "let g:sniff_mappings=expand(g:sniff_mappings)|"
121 "if filereadable(g:sniff_mappings)|"
122 "execute 'source' g:sniff_mappings|"
123 "let g:sniff_mappings_sourced=1|"
130 /*-------- Function Prototypes ----------------------------------*/
132 static int ConnectToSniffEmacs
__ARGS((void));
133 static void sniff_connect
__ARGS((void));
134 static void HandleSniffRequest
__ARGS((char* buffer
));
135 static int get_request
__ARGS((int fd
, char *buf
, int maxlen
));
136 static void WriteToSniff
__ARGS((char *str
));
137 static void SendRequest
__ARGS((struct sn_cmd
*command
, char* symbol
));
138 static void vi_msg
__ARGS((char *));
139 static void vi_error_msg
__ARGS((char *));
140 static char *vi_symbol_under_cursor
__ARGS((void));
141 static void vi_open_file
__ARGS((char *));
142 static char *vi_buffer_name
__ARGS((void));
143 static buf_T
*vi_find_buffer
__ARGS((char *));
144 static void vi_exec_cmd
__ARGS((char *));
145 static void vi_set_cursor_pos
__ARGS((long char_nr
));
146 static long vi_cursor_pos
__ARGS((void));
150 static FILE* _tracefile
= NULL
;
151 #define SNIFF_TRACE_OPEN(file) if (!_tracefile) _tracefile = fopen(file, "w")
152 #define SNIFF_TRACE(msg) fprintf(_tracefile, msg); fflush(_tracefile);
153 #define SNIFF_TRACE1(msg, arg) fprintf(_tracefile, msg,arg); fflush(_tracefile);
154 #define SNIFF_TRACE_CLOSE fclose(_tracefile); _tracefile=NULL;
156 #define SNIFF_TRACE_OPEN(file)
157 #define SNIFF_TRACE(msg)
158 #define SNIFF_TRACE1(msg, arg)
159 #define SNIFF_TRACE_CLOSE
162 /*-------- Windows Only Declarations -----------------------------*/
165 static int sniff_request_processed
=1;
166 static HANDLE sniffemacs_handle
=NULL
;
167 static HANDLE readthread_handle
=NULL
;
168 static HANDLE handle_to_sniff
=NULL
;
169 static HANDLE handle_from_sniff
=NULL
;
173 struct sniffBufNode
*next
;
175 char buf
[MAX_REQUEST_LEN
];
177 static struct sniffBufNode
*sniffBufStart
=NULL
;
178 static struct sniffBufNode
*sniffBufEnd
=NULL
;
179 static HANDLE hBufferMutex
=NULL
;
182 extern HWND s_hwnd
; /* gvim's Window handle */
185 * some helper functions for Windows port only
189 ExecuteDetachedProgram(char *szBinary
, char *szCmdLine
,
190 HANDLE hStdInput
, HANDLE hStdOutput
)
194 PROCESS_INFORMATION aProcessInformation
;
195 PROCESS_INFORMATION
*pProcessInformation
= &aProcessInformation
;
196 STARTUPINFO aStartupInfo
;
197 STARTUPINFO
*pStartupInfo
= &aStartupInfo
;
198 DWORD dwCreationFlags
= 0;
202 hResult
= FindExecutable(szBinary
, ".", szPath
);
203 if ((int)hResult
<= 32)
205 /* can't find the exe file */
209 ZeroMemory(pStartupInfo
, sizeof(*pStartupInfo
));
210 pStartupInfo
->dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
211 pStartupInfo
->hStdInput
= hStdInput
;
212 pStartupInfo
->hStdOutput
= hStdOutput
;
213 pStartupInfo
->wShowWindow
= SW_HIDE
;
214 pStartupInfo
->cb
= sizeof(STARTUPINFO
);
216 bResult
= CreateProcess(
219 NULL
, /* security attr for process */
220 NULL
, /* security attr for primary thread */
221 TRUE
, /* DO inherit stdin and stdout */
222 dwCreationFlags
, /* creation flags */
223 NULL
, /* environment */
224 ".", /* current directory */
225 pStartupInfo
, /* startup info: NULL crashes */
226 pProcessInformation
/* process information: NULL crashes */
228 nError
= GetLastError();
231 CloseHandle(pProcessInformation
->hThread
);
232 CloseHandle(hStdInput
);
233 CloseHandle(hStdOutput
);
234 return(pProcessInformation
->hProcess
);
241 * write to the internal Thread / Thread communications buffer.
242 * Return TRUE if successful, FALSE else.
245 writeToBuffer(char *msg
, int len
)
247 DWORD dwWaitResult
; /* Request ownership of mutex. */
248 struct sniffBufNode
*bn
;
251 SNIFF_TRACE1("writeToBuffer %d\n", len
);
252 bnSize
= sizeof(struct sniffBufNode
) - MAX_REQUEST_LEN
+ len
+ 1;
253 if (bnSize
< 128) bnSize
= 128; /* minimum length to avoid fragmentation */
254 bn
= (struct sniffBufNode
*)malloc(bnSize
);
258 memcpy(bn
->buf
, msg
, len
);
259 bn
->buf
[len
]='\0'; /* terminate CString for added safety */
262 /* now, acquire a Mutex for adding the string to our linked list */
263 dwWaitResult
= WaitForSingleObject(
264 hBufferMutex
, /* handle of mutex */
265 1000L); /* one-second time-out interval */
266 if (dwWaitResult
== WAIT_OBJECT_0
)
268 /* The thread got mutex ownership. */
271 sniffBufEnd
->next
= bn
;
275 sniffBufStart
= sniffBufEnd
= bn
;
276 /* Release ownership of the mutex object. */
277 if (! ReleaseMutex(hBufferMutex
))
279 /* Deal with error. */
284 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
290 * read from the internal Thread / Thread communications buffer.
291 * Return TRUE if successful, FALSE else.
294 ReadFromBuffer(char *buf
, int maxlen
)
296 DWORD dwWaitResult
; /* Request ownership of mutex. */
298 struct sniffBufNode
*bn
;
300 dwWaitResult
= WaitForSingleObject(
301 hBufferMutex
, /* handle of mutex */
302 1000L); /* one-second time-out interval */
303 if (dwWaitResult
== WAIT_OBJECT_0
)
307 /* all pending Requests Processed */
314 SNIFF_TRACE1("ReadFromBuffer %d\n", theLen
);
315 if (theLen
>= maxlen
)
317 /* notify the user of buffer overflow? */
320 memcpy(buf
, bn
->buf
, theLen
);
322 if (! (sniffBufStart
= bn
->next
))
325 sniff_request_processed
= 1;
329 if (! ReleaseMutex(hBufferMutex
))
331 /* Deal with error. */
336 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
340 /* on Win32, a separate Thread reads the input pipe. get_request is not needed here. */
342 SniffEmacsReadThread(void *dummy
)
344 static char ReadThreadBuffer
[MAX_REQUEST_LEN
];
348 char *msgStart
, *msgCur
;
350 SNIFF_TRACE("begin thread\n");
351 /* Read from the pipe to SniffEmacs */
352 while (sniff_connected
)
354 if (!ReadFile(handle_from_sniff
,
355 ReadThreadBuffer
+ ReadThreadLen
, /* acknowledge rest in buffer */
356 MAX_REQUEST_LEN
- ReadThreadLen
,
360 DWORD err
= GetLastError();
366 /* probably sniffemacs died... log the Error? */
371 ReadThreadLen
+= result
-1; /* total length of valid chars */
372 for(msgCur
=msgStart
=ReadThreadBuffer
; ReadThreadLen
> 0; msgCur
++, ReadThreadLen
--)
374 if (*msgCur
== '\0' || *msgCur
== '\r' || *msgCur
== '\n')
376 msgLen
= msgCur
-msgStart
; /* don't add the CR/LF chars */
378 writeToBuffer(msgStart
, msgLen
);
379 msgStart
= msgCur
+ 1; /* over-read single CR/LF chars */
383 /* move incomplete message to beginning of buffer */
384 ReadThreadLen
= msgCur
- msgStart
;
385 if (ReadThreadLen
> 0)
386 mch_memmove(ReadThreadBuffer
, msgStart
, ReadThreadLen
);
388 if (sniff_request_processed
)
390 /* notify others that new data has arrived */
391 sniff_request_processed
= 0;
392 sniff_request_waiting
= 1;
394 PostMessage(s_hwnd
, WM_USER
, (WPARAM
)0, (LPARAM
)0);
399 SNIFF_TRACE("end thread\n");
402 /*-------- End of Windows Only Declarations ------------------------*/
405 /* ProcessSniffRequests
406 * Function that should be called from outside
407 * to process the waiting sniff requests
410 ProcessSniffRequests()
412 static char buf
[MAX_REQUEST_LEN
];
415 while (sniff_connected
)
418 len
= ReadFromBuffer(buf
, sizeof(buf
));
420 len
= get_request(fd_from_sniff
, buf
, sizeof(buf
));
424 vi_error_msg(_("E274: Sniff: Error during read. Disconnected"));
429 HandleSniffRequest( buf
);
434 if (sniff_will_disconnect
) /* Now the last msg has been processed */
438 static struct sn_cmd
*
442 struct sn_cmd
*sniff_cmd
= NULL
;
444 for(i
=0; sniff_cmds
[i
].cmd_name
; i
++)
446 if (!strcmp(cmd
, sniff_cmds
[i
].cmd_name
))
448 sniff_cmd
= &sniff_cmds
[i
];
454 struct sn_cmd_list
*list
= sniff_cmd_ext
;
457 if (!strcmp(cmd
, list
->sniff_cmd
->cmd_name
))
459 sniff_cmd
= list
->sniff_cmd
;
462 list
= list
->next_cmd
;
469 add_sniff_cmd(cmd
, def
, msg
)
475 if (def
!= NULL
&& def
[0] != NUL
&& find_sniff_cmd(cmd
) == NULL
)
477 struct sn_cmd_list
*list
= sniff_cmd_ext
;
478 struct sn_cmd
*sniff_cmd
= (struct sn_cmd
*)malloc(sizeof(struct sn_cmd
));
479 struct sn_cmd_list
*cmd_node
= (struct sn_cmd_list
*)malloc(sizeof(struct sn_cmd_list
));
482 /* unescape message text */
484 char *end
= p
+strlen(msg
);
488 mch_memmove(p
,p
+1,end
-p
);
491 SNIFF_TRACE1("request name = %s\n",cmd
);
492 SNIFF_TRACE1("request def = %s\n",def
);
493 SNIFF_TRACE1("request msg = %s\n",msg
);
495 while(list
&& list
->next_cmd
)
496 list
= list
->next_cmd
;
498 sniff_cmd_ext
= cmd_node
;
500 list
->next_cmd
= cmd_node
;
502 sniff_cmd
->cmd_name
= cmd
;
503 sniff_cmd
->cmd_code
= def
[0];
504 sniff_cmd
->cmd_msg
= msg
;
508 rq_type
= RQ_NOSYMBOL
;
511 rq_type
= RQ_CONTEXT
;
514 rq_type
= RQ_SCONTEXT
;
520 sniff_cmd
->cmd_type
= rq_type
;
521 cmd_node
->sniff_cmd
= sniff_cmd
;
522 cmd_node
->next_cmd
= NULL
;
529 * Handle ":sniff" command
535 char_u
*arg
= eap
->arg
;
536 char_u
*symbol
= NULL
;
539 SNIFF_TRACE_OPEN("if_sniff.log");
540 if (ends_excmd(*arg
)) /* no request: print available commands */
544 msg_outtrans_attr((char_u
*)"-- SNiFF+ commands --", hl_attr(HLF_T
));
545 for(i
=0; sniff_cmds
[i
].cmd_name
; i
++)
548 msg_outtrans((char_u
*)":sniff ");
549 msg_outtrans((char_u
*)sniff_cmds
[i
].cmd_name
);
552 msg_outtrans((char_u
*)_("SNiFF+ is currently "));
553 if (!sniff_connected
)
554 msg_outtrans((char_u
*)_("not "));
555 msg_outtrans((char_u
*)_("connected"));
558 else /* extract command name and symbol if present */
560 symbol
= skiptowhite(arg
);
561 cmd
= vim_strnsave(arg
, (int)(symbol
-arg
));
562 symbol
= skipwhite(symbol
);
563 if (ends_excmd(*symbol
))
565 if (!strcmp((char *)cmd
, "addcmd"))
567 char_u
*def
= skiptowhite(symbol
);
568 char_u
*name
= vim_strnsave(symbol
, (int)(def
-symbol
));
570 def
= skipwhite(def
);
571 msg
= skiptowhite(def
);
572 def
= vim_strnsave(def
, (int)(msg
-def
));
573 msg
= skipwhite(msg
);
574 if (ends_excmd(*msg
))
575 msg
= vim_strsave(name
);
577 msg
= vim_strnsave(msg
, (int)(skiptowhite_esc(msg
)-msg
));
578 if (!add_sniff_cmd((char*)name
, (char*)def
, (char*)msg
))
587 struct sn_cmd
* sniff_cmd
= find_sniff_cmd((char*)cmd
);
589 SendRequest(sniff_cmd
, (char *)symbol
);
591 EMSG2(_("E275: Unknown SNiFF+ request: %s"), cmd
);
603 if (ConnectToSniffEmacs())
604 vi_error_msg(_("E276: Error connecting to SNiFF+"));
609 for (i
= 0; init_cmds
[i
]; i
++)
610 vi_exec_cmd(init_cmds
[i
]);
615 sniff_disconnect(immediately
)
618 if (!sniff_connected
)
622 vi_exec_cmd("augroup sniff");
624 vi_exec_cmd("augroup END");
625 vi_exec_cmd("unlet g:sniff_connected");
627 want_sniff_request
= 0;
628 sniff_will_disconnect
= 0;
631 gui_mch_wait_for_chars(0L);
634 while(sniffBufStart
!= NULL
)
636 struct sniffBufNode
*node
= sniffBufStart
;
637 sniffBufStart
= sniffBufStart
->next
;
640 sniffBufStart
= sniffBufEnd
= NULL
;
641 sniff_request_processed
= 1;
642 CloseHandle(handle_to_sniff
);
643 CloseHandle(handle_from_sniff
);
644 WaitForSingleObject(sniffemacs_handle
, 1000L);
645 CloseHandle(sniffemacs_handle
);
646 sniffemacs_handle
= NULL
;
647 WaitForSingleObject(readthread_handle
, 1000L);
648 readthread_handle
= NULL
;
649 CloseHandle(hBufferMutex
);
654 close(fd_from_sniff
);
662 if (!sniff_request_processed
)
663 ProcessSniffRequests();
665 sleep(2); /* Incoming msg could disturb edit */
667 sniff_will_disconnect
= 1; /* We expect disconnect msg in 2 secs */
672 /* ConnectToSniffEmacs
673 * Connect to Sniff: returns 1 on error
676 ConnectToSniffEmacs()
678 #ifdef WIN32 /* Windows Version of the Code */
679 HANDLE ToSniffEmacs
[2], FromSniffEmacs
[2];
680 SECURITY_ATTRIBUTES sa
;
682 sa
.nLength
= sizeof(sa
);
683 sa
.lpSecurityDescriptor
= NULL
;
684 sa
.bInheritHandle
= TRUE
;
686 if (! CreatePipe(&ToSniffEmacs
[0], &ToSniffEmacs
[1], &sa
, 0))
688 if (! CreatePipe(&FromSniffEmacs
[0], &FromSniffEmacs
[1], &sa
, 0))
691 sniffemacs_handle
= ExecuteDetachedProgram(SniffEmacs
[0], SniffEmacs
[0],
692 ToSniffEmacs
[0], FromSniffEmacs
[1]);
694 if (sniffemacs_handle
)
696 handle_to_sniff
= ToSniffEmacs
[1];
697 handle_from_sniff
= FromSniffEmacs
[0];
699 hBufferMutex
= CreateMutex(
700 NULL
, /* no security attributes */
701 FALSE
, /* initially not owned */
702 "SniffReadBufferMutex"); /* name of mutex */
703 if (hBufferMutex
== NULL
)
705 /* Check for error. */
707 readthread_handle
= (HANDLE
)_beginthread(SniffEmacsReadThread
, 0, NULL
);
712 /* error in spawn() */
716 #else /* UNIX Version of the Code */
717 int ToSniffEmacs
[2], FromSniffEmacs
[2];
720 pipe(FromSniffEmacs
);
723 if ((sniffemacs_pid
=fork()) == 0)
727 /* prepare communication pipes */
728 close(ToSniffEmacs
[1]);
729 close(FromSniffEmacs
[0]);
731 dup2(ToSniffEmacs
[0],fileno(stdin
)); /* write to ToSniffEmacs[1] */
732 dup2(FromSniffEmacs
[1],fileno(stdout
));/* read from FromSniffEmacs[0] */
734 close(ToSniffEmacs
[0]);
735 close(FromSniffEmacs
[1]);
737 /* start sniffemacs */
738 execvp (SniffEmacs
[0], SniffEmacs
);
740 /* FILE *out = fdopen(FromSniffEmacs[1], "w"); */
742 fputs(_(msg_sniff_disconnect
), stdout
);
753 else if (sniffemacs_pid
> 0)
756 close(ToSniffEmacs
[0]);
757 fd_to_sniff
= ToSniffEmacs
[1];
758 close(FromSniffEmacs
[1]);
759 fd_from_sniff
= FromSniffEmacs
[0];
763 else /* error in fork() */
765 #endif /* UNIX Version of the Code */
769 /* HandleSniffRequest
770 * Handle one request from SNiFF+
773 HandleSniffRequest(buffer
)
776 char VICommand
[MAX_REQUEST_LEN
];
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";
791 arguments
= &buffer
[1];
792 token
= strtok(arguments
, sniff_rq_sep
);
797 argv
[argc
] = (char*)vim_strsave((char_u
*)token
);
798 token
= strtok(0, sniff_rq_sep
);
801 argv
[argc
] = strdup("");
807 case 'o' : /* visit file at char pos */
808 case 'O' : /* visit file at line number */
810 char *file
= argv
[0];
811 int position
= atoi(argv
[1]);
813 buf
= vi_find_buffer(file
);
814 setpcmark(); /* insert current pos in jump list [mark.c]*/
817 else if (buf
!=curbuf
)
819 vim_snprintf(VICommand
, sizeof(VICommand
),
820 (char *)SelectBuf
, file
);
821 vi_exec_cmd(VICommand
);
824 vi_set_cursor_pos((long)position
);
827 vim_snprintf(VICommand
, sizeof(VICommand
),
828 (char *)GotoLine
, (int)position
);
829 vi_exec_cmd(VICommand
);
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 */
836 SetForegroundWindow(s_hwnd
);
838 extern Widget vimShell
;
840 XSetInputFocus(gui
.dpy
, XtWindow(vimShell
), RevertToNone
,
842 XRaiseWindow(gui
.dpy
, XtWindow(vimShell
));
848 case 'p' : /* path of file has changed */
849 /* when changing from shared to private WS (checkout) */
851 char *file
= argv
[0];
852 char *new_path
= argv
[1];
854 buf
= vi_find_buffer(file
);
855 if (buf
&& !buf
->b_changed
) /* delete buffer only if not modified */
857 vim_snprintf(VICommand
, sizeof(VICommand
),
858 (char *)DeleteBuf
, file
);
859 vi_exec_cmd(VICommand
);
861 vi_open_file(new_path
);
864 case 'w' : /* writability has changed */
865 /* Sniff sends request twice,
866 * but only the last one is the right one */
868 char *file
= argv
[0];
869 int writable
= atoi(argv
[1]);
871 buf
= vi_find_buffer(file
);
874 buf
->b_p_ro
= !writable
;
877 buf
->b_flags
|= BF_CHECK_RO
+ BF_NEVERLOADED
;
878 if (writable
&& !buf
->b_changed
)
880 vim_snprintf(VICommand
, sizeof(VICommand
),
881 (char *)UnloadBuf
, file
);
882 vi_exec_cmd(VICommand
);
885 else if (writable
&& !buf
->b_changed
)
892 case 'h' : /* highlight info */
893 break; /* not implemented */
895 case 't' : /* Set tab width */
897 int tab_width
= atoi(argv
[1]);
899 if (tab_width
> 0 && tab_width
<= 16)
901 vim_snprintf(VICommand
, sizeof(VICommand
),
902 (char *)SetTab
, tab_width
);
903 vi_exec_cmd(VICommand
);
909 /* change the request separator */
910 sniff_rq_sep
[0] = arguments
[0];
911 /* echo the request */
912 WriteToSniff(buffer
);
915 case 'A' : /* Warning/Info msg */
917 if (!strncmp(arguments
, "Disconnected", 12))
918 sniff_disconnect(1); /* unexpected disconnection */
920 case 'a' : /* Error msg */
921 vi_error_msg(arguments
);
922 if (!strncmp(arguments
, "Cannot connect", 14))
930 vim_free(argv
[--argc
]);
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
942 get_request(fd
, buf
, maxlen
)
947 static char inbuf
[1024];
948 static int pos
= 0, bytes
= 0;
965 for (len
= 0; len
< maxlen
; len
++)
967 if (pos
>= bytes
) /* end of buffer reached? */
970 if (select(fd
+ 1, &rfds
, NULL
, NULL
, &tval
) > 0)
972 if (poll(&fds
, 1, 0) > 0)
976 bytes
= read(fd
, inbuf
, sizeof(inbuf
));
987 if ((buf
[len
] = inbuf
[pos
++]) =='\n')
997 SendRequest(command
, symbol
)
998 struct sn_cmd
*command
;
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
;
1006 if (cmd_type
== RQ_CONNECT
)
1011 if (!sniff_connected
&& !(cmd_type
& SILENT
))
1013 vi_error_msg(_("E278: SNiFF+ not connected"));
1017 if (cmd_type
& NEED_FILE
)
1019 if (!curbuf
->b_sniff
)
1021 if (!(cmd_type
& SILENT
))
1022 vi_error_msg(_("E279: Not a SNiFF+ buffer"));
1025 buffer_name
= vi_buffer_name();
1026 if (buffer_name
== NULL
)
1028 if (cmd_type
& NEED_SYMBOL
)
1030 if (cmd_type
& EMPTY_SYMBOL
)
1032 else if (!symbol
&& !(symbol
= vi_symbol_under_cursor()))
1033 return; /* error msg already displayed */
1037 vim_snprintf(cmdstr
, sizeof(cmdstr
), "%c%s%s%ld%s%s\n",
1046 vim_snprintf(cmdstr
, sizeof(cmdstr
), "%c%s\n",
1047 command
->cmd_code
, buffer_name
);
1049 else /* simple request */
1051 cmdstr
[0] = command
->cmd_code
;
1055 if (command
->cmd_msg
&& !(cmd_type
& SILENT
))
1057 if ((cmd_type
& NEED_SYMBOL
) && !(cmd_type
& EMPTY_SYMBOL
))
1059 vim_snprintf(msgtxt
, sizeof(msgtxt
), "%s: %s",
1060 _(command
->cmd_msg
), symbol
);
1064 vi_msg(_(command
->cmd_msg
));
1066 WriteToSniff(cmdstr
);
1067 if (cmd_type
& DISCONNECT
)
1068 sniff_disconnect(0);
1079 if (! WriteFile(handle_to_sniff
, str
, strlen(str
), &bytes
, NULL
))
1081 DWORD err
=GetLastError();
1085 bytes
= write(fd_to_sniff
, str
, strlen(str
));
1089 vi_msg(_("Sniff: Error during write. Disconnected"));
1090 sniff_disconnect(1);
1094 /*-------- vim helping functions --------------------------------*/
1100 if (str
!= NULL
&& *str
!= NUL
)
1108 if (str
!= NULL
&& *str
!= NUL
)
1109 EMSG((char_u
*)str
);
1117 do_ecmd(0, (char_u
*)fname
, NULL
, NULL
, ECMD_ONE
, ECMD_HIDE
+ECMD_OLDBUF
);
1118 curbuf
->b_sniff
= TRUE
;
1119 --no_wait_return
; /* [ex_docmd.c] */
1123 vi_find_buffer(fname
)
1125 { /* derived from buflist_findname() [buffer.c] */
1128 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
1129 if (buf
->b_sfname
!= NULL
&& fnamecmp(fname
, buf
->b_sfname
) == 0)
1136 vi_symbol_under_cursor()
1141 static char sniff_symbol
[256];
1143 len
= find_ident_under_cursor((char_u
**)&symbolp
, FIND_IDENT
);
1147 for (p
=sniff_symbol
; len
; len
--)
1150 return sniff_symbol
;
1157 return (char *)curbuf
->b_sfname
;
1164 do_cmdline_cmd((char_u
*)vicmd
); /* [ex_docmd.c] */
1168 * Set cursor on character position
1169 * derived from cursor_pos_info() [buffer.c]
1172 vi_set_cursor_pos(char_pos
)
1176 long char_count
= 1; /* first position = 1 */
1184 if (get_fileformat(curbuf
) == EOL_DOS
)
1188 for (lnum
= 1; lnum
<= curbuf
->b_ml
.ml_line_count
; ++lnum
)
1190 line_size
= STRLEN(ml_get(lnum
)) + eol_size
;
1191 if (char_count
+line_size
> char_pos
) break;
1192 char_count
+= line_size
;
1194 curwin
->w_cursor
.lnum
= lnum
;
1195 curwin
->w_cursor
.col
= char_pos
- char_count
;
1202 long char_count
=1; /* sniff starts with pos 1 */
1210 for (lnum
= 1; lnum
< curwin
->w_cursor
.lnum
; ++lnum
)
1212 line_size
= STRLEN(ml_get(lnum
)) + eol_size
;
1213 char_count
+= line_size
;
1215 return char_count
+ curwin
->w_cursor
.col
;