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