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