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.4 2006/03/06 23:13:51 vimboss Exp $
7 * See README.txt for an overview of the Vim source code.
21 # include "gui_x11.pro"
23 # include "os_unixx.h"
26 static int sniffemacs_pid
;
29 int sniff_connected
= 0;
30 int sniff_request_waiting
= 0;
31 int want_sniff_request
= 0;
33 #define MAX_REQUEST_LEN 512
36 #define EMPTY_SYMBOL 4
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
61 struct sn_cmd
* sniff_cmd
;
62 struct sn_cmd_list
* next_cmd
;
65 static struct sn_cmd sniff_cmds
[] =
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}
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
;
101 /* Initializing vim commands
102 * executed each time vim connects to Sniff
104 static char *init_cmds
[]= {
106 "autocmd BufWritePost * sniff update",
107 "autocmd BufReadPost * sniff font-info",
108 "autocmd VimLeave * sniff disconnect",
111 "let g:sniff_connected = 1",
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'|"
118 "let g:sniff_mappings='$SNIFF_DIR/config/sniff.vim'|"
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|"
131 /*-------- Function Prototypes ----------------------------------*/
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));
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;
157 #define SNIFF_TRACE_OPEN(file)
158 #define SNIFF_TRACE(msg)
159 #define SNIFF_TRACE1(msg, arg)
160 #define SNIFF_TRACE_CLOSE
163 /*-------- Windows Only Declarations -----------------------------*/
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
;
174 struct sniffBufNode
*next
;
176 char buf
[MAX_REQUEST_LEN
];
178 static struct sniffBufNode
*sniffBufStart
=NULL
;
179 static struct sniffBufNode
*sniffBufEnd
=NULL
;
180 static HANDLE hBufferMutex
=NULL
;
183 extern HWND s_hwnd
; /* gvim's Window handle */
186 * some helper functions for Windows port only
190 ExecuteDetachedProgram(char *szBinary
, char *szCmdLine
,
191 HANDLE hStdInput
, HANDLE hStdOutput
)
195 PROCESS_INFORMATION aProcessInformation
;
196 PROCESS_INFORMATION
*pProcessInformation
= &aProcessInformation
;
197 STARTUPINFO aStartupInfo
;
198 STARTUPINFO
*pStartupInfo
= &aStartupInfo
;
199 DWORD dwCreationFlags
= 0;
203 hResult
= FindExecutable(szBinary
, ".", szPath
);
204 if ((int)hResult
<= 32)
206 /* can't find the exe file */
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
);
217 bResult
= CreateProcess(
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 */
229 nError
= GetLastError();
232 CloseHandle(pProcessInformation
->hThread
);
233 CloseHandle(hStdInput
);
234 CloseHandle(hStdOutput
);
235 return(pProcessInformation
->hProcess
);
242 * write to the internal Thread / Thread communications buffer.
243 * Return TRUE if successful, FALSE else.
246 writeToBuffer(char *msg
, int len
)
248 DWORD dwWaitResult
; /* Request ownership of mutex. */
249 struct sniffBufNode
*bn
;
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
);
259 memcpy(bn
->buf
, msg
, len
);
260 bn
->buf
[len
]='\0'; /* terminate CString for added safety */
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
)
269 /* The thread got mutex ownership. */
272 sniffBufEnd
->next
= bn
;
276 sniffBufStart
= sniffBufEnd
= bn
;
277 /* Release ownership of the mutex object. */
278 if (! ReleaseMutex(hBufferMutex
))
280 /* Deal with error. */
285 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
291 * read from the internal Thread / Thread communications buffer.
292 * Return TRUE if successful, FALSE else.
295 ReadFromBuffer(char *buf
, int maxlen
)
297 DWORD dwWaitResult
; /* Request ownership of mutex. */
299 struct sniffBufNode
*bn
;
301 dwWaitResult
= WaitForSingleObject(
302 hBufferMutex
, /* handle of mutex */
303 1000L); /* one-second time-out interval */
304 if (dwWaitResult
== WAIT_OBJECT_0
)
308 /* all pending Requests Processed */
315 SNIFF_TRACE1("ReadFromBuffer %d\n", theLen
);
316 if (theLen
>= maxlen
)
318 /* notify the user of buffer overflow? */
321 memcpy(buf
, bn
->buf
, theLen
);
323 if (! (sniffBufStart
= bn
->next
))
326 sniff_request_processed
= 1;
330 if (! ReleaseMutex(hBufferMutex
))
332 /* Deal with error. */
337 /* Cannot get mutex ownership due to time-out or mutex object abandoned. */
341 /* on Win32, a separate Thread reads the input pipe. get_request is not needed here. */
343 SniffEmacsReadThread(void *dummy
)
345 static char ReadThreadBuffer
[MAX_REQUEST_LEN
];
349 char *msgStart
, *msgCur
;
351 SNIFF_TRACE("begin thread\n");
352 /* Read from the pipe to SniffEmacs */
353 while (sniff_connected
)
355 if (!ReadFile(handle_from_sniff
,
356 ReadThreadBuffer
+ ReadThreadLen
, /* acknowledge rest in buffer */
357 MAX_REQUEST_LEN
- ReadThreadLen
,
361 DWORD err
= GetLastError();
367 /* probably sniffemacs died... log the Error? */
372 ReadThreadLen
+= result
-1; /* total length of valid chars */
373 for(msgCur
=msgStart
=ReadThreadBuffer
; ReadThreadLen
> 0; msgCur
++, ReadThreadLen
--)
375 if (*msgCur
== '\0' || *msgCur
== '\r' || *msgCur
== '\n')
377 msgLen
= msgCur
-msgStart
; /* don't add the CR/LF chars */
379 writeToBuffer(msgStart
, msgLen
);
380 msgStart
= msgCur
+ 1; /* over-read single CR/LF chars */
384 /* move incomplete message to beginning of buffer */
385 ReadThreadLen
= msgCur
- msgStart
;
386 if (ReadThreadLen
> 0)
387 mch_memmove(ReadThreadBuffer
, msgStart
, ReadThreadLen
);
389 if (sniff_request_processed
)
391 /* notify others that new data has arrived */
392 sniff_request_processed
= 0;
393 sniff_request_waiting
= 1;
395 PostMessage(s_hwnd
, WM_USER
, (WPARAM
)0, (LPARAM
)0);
400 SNIFF_TRACE("end thread\n");
403 /*-------- End of Windows Only Declarations ------------------------*/
406 /* ProcessSniffRequests
407 * Function that should be called from outside
408 * to process the waiting sniff requests
411 ProcessSniffRequests()
413 static char buf
[MAX_REQUEST_LEN
];
416 while (sniff_connected
)
419 len
= ReadFromBuffer(buf
, sizeof(buf
));
421 len
= get_request(fd_from_sniff
, buf
, sizeof(buf
));
425 vi_error_msg(_("E274: Sniff: Error during read. Disconnected"));
430 HandleSniffRequest( buf
);
435 if (sniff_will_disconnect
) /* Now the last msg has been processed */
439 static struct sn_cmd
*
443 struct sn_cmd
*sniff_cmd
= NULL
;
445 for(i
=0; sniff_cmds
[i
].cmd_name
; i
++)
447 if (!strcmp(cmd
, sniff_cmds
[i
].cmd_name
))
449 sniff_cmd
= &sniff_cmds
[i
];
455 struct sn_cmd_list
*list
= sniff_cmd_ext
;
458 if (!strcmp(cmd
, list
->sniff_cmd
->cmd_name
))
460 sniff_cmd
= list
->sniff_cmd
;
463 list
= list
->next_cmd
;
470 add_sniff_cmd(cmd
, def
, msg
)
476 if (def
!= NULL
&& def
[0] != NUL
&& find_sniff_cmd(cmd
) == NULL
)
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
));
483 /* unescape message text */
485 char *end
= p
+strlen(msg
);
489 mch_memmove(p
,p
+1,end
-p
);
492 SNIFF_TRACE1("request name = %s\n",cmd
);
493 SNIFF_TRACE1("request def = %s\n",def
);
494 SNIFF_TRACE1("request msg = %s\n",msg
);
496 while(list
&& list
->next_cmd
)
497 list
= list
->next_cmd
;
499 sniff_cmd_ext
= cmd_node
;
501 list
->next_cmd
= cmd_node
;
503 sniff_cmd
->cmd_name
= cmd
;
504 sniff_cmd
->cmd_code
= def
[0];
505 sniff_cmd
->cmd_msg
= msg
;
509 rq_type
= RQ_NOSYMBOL
;
512 rq_type
= RQ_CONTEXT
;
515 rq_type
= RQ_SCONTEXT
;
521 sniff_cmd
->cmd_type
= rq_type
;
522 cmd_node
->sniff_cmd
= sniff_cmd
;
523 cmd_node
->next_cmd
= NULL
;
530 * Handle ":sniff" command
536 char_u
*arg
= eap
->arg
;
537 char_u
*symbol
= NULL
;
540 SNIFF_TRACE_OPEN("if_sniff.log");
541 if (ends_excmd(*arg
)) /* no request: print available commands */
545 msg_outtrans_attr((char_u
*)"-- SNiFF+ commands --", hl_attr(HLF_T
));
546 for(i
=0; sniff_cmds
[i
].cmd_name
; i
++)
549 msg_outtrans((char_u
*)":sniff ");
550 msg_outtrans((char_u
*)sniff_cmds
[i
].cmd_name
);
553 msg_outtrans((char_u
*)_("SNiFF+ is currently "));
554 if (!sniff_connected
)
555 msg_outtrans((char_u
*)_("not "));
556 msg_outtrans((char_u
*)_("connected"));
559 else /* extract command name and symbol if present */
561 symbol
= skiptowhite(arg
);
562 cmd
= vim_strnsave(arg
, (int)(symbol
-arg
));
563 symbol
= skipwhite(symbol
);
564 if (ends_excmd(*symbol
))
566 if (!strcmp((char *)cmd
, "addcmd"))
568 char_u
*def
= skiptowhite(symbol
);
569 char_u
*name
= vim_strnsave(symbol
, (int)(def
-symbol
));
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
);
578 msg
= vim_strnsave(msg
, (int)(skiptowhite_esc(msg
)-msg
));
579 if (!add_sniff_cmd((char*)name
, (char*)def
, (char*)msg
))
588 struct sn_cmd
* sniff_cmd
= find_sniff_cmd((char*)cmd
);
590 SendRequest(sniff_cmd
, (char *)symbol
);
592 EMSG2(_("E275: Unknown SNiFF+ request: %s"), cmd
);
604 if (ConnectToSniffEmacs())
605 vi_error_msg(_("E276: Error connecting to SNiFF+"));
610 for (i
= 0; init_cmds
[i
]; i
++)
611 vi_exec_cmd(init_cmds
[i
]);
616 sniff_disconnect(immediately
)
619 if (!sniff_connected
)
623 vi_exec_cmd("augroup sniff");
625 vi_exec_cmd("augroup END");
626 vi_exec_cmd("unlet g:sniff_connected");
628 want_sniff_request
= 0;
629 sniff_will_disconnect
= 0;
632 gui_mch_wait_for_chars(0L);
635 while(sniffBufStart
!= NULL
)
637 struct sniffBufNode
*node
= sniffBufStart
;
638 sniffBufStart
= sniffBufStart
->next
;
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
);
655 close(fd_from_sniff
);
663 if (!sniff_request_processed
)
664 ProcessSniffRequests();
666 sleep(2); /* Incoming msg could disturb edit */
668 sniff_will_disconnect
= 1; /* We expect disconnect msg in 2 secs */
673 /* ConnectToSniffEmacs
674 * Connect to Sniff: returns 1 on error
677 ConnectToSniffEmacs()
679 #ifdef WIN32 /* Windows Version of the Code */
680 HANDLE ToSniffEmacs
[2], FromSniffEmacs
[2];
681 SECURITY_ATTRIBUTES sa
;
683 sa
.nLength
= sizeof(sa
);
684 sa
.lpSecurityDescriptor
= NULL
;
685 sa
.bInheritHandle
= TRUE
;
687 if (! CreatePipe(&ToSniffEmacs
[0], &ToSniffEmacs
[1], &sa
, 0))
689 if (! CreatePipe(&FromSniffEmacs
[0], &FromSniffEmacs
[1], &sa
, 0))
692 sniffemacs_handle
= ExecuteDetachedProgram(SniffEmacs
[0], SniffEmacs
[0],
693 ToSniffEmacs
[0], FromSniffEmacs
[1]);
695 if (sniffemacs_handle
)
697 handle_to_sniff
= ToSniffEmacs
[1];
698 handle_from_sniff
= FromSniffEmacs
[0];
700 hBufferMutex
= CreateMutex(
701 NULL
, /* no security attributes */
702 FALSE
, /* initially not owned */
703 "SniffReadBufferMutex"); /* name of mutex */
704 if (hBufferMutex
== NULL
)
706 /* Check for error. */
708 readthread_handle
= (HANDLE
)_beginthread(SniffEmacsReadThread
, 0, NULL
);
713 /* error in spawn() */
717 #else /* UNIX Version of the Code */
718 int ToSniffEmacs
[2], FromSniffEmacs
[2];
721 pipe(FromSniffEmacs
);
724 if ((sniffemacs_pid
=fork()) == 0)
728 /* prepare communication pipes */
729 close(ToSniffEmacs
[1]);
730 close(FromSniffEmacs
[0]);
732 dup2(ToSniffEmacs
[0],fileno(stdin
)); /* write to ToSniffEmacs[1] */
733 dup2(FromSniffEmacs
[1],fileno(stdout
));/* read from FromSniffEmacs[0] */
735 close(ToSniffEmacs
[0]);
736 close(FromSniffEmacs
[1]);
738 /* start sniffemacs */
739 execvp (SniffEmacs
[0], SniffEmacs
);
741 /* FILE *out = fdopen(FromSniffEmacs[1], "w"); */
743 fputs(_(msg_sniff_disconnect
), stdout
);
754 else if (sniffemacs_pid
> 0)
757 close(ToSniffEmacs
[0]);
758 fd_to_sniff
= ToSniffEmacs
[1];
759 close(FromSniffEmacs
[1]);
760 fd_from_sniff
= FromSniffEmacs
[0];
764 else /* error in fork() */
766 #endif /* UNIX Version of the Code */
770 /* HandleSniffRequest
771 * Handle one request from SNiFF+
774 HandleSniffRequest(buffer
)
777 char VICommand
[MAX_REQUEST_LEN
];
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";
792 arguments
= &buffer
[1];
793 token
= strtok(arguments
, sniff_rq_sep
);
798 argv
[argc
] = (char*)vim_strsave((char_u
*)token
);
799 token
= strtok(0, sniff_rq_sep
);
802 argv
[argc
] = strdup("");
808 case 'o' : /* visit file at char pos */
809 case 'O' : /* visit file at line number */
811 char *file
= argv
[0];
812 int position
= atoi(argv
[1]);
814 buf
= vi_find_buffer(file
);
815 setpcmark(); /* insert current pos in jump list [mark.c]*/
818 else if (buf
!=curbuf
)
820 vim_snprintf(VICommand
, sizeof(VICommand
),
821 (char *)SelectBuf
, file
);
822 vi_exec_cmd(VICommand
);
825 vi_set_cursor_pos((long)position
);
828 vim_snprintf(VICommand
, sizeof(VICommand
),
829 (char *)GotoLine
, (int)position
);
830 vi_exec_cmd(VICommand
);
832 checkpcmark(); /* [mark.c] */
833 #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32)
834 if (gui
.in_use
&& !gui
.in_focus
) /* Raise Vim Window */
837 SetForegroundWindow(s_hwnd
);
839 extern Widget vimShell
;
841 XSetInputFocus(gui
.dpy
, XtWindow(vimShell
), RevertToNone
,
843 XRaiseWindow(gui
.dpy
, XtWindow(vimShell
));
849 case 'p' : /* path of file has changed */
850 /* when changing from shared to private WS (checkout) */
852 char *file
= argv
[0];
853 char *new_path
= argv
[1];
855 buf
= vi_find_buffer(file
);
856 if (buf
&& !buf
->b_changed
) /* delete buffer only if not modified */
858 vim_snprintf(VICommand
, sizeof(VICommand
),
859 (char *)DeleteBuf
, file
);
860 vi_exec_cmd(VICommand
);
862 vi_open_file(new_path
);
865 case 'w' : /* writability has changed */
866 /* Sniff sends request twice,
867 * but only the last one is the right one */
869 char *file
= argv
[0];
870 int writable
= atoi(argv
[1]);
872 buf
= vi_find_buffer(file
);
875 buf
->b_p_ro
= !writable
;
878 buf
->b_flags
|= BF_CHECK_RO
+ BF_NEVERLOADED
;
879 if (writable
&& !buf
->b_changed
)
881 vim_snprintf(VICommand
, sizeof(VICommand
),
882 (char *)UnloadBuf
, file
);
883 vi_exec_cmd(VICommand
);
886 else if (writable
&& !buf
->b_changed
)
893 case 'h' : /* highlight info */
894 break; /* not implemented */
896 case 't' : /* Set tab width */
898 int tab_width
= atoi(argv
[1]);
900 if (tab_width
> 0 && tab_width
<= 16)
902 vim_snprintf(VICommand
, sizeof(VICommand
),
903 (char *)SetTab
, tab_width
);
904 vi_exec_cmd(VICommand
);
910 /* change the request separator */
911 sniff_rq_sep
[0] = arguments
[0];
912 /* echo the request */
913 WriteToSniff(buffer
);
916 case 'A' : /* Warning/Info msg */
918 if (!strncmp(arguments
, "Disconnected", 12))
919 sniff_disconnect(1); /* unexpected disconnection */
921 case 'a' : /* Error msg */
922 vi_error_msg(arguments
);
923 if (!strncmp(arguments
, "Cannot connect", 14))
931 vim_free(argv
[--argc
]);
937 * read string from fd up to next newline (excluding the nl),
938 * returns length of string
939 * 0 if no data available or no complete line
943 get_request(fd
, buf
, maxlen
)
948 static char inbuf
[1024];
949 static int pos
= 0, bytes
= 0;
966 for (len
= 0; len
< maxlen
; len
++)
968 if (pos
>= bytes
) /* end of buffer reached? */
971 if (select(fd
+ 1, &rfds
, NULL
, NULL
, &tval
) > 0)
973 if (poll(&fds
, 1, 0) > 0)
977 bytes
= read(fd
, inbuf
, sizeof(inbuf
));
988 if ((buf
[len
] = inbuf
[pos
++]) =='\n')
998 SendRequest(command
, symbol
)
999 struct sn_cmd
*command
;
1002 int cmd_type
= command
->cmd_type
;
1003 static char cmdstr
[MAX_REQUEST_LEN
];
1004 static char msgtxt
[MAX_REQUEST_LEN
];
1005 char *buffer_name
= NULL
;
1007 if (cmd_type
== RQ_CONNECT
)
1012 if (!sniff_connected
&& !(cmd_type
& SILENT
))
1014 vi_error_msg(_("E278: SNiFF+ not connected"));
1018 if (cmd_type
& NEED_FILE
)
1020 if (!curbuf
->b_sniff
)
1022 if (!(cmd_type
& SILENT
))
1023 vi_error_msg(_("E279: Not a SNiFF+ buffer"));
1026 buffer_name
= vi_buffer_name();
1027 if (buffer_name
== NULL
)
1029 if (cmd_type
& NEED_SYMBOL
)
1031 if (cmd_type
& EMPTY_SYMBOL
)
1033 else if (!symbol
&& !(symbol
= vi_symbol_under_cursor()))
1034 return; /* error msg already displayed */
1038 vim_snprintf(cmdstr
, sizeof(cmdstr
), "%c%s%s%ld%s%s\n",
1047 vim_snprintf(cmdstr
, sizeof(cmdstr
), "%c%s\n",
1048 command
->cmd_code
, buffer_name
);
1050 else /* simple request */
1052 cmdstr
[0] = command
->cmd_code
;
1056 if (command
->cmd_msg
&& !(cmd_type
& SILENT
))
1058 if ((cmd_type
& NEED_SYMBOL
) && !(cmd_type
& EMPTY_SYMBOL
))
1060 vim_snprintf(msgtxt
, sizeof(msgtxt
), "%s: %s",
1061 _(command
->cmd_msg
), symbol
);
1065 vi_msg(_(command
->cmd_msg
));
1067 WriteToSniff(cmdstr
);
1068 if (cmd_type
& DISCONNECT
)
1069 sniff_disconnect(0);
1080 if (! WriteFile(handle_to_sniff
, str
, strlen(str
), &bytes
, NULL
))
1082 DWORD err
=GetLastError();
1086 bytes
= write(fd_to_sniff
, str
, strlen(str
));
1090 vi_msg(_("Sniff: Error during write. Disconnected"));
1091 sniff_disconnect(1);
1095 /*-------- vim helping functions --------------------------------*/
1101 if (str
!= NULL
&& *str
!= NUL
)
1109 if (str
!= NULL
&& *str
!= NUL
)
1110 EMSG((char_u
*)str
);
1118 do_ecmd(0, (char_u
*)fname
, NULL
, NULL
, ECMD_ONE
, ECMD_HIDE
+ECMD_OLDBUF
);
1119 curbuf
->b_sniff
= TRUE
;
1120 --no_wait_return
; /* [ex_docmd.c] */
1124 vi_find_buffer(fname
)
1126 { /* derived from buflist_findname() [buffer.c] */
1129 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
1130 if (buf
->b_sfname
!= NULL
&& fnamecmp(fname
, buf
->b_sfname
) == 0)
1137 vi_symbol_under_cursor()
1142 static char sniff_symbol
[256];
1144 len
= find_ident_under_cursor((char_u
**)&symbolp
, FIND_IDENT
);
1148 for (p
=sniff_symbol
; len
; len
--)
1151 return sniff_symbol
;
1158 return (char *)curbuf
->b_sfname
;
1165 do_cmdline_cmd((char_u
*)vicmd
); /* [ex_docmd.c] */
1169 * Set cursor on character position
1170 * derived from cursor_pos_info() [buffer.c]
1173 vi_set_cursor_pos(char_pos
)
1177 long char_count
= 1; /* first position = 1 */
1185 if (get_fileformat(curbuf
) == EOL_DOS
)
1189 for (lnum
= 1; lnum
<= curbuf
->b_ml
.ml_line_count
; ++lnum
)
1191 line_size
= STRLEN(ml_get(lnum
)) + eol_size
;
1192 if (char_count
+line_size
> char_pos
) break;
1193 char_count
+= line_size
;
1195 curwin
->w_cursor
.lnum
= lnum
;
1196 curwin
->w_cursor
.col
= char_pos
- char_count
;
1203 long char_count
=1; /* sniff starts with pos 1 */
1211 for (lnum
= 1; lnum
< curwin
->w_cursor
.lnum
; ++lnum
)
1213 line_size
= STRLEN(ml_get(lnum
)) + eol_size
;
1214 char_count
+= line_size
;
1216 return char_count
+ curwin
->w_cursor
.col
;