Mercurial > vim
annotate src/if_sniff.c @ 6044:b43ce6bb5d79
Added tag v7-4-361 for changeset a97e5b9dbc26
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 09 Jul 2014 19:58:24 +0200 |
parents | ee138f29259e |
children | 2ebc20378f68 |
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 | |
658 _sleep(2); | |
659 if (!sniff_request_processed) | |
660 ProcessSniffRequests(); | |
661 #else | |
662 sleep(2); /* Incoming msg could disturb edit */ | |
663 #endif | |
664 sniff_will_disconnect = 1; /* We expect disconnect msg in 2 secs */ | |
665 } | |
666 } | |
667 | |
668 | |
669 /* ConnectToSniffEmacs | |
670 * Connect to Sniff: returns 1 on error | |
671 */ | |
672 static int | |
673 ConnectToSniffEmacs() | |
674 { | |
675 #ifdef WIN32 /* Windows Version of the Code */ | |
676 HANDLE ToSniffEmacs[2], FromSniffEmacs[2]; | |
677 SECURITY_ATTRIBUTES sa; | |
678 | |
679 sa.nLength = sizeof(sa); | |
680 sa.lpSecurityDescriptor = NULL; | |
681 sa.bInheritHandle = TRUE; | |
682 | |
683 if (! CreatePipe(&ToSniffEmacs[0], &ToSniffEmacs[1], &sa, 0)) | |
684 return 1; | |
685 if (! CreatePipe(&FromSniffEmacs[0], &FromSniffEmacs[1], &sa, 0)) | |
686 return 1; | |
687 | |
688 sniffemacs_handle = ExecuteDetachedProgram(SniffEmacs[0], SniffEmacs[0], | |
689 ToSniffEmacs[0], FromSniffEmacs[1]); | |
690 | |
691 if (sniffemacs_handle) | |
692 { | |
693 handle_to_sniff = ToSniffEmacs[1]; | |
694 handle_from_sniff = FromSniffEmacs[0]; | |
695 sniff_connected = 1; | |
696 hBufferMutex = CreateMutex( | |
697 NULL, /* no security attributes */ | |
698 FALSE, /* initially not owned */ | |
699 "SniffReadBufferMutex"); /* name of mutex */ | |
700 if (hBufferMutex == NULL) | |
701 { | |
702 /* Check for error. */ | |
703 } | |
704 readthread_handle = (HANDLE)_beginthread(SniffEmacsReadThread, 0, NULL); | |
705 return 0; | |
706 } | |
707 else | |
708 { | |
709 /* error in spawn() */ | |
710 return 1; | |
711 } | |
712 | |
713 #else /* UNIX Version of the Code */ | |
714 int ToSniffEmacs[2], FromSniffEmacs[2]; | |
715 | |
1774 | 716 if (pipe(ToSniffEmacs) != 0) |
717 return 1; | |
718 if (pipe(FromSniffEmacs) != 0) | |
719 return 1; | |
7 | 720 |
721 /* fork */ | |
722 if ((sniffemacs_pid=fork()) == 0) | |
723 { | |
724 /* child */ | |
725 | |
726 /* prepare communication pipes */ | |
727 close(ToSniffEmacs[1]); | |
728 close(FromSniffEmacs[0]); | |
729 | |
730 dup2(ToSniffEmacs[0],fileno(stdin)); /* write to ToSniffEmacs[1] */ | |
731 dup2(FromSniffEmacs[1],fileno(stdout));/* read from FromSniffEmacs[0] */ | |
732 | |
733 close(ToSniffEmacs[0]); | |
734 close(FromSniffEmacs[1]); | |
735 | |
736 /* start sniffemacs */ | |
737 execvp (SniffEmacs[0], SniffEmacs); | |
738 { | |
739 /* FILE *out = fdopen(FromSniffEmacs[1], "w"); */ | |
740 sleep(1); | |
741 fputs(_(msg_sniff_disconnect), stdout); | |
742 fflush(stdout); | |
743 sleep(3); | |
744 #ifdef FEAT_GUI | |
745 if (gui.in_use) | |
746 gui_exit(1); | |
747 #endif | |
748 exit(1); | |
749 } | |
750 return 1; | |
751 } | |
752 else if (sniffemacs_pid > 0) | |
753 { | |
754 /* parent process */ | |
755 close(ToSniffEmacs[0]); | |
756 fd_to_sniff = ToSniffEmacs[1]; | |
757 close(FromSniffEmacs[1]); | |
758 fd_from_sniff = FromSniffEmacs[0]; | |
759 sniff_connected = 1; | |
760 return 0; | |
761 } | |
762 else /* error in fork() */ | |
763 return 1; | |
764 #endif /* UNIX Version of the Code */ | |
765 } | |
766 | |
767 | |
768 /* HandleSniffRequest | |
769 * Handle one request from SNiFF+ | |
770 */ | |
771 static void | |
772 HandleSniffRequest(buffer) | |
773 char *buffer; | |
774 { | |
775 char VICommand[MAX_REQUEST_LEN]; | |
776 char command; | |
777 char *arguments; | |
778 char *token; | |
779 char *argv[3]; | |
780 int argc = 0; | |
781 buf_T *buf; | |
782 | |
783 const char *SetTab = "set tabstop=%d"; | |
784 const char *SelectBuf = "buf %s"; | |
785 const char *DeleteBuf = "bd %s"; | |
786 const char *UnloadBuf = "bun %s"; | |
787 const char *GotoLine = "%d"; | |
788 | |
789 command = buffer[0]; | |
790 arguments = &buffer[1]; | |
791 token = strtok(arguments, sniff_rq_sep); | |
3935 | 792 while (argc <3) |
7 | 793 { |
794 if (token) | |
795 { | |
796 argv[argc] = (char*)vim_strsave((char_u *)token); | |
797 token = strtok(0, sniff_rq_sep); | |
798 } | |
799 else | |
800 argv[argc] = strdup(""); | |
801 argc++; | |
802 } | |
803 | |
804 switch (command) | |
805 { | |
806 case 'o' : /* visit file at char pos */ | |
807 case 'O' : /* visit file at line number */ | |
808 { | |
809 char *file = argv[0]; | |
810 int position = atoi(argv[1]); | |
811 | |
812 buf = vi_find_buffer(file); | |
813 setpcmark(); /* insert current pos in jump list [mark.c]*/ | |
814 if (!buf) | |
815 vi_open_file(file); | |
816 else if (buf!=curbuf) | |
817 { | |
426 | 818 vim_snprintf(VICommand, sizeof(VICommand), |
819 (char *)SelectBuf, file); | |
7 | 820 vi_exec_cmd(VICommand); |
821 } | |
822 if (command == 'o') | |
823 vi_set_cursor_pos((long)position); | |
824 else | |
825 { | |
426 | 826 vim_snprintf(VICommand, sizeof(VICommand), |
827 (char *)GotoLine, (int)position); | |
7 | 828 vi_exec_cmd(VICommand); |
829 } | |
830 checkpcmark(); /* [mark.c] */ | |
831 #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32) | |
832 if (gui.in_use && !gui.in_focus) /* Raise Vim Window */ | |
833 { | |
834 # ifdef FEAT_GUI_W32 | |
835 SetForegroundWindow(s_hwnd); | |
836 # else | |
837 extern Widget vimShell; | |
838 | |
839 XSetInputFocus(gui.dpy, XtWindow(vimShell), RevertToNone, | |
840 CurrentTime); | |
841 XRaiseWindow(gui.dpy, XtWindow(vimShell)); | |
842 # endif | |
843 } | |
844 #endif | |
845 break; | |
846 } | |
847 case 'p' : /* path of file has changed */ | |
848 /* when changing from shared to private WS (checkout) */ | |
849 { | |
850 char *file = argv[0]; | |
851 char *new_path = argv[1]; | |
852 | |
853 buf = vi_find_buffer(file); | |
854 if (buf && !buf->b_changed) /* delete buffer only if not modified */ | |
855 { | |
426 | 856 vim_snprintf(VICommand, sizeof(VICommand), |
857 (char *)DeleteBuf, file); | |
7 | 858 vi_exec_cmd(VICommand); |
859 } | |
860 vi_open_file(new_path); | |
861 break; | |
862 } | |
863 case 'w' : /* writability has changed */ | |
864 /* Sniff sends request twice, | |
865 * but only the last one is the right one */ | |
866 { | |
867 char *file = argv[0]; | |
868 int writable = atoi(argv[1]); | |
869 | |
870 buf = vi_find_buffer(file); | |
871 if (buf) | |
872 { | |
873 buf->b_p_ro = !writable; | |
874 if (buf != curbuf) | |
875 { | |
876 buf->b_flags |= BF_CHECK_RO + BF_NEVERLOADED; | |
877 if (writable && !buf->b_changed) | |
878 { | |
426 | 879 vim_snprintf(VICommand, sizeof(VICommand), |
880 (char *)UnloadBuf, file); | |
7 | 881 vi_exec_cmd(VICommand); |
882 } | |
883 } | |
884 else if (writable && !buf->b_changed) | |
885 { | |
886 vi_exec_cmd("e"); | |
887 } | |
888 } | |
889 break; | |
890 } | |
891 case 'h' : /* highlight info */ | |
892 break; /* not implemented */ | |
893 | |
894 case 't' : /* Set tab width */ | |
895 { | |
896 int tab_width = atoi(argv[1]); | |
897 | |
898 if (tab_width > 0 && tab_width <= 16) | |
899 { | |
426 | 900 vim_snprintf(VICommand, sizeof(VICommand), |
901 (char *)SetTab, tab_width); | |
7 | 902 vi_exec_cmd(VICommand); |
903 } | |
904 break; | |
905 } | |
906 case '|': | |
907 { | |
908 /* change the request separator */ | |
909 sniff_rq_sep[0] = arguments[0]; | |
910 /* echo the request */ | |
911 WriteToSniff(buffer); | |
912 break; | |
913 } | |
914 case 'A' : /* Warning/Info msg */ | |
915 vi_msg(arguments); | |
426 | 916 if (!strncmp(arguments, "Disconnected", 12)) |
7 | 917 sniff_disconnect(1); /* unexpected disconnection */ |
918 break; | |
919 case 'a' : /* Error msg */ | |
920 vi_error_msg(arguments); | |
426 | 921 if (!strncmp(arguments, "Cannot connect", 14)) |
7 | 922 sniff_disconnect(1); |
923 break; | |
924 | |
925 default : | |
926 break; | |
927 } | |
3935 | 928 while (argc) |
7 | 929 vim_free(argv[--argc]); |
930 } | |
931 | |
932 | |
933 #ifndef WIN32 | |
934 /* get_request | |
935 * read string from fd up to next newline (excluding the nl), | |
936 * returns length of string | |
937 * 0 if no data available or no complete line | |
938 * <0 on error | |
939 */ | |
940 static int | |
941 get_request(fd, buf, maxlen) | |
942 int fd; | |
943 char *buf; | |
944 int maxlen; | |
945 { | |
946 static char inbuf[1024]; | |
947 static int pos = 0, bytes = 0; | |
948 int len; | |
949 #ifdef HAVE_SELECT | |
950 struct timeval tval; | |
951 fd_set rfds; | |
952 | |
953 FD_ZERO(&rfds); | |
954 FD_SET(fd, &rfds); | |
955 tval.tv_sec = 0; | |
956 tval.tv_usec = 0; | |
957 #else | |
958 struct pollfd fds; | |
959 | |
960 fds.fd = fd; | |
961 fds.events = POLLIN; | |
962 #endif | |
963 | |
964 for (len = 0; len < maxlen; len++) | |
965 { | |
966 if (pos >= bytes) /* end of buffer reached? */ | |
967 { | |
968 #ifdef HAVE_SELECT | |
969 if (select(fd + 1, &rfds, NULL, NULL, &tval) > 0) | |
970 #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
|
971 if (poll(&fds, 1, 0) > 0) |
7 | 972 #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
|
973 { |
073ff46fe397
Fold Vim 7.2 default branch back to trunk to avoid two heads. (Tony
Bram Moolenaar <bram@vim.org>
parents:
2165
diff
changeset
|
974 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
|
975 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
|
976 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
|
977 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
|
978 } |
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 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
|
980 { |
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 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
|
982 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
|
983 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
|
984 } |
7 | 985 } |
986 if ((buf[len] = inbuf[pos++]) =='\n') | |
987 break; | |
988 } | |
989 buf[len] = '\0'; | |
990 return len; | |
991 } | |
992 #endif /* WIN32 */ | |
993 | |
994 | |
995 static void | |
996 SendRequest(command, symbol) | |
997 struct sn_cmd *command; | |
998 char *symbol; | |
999 { | |
1000 int cmd_type = command->cmd_type; | |
1001 static char cmdstr[MAX_REQUEST_LEN]; | |
1002 static char msgtxt[MAX_REQUEST_LEN]; | |
1003 char *buffer_name = NULL; | |
1004 | |
1005 if (cmd_type == RQ_CONNECT) | |
1006 { | |
1007 sniff_connect(); | |
1008 return; | |
1009 } | |
1010 if (!sniff_connected && !(cmd_type & SILENT)) | |
1011 { | |
1012 vi_error_msg(_("E278: SNiFF+ not connected")); | |
1013 return; | |
1014 } | |
1015 | |
1016 if (cmd_type & NEED_FILE) | |
1017 { | |
1018 if (!curbuf->b_sniff) | |
1019 { | |
1020 if (!(cmd_type & SILENT)) | |
1021 vi_error_msg(_("E279: Not a SNiFF+ buffer")); | |
1022 return; | |
1023 } | |
1024 buffer_name = vi_buffer_name(); | |
1025 if (buffer_name == NULL) | |
1026 return; | |
1027 if (cmd_type & NEED_SYMBOL) | |
1028 { | |
1029 if (cmd_type & EMPTY_SYMBOL) | |
1030 symbol = " "; | |
1031 else if (!symbol && !(symbol = vi_symbol_under_cursor())) | |
1032 return; /* error msg already displayed */ | |
1033 } | |
1034 | |
1035 if (symbol) | |
272 | 1036 vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s%s%ld%s%s\n", |
7 | 1037 command->cmd_code, |
1038 buffer_name, | |
1039 sniff_rq_sep, | |
1040 vi_cursor_pos(), | |
1041 sniff_rq_sep, | |
1042 symbol | |
1043 ); | |
1044 else | |
272 | 1045 vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s\n", |
1046 command->cmd_code, buffer_name); | |
7 | 1047 } |
1048 else /* simple request */ | |
1049 { | |
1050 cmdstr[0] = command->cmd_code; | |
1051 cmdstr[1] = '\n'; | |
1052 cmdstr[2] = '\0'; | |
1053 } | |
1054 if (command->cmd_msg && !(cmd_type & SILENT)) | |
1055 { | |
1056 if ((cmd_type & NEED_SYMBOL) && !(cmd_type & EMPTY_SYMBOL)) | |
1057 { | |
272 | 1058 vim_snprintf(msgtxt, sizeof(msgtxt), "%s: %s", |
1059 _(command->cmd_msg), symbol); | |
7 | 1060 vi_msg(msgtxt); |
1061 } | |
1062 else | |
1063 vi_msg(_(command->cmd_msg)); | |
1064 } | |
1065 WriteToSniff(cmdstr); | |
1066 if (cmd_type & DISCONNECT) | |
1067 sniff_disconnect(0); | |
1068 } | |
1069 | |
1070 | |
1071 | |
1072 static void | |
1073 WriteToSniff(str) | |
1074 char *str; | |
1075 { | |
1076 int bytes; | |
1077 #ifdef WIN32 | |
1078 if (! WriteFile(handle_to_sniff, str, strlen(str), &bytes, NULL)) | |
1079 { | |
1080 DWORD err=GetLastError(); | |
1081 bytes = -1; | |
1082 } | |
1083 #else | |
1084 bytes = write(fd_to_sniff, str, strlen(str)); | |
1085 #endif | |
1086 if (bytes<0) | |
1087 { | |
1088 vi_msg(_("Sniff: Error during write. Disconnected")); | |
1089 sniff_disconnect(1); | |
1090 } | |
1091 } | |
1092 | |
1093 /*-------- vim helping functions --------------------------------*/ | |
1094 | |
1095 static void | |
1096 vi_msg(str) | |
1097 char *str; | |
1098 { | |
1099 if (str != NULL && *str != NUL) | |
1100 MSG((char_u *)str); | |
1101 } | |
1102 | |
1103 static void | |
1104 vi_error_msg(str) | |
1105 char *str; | |
1106 { | |
1107 if (str != NULL && *str != NUL) | |
1108 EMSG((char_u *)str); | |
1109 } | |
1110 | |
1111 static void | |
1112 vi_open_file(fname) | |
1113 char *fname; | |
1114 { | |
1115 ++no_wait_return; | |
1743 | 1116 do_ecmd(0, (char_u *)fname, NULL, NULL, ECMD_ONE, ECMD_HIDE+ECMD_OLDBUF, |
1117 curwin); | |
7 | 1118 curbuf->b_sniff = TRUE; |
1119 --no_wait_return; /* [ex_docmd.c] */ | |
1120 } | |
1121 | |
1122 static buf_T * | |
1123 vi_find_buffer(fname) | |
1124 char *fname; | |
1125 { /* derived from buflist_findname() [buffer.c] */ | |
1126 buf_T *buf; | |
1127 | |
1128 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
1129 if (buf->b_sfname != NULL && fnamecmp(fname, buf->b_sfname) == 0) | |
1130 return (buf); | |
1131 return NULL; | |
1132 } | |
1133 | |
1134 | |
1135 static char * | |
1136 vi_symbol_under_cursor() | |
1137 { | |
1138 int len; | |
1139 char *symbolp; | |
1140 char *p; | |
1141 static char sniff_symbol[256]; | |
1142 | |
1143 len = find_ident_under_cursor((char_u **)&symbolp, FIND_IDENT); | |
1144 /* [normal.c] */ | |
1145 if (len <= 0) | |
1146 return NULL; | |
1147 for (p=sniff_symbol; len; len--) | |
1148 *p++ = *symbolp++; | |
1149 *p = '\0'; | |
1150 return sniff_symbol; | |
1151 } | |
1152 | |
1153 | |
1154 static char * | |
1155 vi_buffer_name() | |
1156 { | |
1157 return (char *)curbuf->b_sfname; | |
1158 } | |
1159 | |
1160 static void | |
1161 vi_exec_cmd(vicmd) | |
1162 char *vicmd; | |
1163 { | |
1164 do_cmdline_cmd((char_u *)vicmd); /* [ex_docmd.c] */ | |
1165 } | |
1166 | |
1167 /* | |
1168 * Set cursor on character position | |
1169 * derived from cursor_pos_info() [buffer.c] | |
1170 */ | |
1171 static void | |
1172 vi_set_cursor_pos(char_pos) | |
1173 long char_pos; | |
1174 { | |
1175 linenr_T lnum; | |
1176 long char_count = 1; /* first position = 1 */ | |
1177 int line_size; | |
1178 int eol_size; | |
1179 | |
1180 if (char_pos == 0) | |
1181 { | |
1182 char_pos = 1; | |
1183 } | |
1184 if (get_fileformat(curbuf) == EOL_DOS) | |
1185 eol_size = 2; | |
1186 else | |
1187 eol_size = 1; | |
1188 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) | |
1189 { | |
1190 line_size = STRLEN(ml_get(lnum)) + eol_size; | |
1191 if (char_count+line_size > char_pos) break; | |
1192 char_count += line_size; | |
1193 } | |
1194 curwin->w_cursor.lnum = lnum; | |
1195 curwin->w_cursor.col = char_pos - char_count; | |
1196 } | |
1197 | |
1198 static long | |
1199 vi_cursor_pos() | |
1200 { | |
1201 linenr_T lnum; | |
1202 long char_count=1; /* sniff starts with pos 1 */ | |
1203 int line_size; | |
1204 int eol_size; | |
1205 | |
1206 if (curbuf->b_p_tx) | |
1207 eol_size = 2; | |
1208 else | |
1209 eol_size = 1; | |
1210 for (lnum = 1; lnum < curwin->w_cursor.lnum; ++lnum) | |
1211 { | |
1212 line_size = STRLEN(ml_get(lnum)) + eol_size; | |
1213 char_count += line_size; | |
1214 } | |
1215 return char_count + curwin->w_cursor.col; | |
1216 } |