feat/quickfix-title: fixed problem with compiling tiny version.
[vim_extended.git] / src / if_cscope.c
blob1ed9e86d9fd724e2a96a746d4e16132504006e49
1 /* vi:set ts=8 sts=4 sw=4:
3 * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
4 * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com>
6 * The basic idea/structure of cscope for Vim was borrowed from Nvi. There
7 * might be a few lines of code that look similar to what Nvi has.
9 * See README.txt for an overview of the Vim source code.
12 #include "vim.h"
14 #if defined(FEAT_CSCOPE) || defined(PROTO)
16 #include <string.h>
17 #include <errno.h>
18 #include <assert.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #if defined(UNIX)
22 # include <sys/wait.h>
23 #else
24 /* not UNIX, must be WIN32 */
25 # include "vimio.h"
26 #endif
27 #include "if_cscope.h"
29 static void cs_usage_msg __ARGS((csid_e x));
30 static int cs_add __ARGS((exarg_T *eap));
31 static void cs_stat_emsg __ARGS((char *fname));
32 static int cs_add_common __ARGS((char *, char *, char *));
33 static int cs_check_for_connections __ARGS((void));
34 static int cs_check_for_tags __ARGS((void));
35 static int cs_cnt_connections __ARGS((void));
36 static void cs_reading_emsg __ARGS((int idx));
37 static int cs_cnt_matches __ARGS((int idx));
38 static char * cs_create_cmd __ARGS((char *csoption, char *pattern));
39 static int cs_create_connection __ARGS((int i));
40 static void do_cscope_general __ARGS((exarg_T *eap, int make_split));
41 #ifdef FEAT_QUICKFIX
42 static void cs_file_results __ARGS((FILE *, int *));
43 #endif
44 static void cs_fill_results __ARGS((char *, int , int *, char ***,
45 char ***, int *));
46 static int cs_find __ARGS((exarg_T *eap));
47 static int cs_find_common __ARGS((char *opt, char *pat, int, int, int, char *cmdline));
48 static int cs_help __ARGS((exarg_T *eap));
49 static void clear_csinfo __ARGS((int i));
50 static int cs_insert_filelist __ARGS((char *, char *, char *,
51 struct stat *));
52 static int cs_kill __ARGS((exarg_T *eap));
53 static void cs_kill_execute __ARGS((int, char *));
54 static cscmd_T * cs_lookup_cmd __ARGS((exarg_T *eap));
55 static char * cs_make_vim_style_matches __ARGS((char *, char *,
56 char *, char *));
57 static char * cs_manage_matches __ARGS((char **, char **, int, mcmd_e));
58 static char * cs_parse_results __ARGS((int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search));
59 static char * cs_pathcomponents __ARGS((char *path));
60 static void cs_print_tags_priv __ARGS((char **, char **, int));
61 static int cs_read_prompt __ARGS((int));
62 static void cs_release_csp __ARGS((int, int freefnpp));
63 static int cs_reset __ARGS((exarg_T *eap));
64 static char * cs_resolve_file __ARGS((int, char *));
65 static int cs_show __ARGS((exarg_T *eap));
68 static csinfo_T * csinfo = NULL;
69 static int csinfo_size = 0; /* number of items allocated in
70 csinfo[] */
72 static int eap_arg_len; /* length of eap->arg, set in
73 cs_lookup_cmd() */
74 static cscmd_T cs_cmds[] =
76 { "add", cs_add,
77 N_("Add a new database"), "add file|dir [pre-path] [flags]", 0 },
78 { "find", cs_find,
79 N_("Query for a pattern"), "find c|d|e|f|g|i|s|t name", 1 },
80 { "help", cs_help,
81 N_("Show this message"), "help", 0 },
82 { "kill", cs_kill,
83 N_("Kill a connection"), "kill #", 0 },
84 { "reset", cs_reset,
85 N_("Reinit all connections"), "reset", 0 },
86 { "show", cs_show,
87 N_("Show connections"), "show", 0 },
88 { NULL, NULL, NULL, NULL, 0 }
91 static void
92 cs_usage_msg(x)
93 csid_e x;
95 (void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
98 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
100 static enum
102 EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */
103 EXP_SCSCOPE_SUBCMD, /* expand ":scscope" sub-commands */
104 EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */
105 EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */
106 } expand_what;
109 * Function given to ExpandGeneric() to obtain the cscope command
110 * expansion.
112 char_u *
113 get_cscope_name(xp, idx)
114 expand_T *xp UNUSED;
115 int idx;
117 int current_idx;
118 int i;
120 switch (expand_what)
122 case EXP_CSCOPE_SUBCMD:
123 /* Complete with sub-commands of ":cscope":
124 * add, find, help, kill, reset, show */
125 return (char_u *)cs_cmds[idx].name;
126 case EXP_SCSCOPE_SUBCMD:
127 /* Complete with sub-commands of ":scscope": same sub-commands as
128 * ":cscope" but skip commands which don't support split windows */
129 for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++)
130 if (cs_cmds[i].cansplit)
131 if (current_idx++ == idx)
132 break;
133 return (char_u *)cs_cmds[i].name;
134 case EXP_CSCOPE_FIND:
136 const char *query_type[] =
138 "c", "d", "e", "f", "g", "i", "s", "t", NULL
141 /* Complete with query type of ":cscope find {query_type}".
142 * {query_type} can be letters (c, d, ... t) or numbers (0, 1,
143 * ..., 8) but only complete with letters, since numbers are
144 * redundant. */
145 return (char_u *)query_type[idx];
147 case EXP_CSCOPE_KILL:
149 static char connection[5];
151 /* ":cscope kill" accepts connection numbers or partial names of
152 * the pathname of the cscope database as argument. Only complete
153 * with connection numbers. -1 can also be used to kill all
154 * connections. */
155 for (i = 0, current_idx = 0; i < csinfo_size; i++)
157 if (csinfo[i].fname == NULL)
158 continue;
159 if (current_idx++ == idx)
161 vim_snprintf(connection, sizeof(connection), "%d", i);
162 return (char_u *)connection;
165 return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
167 default:
168 return NULL;
173 * Handle command line completion for :cscope command.
175 void
176 set_context_in_cscope_cmd(xp, arg, cmdidx)
177 expand_T *xp;
178 char_u *arg;
179 cmdidx_T cmdidx;
181 char_u *p;
183 /* Default: expand subcommands */
184 xp->xp_context = EXPAND_CSCOPE;
185 xp->xp_pattern = arg;
186 expand_what = (cmdidx == CMD_scscope)
187 ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
189 /* (part of) subcommand already typed */
190 if (*arg != NUL)
192 p = skiptowhite(arg);
193 if (*p != NUL) /* past first word */
195 xp->xp_pattern = skipwhite(p);
196 if (*skiptowhite(xp->xp_pattern) != NUL)
197 xp->xp_context = EXPAND_NOTHING;
198 else if (STRNICMP(arg, "add", p - arg) == 0)
199 xp->xp_context = EXPAND_FILES;
200 else if (STRNICMP(arg, "kill", p - arg) == 0)
201 expand_what = EXP_CSCOPE_KILL;
202 else if (STRNICMP(arg, "find", p - arg) == 0)
203 expand_what = EXP_CSCOPE_FIND;
204 else
205 xp->xp_context = EXPAND_NOTHING;
210 #endif /* FEAT_CMDL_COMPL */
213 * PRIVATE: do_cscope_general
215 * Find the command, print help if invalid, and then call the corresponding
216 * command function.
218 static void
219 do_cscope_general(eap, make_split)
220 exarg_T *eap;
221 int make_split; /* whether to split window */
223 cscmd_T *cmdp;
225 if ((cmdp = cs_lookup_cmd(eap)) == NULL)
227 cs_help(eap);
228 return;
231 #ifdef FEAT_WINDOWS
232 if (make_split)
234 if (!cmdp->cansplit)
236 (void)MSG_PUTS(_("This cscope command does not support splitting the window.\n"));
237 return;
239 postponed_split = -1;
240 postponed_split_flags = cmdmod.split;
241 postponed_split_tab = cmdmod.tab;
243 #endif
245 cmdp->func(eap);
247 #ifdef FEAT_WINDOWS
248 postponed_split_flags = 0;
249 postponed_split_tab = 0;
250 #endif
254 * PUBLIC: do_cscope
256 void
257 do_cscope(eap)
258 exarg_T *eap;
260 do_cscope_general(eap, FALSE);
264 * PUBLIC: do_scscope
266 * same as do_cscope, but splits window, too.
268 void
269 do_scscope(eap)
270 exarg_T *eap;
272 do_cscope_general(eap, TRUE);
276 * PUBLIC: do_cstag
279 void
280 do_cstag(eap)
281 exarg_T *eap;
283 int ret = FALSE;
285 if (*eap->arg == NUL)
287 (void)EMSG(_("E562: Usage: cstag <ident>"));
288 return;
291 switch (p_csto)
293 case 0 :
294 if (cs_check_for_connections())
296 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
297 FALSE,
298 (char *)*eap->cmdlinep);
299 if (ret == FALSE)
301 cs_free_tags();
302 if (msg_col)
303 msg_putchar('\n');
305 if (cs_check_for_tags())
306 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
309 else if (cs_check_for_tags())
311 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
313 break;
314 case 1 :
315 if (cs_check_for_tags())
317 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
318 if (ret == FALSE)
320 if (msg_col)
321 msg_putchar('\n');
323 if (cs_check_for_connections())
325 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
326 FALSE, FALSE,
327 (char *)*eap->cmdlinep);
328 if (ret == FALSE)
329 cs_free_tags();
333 else if (cs_check_for_connections())
335 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
336 FALSE,
337 (char *)*eap->cmdlinep);
338 if (ret == FALSE)
339 cs_free_tags();
341 break;
342 default :
343 break;
346 if (!ret)
348 (void)EMSG(_("E257: cstag: tag not found"));
349 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
350 g_do_tagpreview = 0;
351 #endif
354 } /* do_cscope */
358 * PUBLIC: cs_find
360 * this simulates a vim_fgets(), but for cscope, returns the next line
361 * from the cscope output. should only be called from find_tags()
363 * returns TRUE if eof, FALSE otherwise
366 cs_fgets(buf, size)
367 char_u *buf;
368 int size;
370 char *p;
372 if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
373 return TRUE;
374 vim_strncpy(buf, (char_u *)p, size - 1);
376 return FALSE;
377 } /* cs_fgets */
381 * PUBLIC: cs_free_tags
383 * called only from do_tag(), when popping the tag stack
385 void
386 cs_free_tags()
388 cs_manage_matches(NULL, NULL, -1, Free);
393 * PUBLIC: cs_print_tags
395 * called from do_tag()
397 void
398 cs_print_tags()
400 cs_manage_matches(NULL, NULL, -1, Print);
405 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
407 * Checks for the existence of a |cscope| connection. If no
408 * parameters are specified, then the function returns:
410 * 0, if cscope was not available (not compiled in), or if there
411 * are no cscope connections; or
412 * 1, if there is at least one cscope connection.
414 * If parameters are specified, then the value of {num}
415 * determines how existence of a cscope connection is checked:
417 * {num} Description of existence check
418 * ----- ------------------------------
419 * 0 Same as no parameters (e.g., "cscope_connection()").
420 * 1 Ignore {prepend}, and use partial string matches for
421 * {dbpath}.
422 * 2 Ignore {prepend}, and use exact string matches for
423 * {dbpath}.
424 * 3 Use {prepend}, use partial string matches for both
425 * {dbpath} and {prepend}.
426 * 4 Use {prepend}, use exact string matches for both
427 * {dbpath} and {prepend}.
429 * Note: All string comparisons are case sensitive!
431 #if defined(FEAT_EVAL) || defined(PROTO)
433 cs_connection(num, dbpath, ppath)
434 int num;
435 char_u *dbpath;
436 char_u *ppath;
438 int i;
440 if (num < 0 || num > 4 || (num > 0 && !dbpath))
441 return FALSE;
443 for (i = 0; i < csinfo_size; i++)
445 if (!csinfo[i].fname)
446 continue;
448 if (num == 0)
449 return TRUE;
451 switch (num)
453 case 1:
454 if (strstr(csinfo[i].fname, (char *)dbpath))
455 return TRUE;
456 break;
457 case 2:
458 if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
459 return TRUE;
460 break;
461 case 3:
462 if (strstr(csinfo[i].fname, (char *)dbpath)
463 && ((!ppath && !csinfo[i].ppath)
464 || (ppath
465 && csinfo[i].ppath
466 && strstr(csinfo[i].ppath, (char *)ppath))))
467 return TRUE;
468 break;
469 case 4:
470 if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
471 && ((!ppath && !csinfo[i].ppath)
472 || (ppath
473 && csinfo[i].ppath
474 && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
475 return TRUE;
476 break;
480 return FALSE;
481 } /* cs_connection */
482 #endif
486 * PRIVATE functions
487 ****************************************************************************/
490 * PRIVATE: cs_add
492 * add cscope database or a directory name (to look for cscope.out)
493 * to the cscope connection list
495 * MAXPATHL 256
497 static int
498 cs_add(eap)
499 exarg_T *eap UNUSED;
501 char *fname, *ppath, *flags = NULL;
503 if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL)
505 cs_usage_msg(Add);
506 return CSCOPE_FAILURE;
508 if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
509 flags = strtok((char *)NULL, (const char *)" ");
511 return cs_add_common(fname, ppath, flags);
514 static void
515 cs_stat_emsg(fname)
516 char *fname;
518 char *stat_emsg = _("E563: stat(%s) error: %d");
519 char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10);
521 if (buf != NULL)
523 (void)sprintf(buf, stat_emsg, fname, errno);
524 (void)EMSG(buf);
525 vim_free(buf);
527 else
528 (void)EMSG(_("E563: stat error"));
533 * PRIVATE: cs_add_common
535 * the common routine to add a new cscope connection. called by
536 * cs_add() and cs_reset(). i really don't like to do this, but this
537 * routine uses a number of goto statements.
539 static int
540 cs_add_common(arg1, arg2, flags)
541 char *arg1; /* filename - may contain environment variables */
542 char *arg2; /* prepend path - may contain environment variables */
543 char *flags;
545 struct stat statbuf;
546 int ret;
547 char *fname = NULL;
548 char *fname2 = NULL;
549 char *ppath = NULL;
550 int i;
552 /* get the filename (arg1), expand it, and try to stat it */
553 if ((fname = (char *)alloc(MAXPATHL + 1)) == NULL)
554 goto add_err;
556 expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
557 ret = stat(fname, &statbuf);
558 if (ret < 0)
560 staterr:
561 if (p_csverbose)
562 cs_stat_emsg(fname);
563 goto add_err;
566 /* get the prepend path (arg2), expand it, and try to stat it */
567 if (arg2 != NULL)
569 struct stat statbuf2;
571 if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
572 goto add_err;
574 expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
575 ret = stat(ppath, &statbuf2);
576 if (ret < 0)
577 goto staterr;
580 /* if filename is a directory, append the cscope database name to it */
581 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
583 fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
584 if (fname2 == NULL)
585 goto add_err;
587 while (fname[strlen(fname)-1] == '/'
588 #ifdef WIN32
589 || fname[strlen(fname)-1] == '\\'
590 #endif
593 fname[strlen(fname)-1] = '\0';
594 if (strlen(fname) == 0)
595 break;
597 if (fname[0] == '\0')
598 (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
599 else
600 (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
602 ret = stat(fname2, &statbuf);
603 if (ret < 0)
605 if (p_csverbose)
606 cs_stat_emsg(fname2);
607 goto add_err;
610 i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
612 #if defined(UNIX)
613 else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
614 #else
615 /* WIN32 - substitute define S_ISREG from os_unix.h */
616 else if (((statbuf.st_mode) & S_IFMT) == S_IFREG)
617 #endif
619 i = cs_insert_filelist(fname, ppath, flags, &statbuf);
621 else
623 if (p_csverbose)
624 (void)EMSG2(
625 _("E564: %s is not a directory or a valid cscope database"),
626 fname);
627 goto add_err;
630 if (i != -1)
632 if (cs_create_connection(i) == CSCOPE_FAILURE
633 || cs_read_prompt(i) == CSCOPE_FAILURE)
635 cs_release_csp(i, TRUE);
636 goto add_err;
639 if (p_csverbose)
641 msg_clr_eos();
642 (void)smsg_attr(hl_attr(HLF_R),
643 (char_u *)_("Added cscope database %s"),
644 csinfo[i].fname);
648 vim_free(fname);
649 vim_free(fname2);
650 vim_free(ppath);
651 return CSCOPE_SUCCESS;
653 add_err:
654 vim_free(fname2);
655 vim_free(fname);
656 vim_free(ppath);
657 return CSCOPE_FAILURE;
658 } /* cs_add_common */
661 static int
662 cs_check_for_connections()
664 return (cs_cnt_connections() > 0);
665 } /* cs_check_for_connections */
668 static int
669 cs_check_for_tags()
671 return (p_tags[0] != NUL && curbuf->b_p_tags != NULL);
672 } /* cs_check_for_tags */
676 * PRIVATE: cs_cnt_connections
678 * count the number of cscope connections
680 static int
681 cs_cnt_connections()
683 short i;
684 short cnt = 0;
686 for (i = 0; i < csinfo_size; i++)
688 if (csinfo[i].fname != NULL)
689 cnt++;
691 return cnt;
692 } /* cs_cnt_connections */
694 static void
695 cs_reading_emsg(idx)
696 int idx; /* connection index */
698 EMSGN(_("E262: error reading cscope connection %ld"), idx);
701 #define CSREAD_BUFSIZE 2048
703 * PRIVATE: cs_cnt_matches
705 * count the number of matches for a given cscope connection.
707 static int
708 cs_cnt_matches(idx)
709 int idx;
711 char *stok;
712 char *buf;
713 int nlines;
715 buf = (char *)alloc(CSREAD_BUFSIZE);
716 if (buf == NULL)
717 return 0;
718 for (;;)
720 if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp))
722 if (feof(csinfo[idx].fr_fp))
723 errno = EIO;
725 cs_reading_emsg(idx);
727 vim_free(buf);
728 return -1;
732 * If the database is out of date, or there's some other problem,
733 * cscope will output error messages before the number-of-lines output.
734 * Display/discard any output that doesn't match what we want.
735 * Accept "\S*cscope: X lines", also matches "mlcscope".
737 if ((stok = strtok(buf, (const char *)" ")) == NULL)
738 continue;
739 if (strstr((const char *)stok, "cscope:") == NULL)
740 continue;
742 if ((stok = strtok(NULL, (const char *)" ")) == NULL)
743 continue;
744 nlines = atoi(stok);
745 if (nlines < 0)
747 nlines = 0;
748 break;
751 if ((stok = strtok(NULL, (const char *)" ")) == NULL)
752 continue;
753 if (strncmp((const char *)stok, "lines", 5))
754 continue;
756 break;
759 vim_free(buf);
760 return nlines;
761 } /* cs_cnt_matches */
765 * PRIVATE: cs_create_cmd
767 * Creates the actual cscope command query from what the user entered.
769 static char *
770 cs_create_cmd(csoption, pattern)
771 char *csoption;
772 char *pattern;
774 char *cmd;
775 short search;
776 char *pat;
778 switch (csoption[0])
780 case '0' : case 's' :
781 search = 0;
782 break;
783 case '1' : case 'g' :
784 search = 1;
785 break;
786 case '2' : case 'd' :
787 search = 2;
788 break;
789 case '3' : case 'c' :
790 search = 3;
791 break;
792 case '4' : case 't' :
793 search = 4;
794 break;
795 case '6' : case 'e' :
796 search = 6;
797 break;
798 case '7' : case 'f' :
799 search = 7;
800 break;
801 case '8' : case 'i' :
802 search = 8;
803 break;
804 default :
805 (void)EMSG(_("E561: unknown cscope search type"));
806 cs_usage_msg(Find);
807 return NULL;
810 /* Skip white space before the patter, except for text and pattern search,
811 * they may want to use the leading white space. */
812 pat = pattern;
813 if (search != 4 && search != 6)
814 while vim_iswhite(*pat)
815 ++pat;
817 if ((cmd = (char *)alloc((unsigned)(strlen(pat) + 2))) == NULL)
818 return NULL;
820 (void)sprintf(cmd, "%d%s", search, pat);
822 return cmd;
823 } /* cs_create_cmd */
827 * PRIVATE: cs_create_connection
829 * This piece of code was taken/adapted from nvi. do we need to add
830 * the BSD license notice?
832 static int
833 cs_create_connection(i)
834 int i;
836 #ifdef UNIX
837 int to_cs[2], from_cs[2];
838 #endif
839 int len;
840 char *prog, *cmd, *ppath = NULL;
841 #ifdef WIN32
842 int fd;
843 SECURITY_ATTRIBUTES sa;
844 PROCESS_INFORMATION pi;
845 STARTUPINFO si;
846 BOOL pipe_stdin = FALSE, pipe_stdout = FALSE;
847 HANDLE stdin_rd, stdout_rd;
848 HANDLE stdout_wr, stdin_wr;
849 BOOL created;
850 # ifdef __BORLANDC__
851 # define OPEN_OH_ARGTYPE long
852 # else
853 # if (_MSC_VER >= 1300)
854 # define OPEN_OH_ARGTYPE intptr_t
855 # else
856 # define OPEN_OH_ARGTYPE long
857 # endif
858 # endif
859 #endif
861 #if defined(UNIX)
863 * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
864 * from_cs[0] and writes to to_cs[1].
866 to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
867 if (pipe(to_cs) < 0 || pipe(from_cs) < 0)
869 (void)EMSG(_("E566: Could not create cscope pipes"));
870 err_closing:
871 if (to_cs[0] != -1)
872 (void)close(to_cs[0]);
873 if (to_cs[1] != -1)
874 (void)close(to_cs[1]);
875 if (from_cs[0] != -1)
876 (void)close(from_cs[0]);
877 if (from_cs[1] != -1)
878 (void)close(from_cs[1]);
879 return CSCOPE_FAILURE;
882 switch (csinfo[i].pid = fork())
884 case -1:
885 (void)EMSG(_("E622: Could not fork for cscope"));
886 goto err_closing;
887 case 0: /* child: run cscope. */
888 if (dup2(to_cs[0], STDIN_FILENO) == -1)
889 PERROR("cs_create_connection 1");
890 if (dup2(from_cs[1], STDOUT_FILENO) == -1)
891 PERROR("cs_create_connection 2");
892 if (dup2(from_cs[1], STDERR_FILENO) == -1)
893 PERROR("cs_create_connection 3");
895 /* close unused */
896 (void)close(to_cs[1]);
897 (void)close(from_cs[0]);
898 #else
899 /* WIN32 */
900 /* Create pipes to communicate with cscope */
901 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
902 sa.bInheritHandle = TRUE;
903 sa.lpSecurityDescriptor = NULL;
905 if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
906 || !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0)))
908 (void)EMSG(_("E566: Could not create cscope pipes"));
909 err_closing:
910 if (pipe_stdin)
912 CloseHandle(stdin_rd);
913 CloseHandle(stdin_wr);
915 if (pipe_stdout)
917 CloseHandle(stdout_rd);
918 CloseHandle(stdout_wr);
920 return CSCOPE_FAILURE;
922 #endif
923 /* expand the cscope exec for env var's */
924 if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL)
926 #ifdef UNIX
927 return CSCOPE_FAILURE;
928 #else
929 /* WIN32 */
930 goto err_closing;
931 #endif
933 expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
935 /* alloc space to hold the cscope command */
936 len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32);
937 if (csinfo[i].ppath)
939 /* expand the prepend path for env var's */
940 if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
942 vim_free(prog);
943 #ifdef UNIX
944 return CSCOPE_FAILURE;
945 #else
946 /* WIN32 */
947 goto err_closing;
948 #endif
950 expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
952 len += (int)strlen(ppath);
955 if (csinfo[i].flags)
956 len += (int)strlen(csinfo[i].flags);
958 if ((cmd = (char *)alloc(len)) == NULL)
960 vim_free(prog);
961 vim_free(ppath);
962 #ifdef UNIX
963 return CSCOPE_FAILURE;
964 #else
965 /* WIN32 */
966 goto err_closing;
967 #endif
970 /* run the cscope command; is there execl for non-unix systems? */
971 #if defined(UNIX)
972 (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
973 #else
974 /* WIN32 */
975 (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
976 #endif
977 if (csinfo[i].ppath != NULL)
979 (void)strcat(cmd, " -P");
980 (void)strcat(cmd, csinfo[i].ppath);
982 if (csinfo[i].flags != NULL)
984 (void)strcat(cmd, " ");
985 (void)strcat(cmd, csinfo[i].flags);
987 # ifdef UNIX
988 /* on Win32 we still need prog */
989 vim_free(prog);
990 # endif
991 vim_free(ppath);
993 #if defined(UNIX)
994 if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
995 PERROR(_("cs_create_connection exec failed"));
997 exit(127);
998 /* NOTREACHED */
999 default: /* parent. */
1001 * Save the file descriptors for later duplication, and
1002 * reopen as streams.
1004 if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
1005 PERROR(_("cs_create_connection: fdopen for to_fp failed"));
1006 if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
1007 PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
1009 /* close unused */
1010 (void)close(to_cs[0]);
1011 (void)close(from_cs[1]);
1013 break;
1016 #else
1017 /* WIN32 */
1018 /* Create a new process to run cscope and use pipes to talk with it */
1019 GetStartupInfo(&si);
1020 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1021 si.wShowWindow = SW_HIDE; /* Hide child application window */
1022 si.hStdOutput = stdout_wr;
1023 si.hStdError = stdout_wr;
1024 si.hStdInput = stdin_rd;
1025 created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
1026 NULL, NULL, &si, &pi);
1027 vim_free(prog);
1028 vim_free(cmd);
1030 if (!created)
1032 PERROR(_("cs_create_connection exec failed"));
1033 (void)EMSG(_("E623: Could not spawn cscope process"));
1034 goto err_closing;
1036 /* else */
1037 csinfo[i].pid = pi.dwProcessId;
1038 csinfo[i].hProc = pi.hProcess;
1039 CloseHandle(pi.hThread);
1041 /* TODO - tidy up after failure to create files on pipe handles. */
1042 if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
1043 _O_TEXT|_O_APPEND)) < 0)
1044 || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
1045 PERROR(_("cs_create_connection: fdopen for to_fp failed"));
1046 if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
1047 _O_TEXT|_O_RDONLY)) < 0)
1048 || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
1049 PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
1051 /* Close handles for file descriptors inherited by the cscope process */
1052 CloseHandle(stdin_rd);
1053 CloseHandle(stdout_wr);
1055 #endif /* !UNIX */
1057 return CSCOPE_SUCCESS;
1058 } /* cs_create_connection */
1062 * PRIVATE: cs_find
1064 * query cscope using command line interface. parse the output and use tselect
1065 * to allow choices. like Nvi, creates a pipe to send to/from query/cscope.
1067 * returns TRUE if we jump to a tag or abort, FALSE if not.
1069 static int
1070 cs_find(eap)
1071 exarg_T *eap;
1073 char *opt, *pat;
1074 int i;
1076 if (cs_check_for_connections() == FALSE)
1078 (void)EMSG(_("E567: no cscope connections"));
1079 return FALSE;
1082 if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL)
1084 cs_usage_msg(Find);
1085 return FALSE;
1088 pat = opt + strlen(opt) + 1;
1089 if (pat >= (char *)eap->arg + eap_arg_len)
1091 cs_usage_msg(Find);
1092 return FALSE;
1096 * Let's replace the NULs written by strtok() with spaces - we need the
1097 * spaces to correctly display the quickfix/location list window's title.
1099 for (i = 0; i < eap_arg_len; ++i)
1100 if ('\0' == eap->arg[i])
1101 eap->arg[i] = ' ';
1103 return cs_find_common(opt, pat, eap->forceit, TRUE,
1104 eap->cmdidx == CMD_lcscope,
1105 (char *)*eap->cmdlinep);
1106 } /* cs_find */
1110 * PRIVATE: cs_find_common
1112 * common code for cscope find, shared by cs_find() and do_cstag()
1114 static int
1115 cs_find_common(opt, pat, forceit, verbose, use_ll, cmdline)
1116 char *opt;
1117 char *pat;
1118 int forceit;
1119 int verbose;
1120 int use_ll;
1121 char *cmdline;
1123 int i;
1124 char *cmd;
1125 int *nummatches;
1126 int totmatches;
1127 #ifdef FEAT_QUICKFIX
1128 char cmdletter;
1129 char *qfpos;
1130 #endif
1132 /* create the actual command to send to cscope */
1133 cmd = cs_create_cmd(opt, pat);
1134 if (cmd == NULL)
1135 return FALSE;
1137 nummatches = (int *)alloc(sizeof(int)*csinfo_size);
1138 if (nummatches == NULL)
1139 return FALSE;
1141 /* send query to all open connections, then count the total number
1142 * of matches so we can alloc matchesp all in one swell foop
1144 for (i = 0; i < csinfo_size; i++)
1145 nummatches[i] = 0;
1146 totmatches = 0;
1147 for (i = 0; i < csinfo_size; i++)
1149 if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
1150 continue;
1152 /* send cmd to cscope */
1153 (void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
1154 (void)fflush(csinfo[i].to_fp);
1156 nummatches[i] = cs_cnt_matches(i);
1158 if (nummatches[i] > -1)
1159 totmatches += nummatches[i];
1161 if (nummatches[i] == 0)
1162 (void)cs_read_prompt(i);
1164 vim_free(cmd);
1166 if (totmatches == 0)
1168 char *nf = _("E259: no matches found for cscope query %s of %s");
1169 char *buf;
1171 if (!verbose)
1173 vim_free(nummatches);
1174 return FALSE;
1177 buf = (char *)alloc((unsigned)(strlen(opt) + strlen(pat) + strlen(nf)));
1178 if (buf == NULL)
1179 (void)EMSG(nf);
1180 else
1182 sprintf(buf, nf, opt, pat);
1183 (void)EMSG(buf);
1184 vim_free(buf);
1186 vim_free(nummatches);
1187 return FALSE;
1190 #ifdef FEAT_QUICKFIX
1191 /* get cmd letter */
1192 switch (opt[0])
1194 case '0' :
1195 cmdletter = 's';
1196 break;
1197 case '1' :
1198 cmdletter = 'g';
1199 break;
1200 case '2' :
1201 cmdletter = 'd';
1202 break;
1203 case '3' :
1204 cmdletter = 'c';
1205 break;
1206 case '4' :
1207 cmdletter = 't';
1208 break;
1209 case '6' :
1210 cmdletter = 'e';
1211 break;
1212 case '7' :
1213 cmdletter = 'f';
1214 break;
1215 case '8' :
1216 cmdletter = 'i';
1217 break;
1218 default :
1219 cmdletter = opt[0];
1222 qfpos = (char *)vim_strchr(p_csqf, cmdletter);
1223 if (qfpos != NULL)
1225 qfpos++;
1226 /* next symbol must be +, - or 0 */
1227 if (strchr(CSQF_FLAGS, *qfpos) == NULL)
1229 char *nf = _("E469: invalid cscopequickfix flag %c for %c");
1230 char *buf = (char *)alloc((unsigned)strlen(nf));
1232 /* strlen will be enough because we use chars */
1233 if (buf != NULL)
1235 sprintf(buf, nf, *qfpos, *(qfpos-1));
1236 (void)EMSG(buf);
1237 vim_free(buf);
1239 vim_free(nummatches);
1240 return FALSE;
1243 if (qfpos != NULL && *qfpos != '0' && totmatches > 0)
1245 /* fill error list */
1246 FILE *f;
1247 char_u *tmp = vim_tempname('c');
1248 qf_info_T *qi = NULL;
1249 win_T *wp = NULL;
1251 f = mch_fopen((char *)tmp, "w");
1252 if (f == NULL)
1253 EMSG2(_(e_notopen), tmp);
1254 else
1256 cs_file_results(f, nummatches);
1257 fclose(f);
1258 if (use_ll) /* Use location list */
1259 wp = curwin;
1260 /* '-' starts a new error list */
1261 if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
1262 *qfpos == '-', cmdline) > 0)
1264 # ifdef FEAT_WINDOWS
1265 if (postponed_split != 0)
1267 win_split(postponed_split > 0 ? postponed_split : 0,
1268 postponed_split_flags);
1269 # ifdef FEAT_SCROLLBIND
1270 curwin->w_p_scb = FALSE;
1271 # endif
1272 postponed_split = 0;
1274 # endif
1275 if (use_ll)
1277 * In the location list window, use the displayed location
1278 * list. Otherwise, use the location list for the window.
1280 qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
1281 ? wp->w_llist_ref : wp->w_llist;
1282 qf_jump(qi, 0, 0, forceit);
1285 mch_remove(tmp);
1286 vim_free(tmp);
1287 vim_free(nummatches);
1288 return TRUE;
1290 else
1291 #endif /* FEAT_QUICKFIX */
1293 char **matches = NULL, **contexts = NULL;
1294 int matched = 0;
1296 /* read output */
1297 cs_fill_results((char *)pat, totmatches, nummatches, &matches,
1298 &contexts, &matched);
1299 vim_free(nummatches);
1300 if (matches == NULL)
1301 return FALSE;
1303 (void)cs_manage_matches(matches, contexts, matched, Store);
1305 return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
1308 } /* cs_find_common */
1311 * PRIVATE: cs_help
1313 * print help
1315 static int
1316 cs_help(eap)
1317 exarg_T *eap UNUSED;
1319 cscmd_T *cmdp = cs_cmds;
1321 (void)MSG_PUTS(_("cscope commands:\n"));
1322 while (cmdp->name != NULL)
1324 char *help = _(cmdp->help);
1325 int space_cnt = 30 - vim_strsize((char_u *)help);
1327 /* Use %*s rather than %30s to ensure proper alignment in utf-8 */
1328 if (space_cnt < 0)
1329 space_cnt = 0;
1330 (void)smsg((char_u *)_("%-5s: %s%*s (Usage: %s)"),
1331 cmdp->name,
1332 help, space_cnt, " ",
1333 cmdp->usage);
1334 if (strcmp(cmdp->name, "find") == 0)
1335 MSG_PUTS(_("\n"
1336 " c: Find functions calling this function\n"
1337 " d: Find functions called by this function\n"
1338 " e: Find this egrep pattern\n"
1339 " f: Find this file\n"
1340 " g: Find this definition\n"
1341 " i: Find files #including this file\n"
1342 " s: Find this C symbol\n"
1343 " t: Find assignments to\n"));
1345 cmdp++;
1348 wait_return(TRUE);
1349 return 0;
1350 } /* cs_help */
1353 static void
1354 clear_csinfo(i)
1355 int i;
1357 csinfo[i].fname = NULL;
1358 csinfo[i].ppath = NULL;
1359 csinfo[i].flags = NULL;
1360 #if defined(UNIX)
1361 csinfo[i].st_dev = (dev_t)0;
1362 csinfo[i].st_ino = (ino_t)0;
1363 #else
1364 csinfo[i].nVolume = 0;
1365 csinfo[i].nIndexHigh = 0;
1366 csinfo[i].nIndexLow = 0;
1367 #endif
1368 csinfo[i].pid = 0;
1369 csinfo[i].fr_fp = NULL;
1370 csinfo[i].to_fp = NULL;
1371 #if defined(WIN32)
1372 csinfo[i].hProc = NULL;
1373 #endif
1376 #ifndef UNIX
1377 static char *GetWin32Error __ARGS((void));
1379 static char *
1380 GetWin32Error()
1382 char *msg = NULL;
1383 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
1384 NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL);
1385 if (msg != NULL)
1387 /* remove trailing \r\n */
1388 char *pcrlf = strstr(msg, "\r\n");
1389 if (pcrlf != NULL)
1390 *pcrlf = '\0';
1392 return msg;
1394 #endif
1397 * PRIVATE: cs_insert_filelist
1399 * insert a new cscope database filename into the filelist
1401 static int
1402 cs_insert_filelist(fname, ppath, flags, sb)
1403 char *fname;
1404 char *ppath;
1405 char *flags;
1406 struct stat *sb UNUSED;
1408 short i, j;
1409 #ifndef UNIX
1410 HANDLE hFile;
1411 BY_HANDLE_FILE_INFORMATION bhfi;
1413 vim_memset(&bhfi, 0, sizeof(bhfi));
1414 /* On windows 9x GetFileInformationByHandle doesn't work, so skip it */
1415 if (!mch_windows95())
1417 hFile = CreateFile(fname, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
1418 FILE_ATTRIBUTE_NORMAL, NULL);
1419 if (hFile == INVALID_HANDLE_VALUE)
1421 if (p_csverbose)
1423 char *cant_msg = _("E625: cannot open cscope database: %s");
1424 char *winmsg = GetWin32Error();
1426 if (winmsg != NULL)
1428 (void)EMSG2(cant_msg, winmsg);
1429 LocalFree(winmsg);
1431 else
1432 /* subst filename if can't get error text */
1433 (void)EMSG2(cant_msg, fname);
1435 return -1;
1437 if (!GetFileInformationByHandle(hFile, &bhfi))
1439 CloseHandle(hFile);
1440 if (p_csverbose)
1441 (void)EMSG(_("E626: cannot get cscope database information"));
1442 return -1;
1444 CloseHandle(hFile);
1446 #endif
1448 i = -1; /* can be set to the index of an empty item in csinfo */
1449 for (j = 0; j < csinfo_size; j++)
1451 if (csinfo[j].fname != NULL
1452 #if defined(UNIX)
1453 && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
1454 #else
1455 /* compare pathnames first */
1456 && ((fullpathcmp(csinfo[j].fname, fname, FALSE) & FPC_SAME)
1457 /* if not Windows 9x, test index file attributes too */
1458 || (!mch_windows95()
1459 && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
1460 && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
1461 && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
1462 #endif
1465 if (p_csverbose)
1466 (void)EMSG(_("E568: duplicate cscope database not added"));
1467 return -1;
1470 if (csinfo[j].fname == NULL && i == -1)
1471 i = j; /* remember first empty entry */
1474 if (i == -1)
1476 i = csinfo_size;
1477 if (csinfo_size == 0)
1479 /* First time allocation: allocate only 1 connection. It should
1480 * be enough for most users. If more is needed, csinfo will be
1481 * reallocated. */
1482 csinfo_size = 1;
1483 csinfo = (csinfo_T *)alloc_clear(sizeof(csinfo_T));
1485 else
1487 /* Reallocate space for more connections. */
1488 csinfo_size *= 2;
1489 csinfo = vim_realloc(csinfo, sizeof(csinfo_T)*csinfo_size);
1491 if (csinfo == NULL)
1492 return -1;
1493 for (j = csinfo_size/2; j < csinfo_size; j++)
1494 clear_csinfo(j);
1497 if ((csinfo[i].fname = (char *)alloc((unsigned)strlen(fname)+1)) == NULL)
1498 return -1;
1500 (void)strcpy(csinfo[i].fname, (const char *)fname);
1502 if (ppath != NULL)
1504 if ((csinfo[i].ppath = (char *)alloc((unsigned)strlen(ppath) + 1)) == NULL)
1506 vim_free(csinfo[i].fname);
1507 csinfo[i].fname = NULL;
1508 return -1;
1510 (void)strcpy(csinfo[i].ppath, (const char *)ppath);
1511 } else
1512 csinfo[i].ppath = NULL;
1514 if (flags != NULL)
1516 if ((csinfo[i].flags = (char *)alloc((unsigned)strlen(flags) + 1)) == NULL)
1518 vim_free(csinfo[i].fname);
1519 vim_free(csinfo[i].ppath);
1520 csinfo[i].fname = NULL;
1521 csinfo[i].ppath = NULL;
1522 return -1;
1524 (void)strcpy(csinfo[i].flags, (const char *)flags);
1525 } else
1526 csinfo[i].flags = NULL;
1528 #if defined(UNIX)
1529 csinfo[i].st_dev = sb->st_dev;
1530 csinfo[i].st_ino = sb->st_ino;
1532 #else
1533 csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
1534 csinfo[i].nIndexLow = bhfi.nFileIndexLow;
1535 csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
1536 #endif
1537 return i;
1538 } /* cs_insert_filelist */
1542 * PRIVATE: cs_lookup_cmd
1544 * find cscope command in command table
1546 static cscmd_T *
1547 cs_lookup_cmd(eap)
1548 exarg_T *eap;
1550 cscmd_T *cmdp;
1551 char *stok;
1552 size_t len;
1554 if (eap->arg == NULL)
1555 return NULL;
1557 /* Store length of eap->arg before it gets modified by strtok(). */
1558 eap_arg_len = (int)STRLEN(eap->arg);
1560 if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
1561 return NULL;
1563 len = strlen(stok);
1564 for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp)
1566 if (strncmp((const char *)(stok), cmdp->name, len) == 0)
1567 return (cmdp);
1569 return NULL;
1570 } /* cs_lookup_cmd */
1574 * PRIVATE: cs_kill
1576 * nuke em
1578 static int
1579 cs_kill(eap)
1580 exarg_T *eap UNUSED;
1582 char *stok;
1583 short i;
1585 if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL)
1587 cs_usage_msg(Kill);
1588 return CSCOPE_FAILURE;
1591 /* only single digit positive and negative integers are allowed */
1592 if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0])))
1593 || (strlen(stok) < 3 && stok[0] == '-'
1594 && VIM_ISDIGIT((int)(stok[1]))))
1595 i = atoi(stok);
1596 else
1598 /* It must be part of a name. We will try to find a match
1599 * within all the names in the csinfo data structure
1601 for (i = 0; i < csinfo_size; i++)
1603 if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
1604 break;
1608 if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL))
1610 if (p_csverbose)
1611 (void)EMSG2(_("E261: cscope connection %s not found"), stok);
1613 else
1615 if (i == -1)
1617 for (i = 0; i < csinfo_size; i++)
1619 if (csinfo[i].fname)
1620 cs_kill_execute(i, csinfo[i].fname);
1623 else
1624 cs_kill_execute(i, stok);
1627 return 0;
1628 } /* cs_kill */
1632 * PRIVATE: cs_kill_execute
1634 * Actually kills a specific cscope connection.
1636 static void
1637 cs_kill_execute(i, cname)
1638 int i; /* cscope table index */
1639 char *cname; /* cscope database name */
1641 if (p_csverbose)
1643 msg_clr_eos();
1644 (void)smsg_attr(hl_attr(HLF_R) | MSG_HIST,
1645 (char_u *)_("cscope connection %s closed"), cname);
1647 cs_release_csp(i, TRUE);
1652 * PRIVATE: cs_make_vim_style_matches
1654 * convert the cscope output into into a ctags style entry (as might be found
1655 * in a ctags tags file). there's one catch though: cscope doesn't tell you
1656 * the type of the tag you are looking for. for example, in Darren Hiebert's
1657 * ctags (the one that comes with vim), #define's use a line number to find the
1658 * tag in a file while function definitions use a regexp search pattern.
1660 * i'm going to always use the line number because cscope does something
1661 * quirky (and probably other things i don't know about):
1663 * if you have "# define" in your source file, which is
1664 * perfectly legal, cscope thinks you have "#define". this
1665 * will result in a failed regexp search. :(
1667 * besides, even if this particular case didn't happen, the search pattern
1668 * would still have to be modified to escape all the special regular expression
1669 * characters to comply with ctags formatting.
1671 static char *
1672 cs_make_vim_style_matches(fname, slno, search, tagstr)
1673 char *fname;
1674 char *slno;
1675 char *search;
1676 char *tagstr;
1678 /* vim style is ctags:
1680 * <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
1682 * but as mentioned above, we'll always use the line number and
1683 * put the search pattern (if one exists) as "extra"
1685 * buf is used as part of vim's method of handling tags, and
1686 * (i think) vim frees it when you pop your tags and get replaced
1687 * by new ones on the tag stack.
1689 char *buf;
1690 int amt;
1692 if (search != NULL)
1694 amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6);
1695 if ((buf = (char *)alloc(amt)) == NULL)
1696 return NULL;
1698 (void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
1700 else
1702 amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + 5);
1703 if ((buf = (char *)alloc(amt)) == NULL)
1704 return NULL;
1706 (void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
1709 return buf;
1710 } /* cs_make_vim_style_matches */
1714 * PRIVATE: cs_manage_matches
1716 * this is kind of hokey, but i don't see an easy way round this..
1718 * Store: keep a ptr to the (malloc'd) memory of matches originally
1719 * generated from cs_find(). the matches are originally lines directly
1720 * from cscope output, but transformed to look like something out of a
1721 * ctags. see cs_make_vim_style_matches for more details.
1723 * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
1724 * the next line from the cscope output. it basically keeps track of which
1725 * lines have been "used" and returns the next one.
1727 * Free: frees up everything and resets
1729 * Print: prints the tags
1731 static char *
1732 cs_manage_matches(matches, contexts, totmatches, cmd)
1733 char **matches;
1734 char **contexts;
1735 int totmatches;
1736 mcmd_e cmd;
1738 static char **mp = NULL;
1739 static char **cp = NULL;
1740 static int cnt = -1;
1741 static int next = -1;
1742 char *p = NULL;
1744 switch (cmd)
1746 case Store:
1747 assert(matches != NULL);
1748 assert(totmatches > 0);
1749 if (mp != NULL || cp != NULL)
1750 (void)cs_manage_matches(NULL, NULL, -1, Free);
1751 mp = matches;
1752 cp = contexts;
1753 cnt = totmatches;
1754 next = 0;
1755 break;
1756 case Get:
1757 if (next >= cnt)
1758 return NULL;
1760 p = mp[next];
1761 next++;
1762 break;
1763 case Free:
1764 if (mp != NULL)
1766 if (cnt > 0)
1767 while (cnt--)
1769 vim_free(mp[cnt]);
1770 if (cp != NULL)
1771 vim_free(cp[cnt]);
1773 vim_free(mp);
1774 vim_free(cp);
1776 mp = NULL;
1777 cp = NULL;
1778 cnt = 0;
1779 next = 0;
1780 break;
1781 case Print:
1782 cs_print_tags_priv(mp, cp, cnt);
1783 break;
1784 default: /* should not reach here */
1785 (void)EMSG(_("E570: fatal error in cs_manage_matches"));
1786 return NULL;
1789 return p;
1790 } /* cs_manage_matches */
1794 * PRIVATE: cs_parse_results
1796 * parse cscope output
1798 static char *
1799 cs_parse_results(cnumber, buf, bufsize, context, linenumber, search)
1800 int cnumber;
1801 char *buf;
1802 int bufsize;
1803 char **context;
1804 char **linenumber;
1805 char **search;
1807 int ch;
1808 char *p;
1809 char *name;
1811 if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL)
1813 if (feof(csinfo[cnumber].fr_fp))
1814 errno = EIO;
1816 cs_reading_emsg(cnumber);
1818 return NULL;
1821 /* If the line's too long for the buffer, discard it. */
1822 if ((p = strchr(buf, '\n')) == NULL)
1824 while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
1826 return NULL;
1828 *p = '\0';
1831 * cscope output is in the following format:
1833 * <filename> <context> <line number> <pattern>
1835 if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
1836 return NULL;
1837 if ((*context = strtok(NULL, (const char *)" ")) == NULL)
1838 return NULL;
1839 if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
1840 return NULL;
1841 *search = *linenumber + strlen(*linenumber) + 1; /* +1 to skip \0 */
1843 /* --- nvi ---
1844 * If the file is older than the cscope database, that is,
1845 * the database was built since the file was last modified,
1846 * or there wasn't a search string, use the line number.
1848 if (strcmp(*search, "<unknown>") == 0)
1849 *search = NULL;
1851 name = cs_resolve_file(cnumber, name);
1852 return name;
1855 #ifdef FEAT_QUICKFIX
1857 * PRIVATE: cs_file_results
1859 * write cscope find results to file
1861 static void
1862 cs_file_results(f, nummatches_a)
1863 FILE *f;
1864 int *nummatches_a;
1866 int i, j;
1867 char *buf;
1868 char *search, *slno;
1869 char *fullname;
1870 char *cntx;
1871 char *context;
1873 buf = (char *)alloc(CSREAD_BUFSIZE);
1874 if (buf == NULL)
1875 return;
1877 for (i = 0; i < csinfo_size; i++)
1879 if (nummatches_a[i] < 1)
1880 continue;
1882 for (j = 0; j < nummatches_a[i]; j++)
1884 if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1885 &slno, &search)) == NULL)
1886 continue;
1888 context = (char *)alloc((unsigned)strlen(cntx)+5);
1889 if (context == NULL)
1890 continue;
1892 if (strcmp(cntx, "<global>")==0)
1893 strcpy(context, "<<global>>");
1894 else
1895 sprintf(context, "<<%s>>", cntx);
1897 if (search == NULL)
1898 fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
1899 else
1900 fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
1902 vim_free(context);
1903 vim_free(fullname);
1904 } /* for all matches */
1906 (void)cs_read_prompt(i);
1908 } /* for all cscope connections */
1909 vim_free(buf);
1911 #endif
1914 * PRIVATE: cs_fill_results
1916 * get parsed cscope output and calls cs_make_vim_style_matches to convert
1917 * into ctags format
1918 * When there are no matches sets "*matches_p" to NULL.
1920 static void
1921 cs_fill_results(tagstr, totmatches, nummatches_a, matches_p, cntxts_p, matched)
1922 char *tagstr;
1923 int totmatches;
1924 int *nummatches_a;
1925 char ***matches_p;
1926 char ***cntxts_p;
1927 int *matched;
1929 int i, j;
1930 char *buf;
1931 char *search, *slno;
1932 int totsofar = 0;
1933 char **matches = NULL;
1934 char **cntxts = NULL;
1935 char *fullname;
1936 char *cntx;
1938 assert(totmatches > 0);
1940 buf = (char *)alloc(CSREAD_BUFSIZE);
1941 if (buf == NULL)
1942 return;
1944 if ((matches = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
1945 goto parse_out;
1946 if ((cntxts = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
1947 goto parse_out;
1949 for (i = 0; i < csinfo_size; i++)
1951 if (nummatches_a[i] < 1)
1952 continue;
1954 for (j = 0; j < nummatches_a[i]; j++)
1956 if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1957 &slno, &search)) == NULL)
1958 continue;
1960 matches[totsofar] = cs_make_vim_style_matches(fullname, slno,
1961 search, tagstr);
1963 vim_free(fullname);
1965 if (strcmp(cntx, "<global>") == 0)
1966 cntxts[totsofar] = NULL;
1967 else
1968 /* note: if vim_strsave returns NULL, then the context
1969 * will be "<global>", which is misleading.
1971 cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
1973 if (matches[totsofar] != NULL)
1974 totsofar++;
1976 } /* for all matches */
1978 (void)cs_read_prompt(i);
1980 } /* for all cscope connections */
1982 parse_out:
1983 if (totsofar == 0)
1985 /* No matches, free the arrays and return NULL in "*matches_p". */
1986 vim_free(matches);
1987 matches = NULL;
1988 vim_free(cntxts);
1989 cntxts = NULL;
1991 *matched = totsofar;
1992 *matches_p = matches;
1993 *cntxts_p = cntxts;
1995 vim_free(buf);
1996 } /* cs_fill_results */
1999 /* get the requested path components */
2000 static char *
2001 cs_pathcomponents(path)
2002 char *path;
2004 int i;
2005 char *s;
2007 if (p_cspc == 0)
2008 return path;
2010 s = path + strlen(path) - 1;
2011 for (i = 0; i < p_cspc; ++i)
2012 while (s > path && *--s != '/'
2013 #ifdef WIN32
2014 && *--s != '\\'
2015 #endif
2018 if ((s > path && *s == '/')
2019 #ifdef WIN32
2020 || (s > path && *s == '\\')
2021 #endif
2023 ++s;
2024 return s;
2028 * PRIVATE: cs_print_tags_priv
2030 * called from cs_manage_matches()
2032 static void
2033 cs_print_tags_priv(matches, cntxts, num_matches)
2034 char **matches;
2035 char **cntxts;
2036 int num_matches;
2038 char *buf = NULL;
2039 int bufsize = 0; /* Track available bufsize */
2040 int newsize = 0;
2041 char *ptag;
2042 char *fname, *lno, *extra, *tbuf;
2043 int i, idx, num;
2044 char *globalcntx = "GLOBAL";
2045 char *cntxformat = " <<%s>>";
2046 char *context;
2047 char *cstag_msg = _("Cscope tag: %s");
2048 char *csfmt_str = "%4d %6s ";
2050 assert (num_matches > 0);
2052 if ((tbuf = (char *)alloc((unsigned)strlen(matches[0]) + 1)) == NULL)
2053 return;
2055 strcpy(tbuf, matches[0]);
2056 ptag = strtok(tbuf, "\t");
2058 newsize = (int)(strlen(cstag_msg) + strlen(ptag));
2059 buf = (char *)alloc(newsize);
2060 if (buf != NULL)
2062 bufsize = newsize;
2063 (void)sprintf(buf, cstag_msg, ptag);
2064 MSG_PUTS_ATTR(buf, hl_attr(HLF_T));
2067 vim_free(tbuf);
2069 MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T)); /* strlen is 7 */
2070 msg_advance(msg_col + 2);
2071 MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T));
2073 num = 1;
2074 for (i = 0; i < num_matches; i++)
2076 idx = i;
2078 /* if we really wanted to, we could avoid this malloc and strcpy
2079 * by parsing matches[i] on the fly and placing stuff into buf
2080 * directly, but that's too much of a hassle
2082 if ((tbuf = (char *)alloc((unsigned)strlen(matches[idx]) + 1)) == NULL)
2083 continue;
2084 (void)strcpy(tbuf, matches[idx]);
2086 if (strtok(tbuf, (const char *)"\t") == NULL)
2087 continue;
2088 if ((fname = strtok(NULL, (const char *)"\t")) == NULL)
2089 continue;
2090 if ((lno = strtok(NULL, (const char *)"\t")) == NULL)
2091 continue;
2092 extra = strtok(NULL, (const char *)"\t");
2094 lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */
2096 /* hopefully 'num' (num of matches) will be less than 10^16 */
2097 newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno));
2098 if (bufsize < newsize)
2100 buf = (char *)vim_realloc(buf, newsize);
2101 if (buf == NULL)
2102 bufsize = 0;
2103 else
2104 bufsize = newsize;
2106 if (buf != NULL)
2108 /* csfmt_str = "%4d %6s "; */
2109 (void)sprintf(buf, csfmt_str, num, lno);
2110 MSG_PUTS_ATTR(buf, hl_attr(HLF_CM));
2112 MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM));
2114 /* compute the required space for the context */
2115 if (cntxts[idx] != NULL)
2116 context = cntxts[idx];
2117 else
2118 context = globalcntx;
2119 newsize = (int)(strlen(context) + strlen(cntxformat));
2121 if (bufsize < newsize)
2123 buf = (char *)vim_realloc(buf, newsize);
2124 if (buf == NULL)
2125 bufsize = 0;
2126 else
2127 bufsize = newsize;
2129 if (buf != NULL)
2131 (void)sprintf(buf, cntxformat, context);
2133 /* print the context only if it fits on the same line */
2134 if (msg_col + (int)strlen(buf) >= (int)Columns)
2135 msg_putchar('\n');
2136 msg_advance(12);
2137 MSG_PUTS_LONG(buf);
2138 msg_putchar('\n');
2140 if (extra != NULL)
2142 msg_advance(13);
2143 MSG_PUTS_LONG(extra);
2146 vim_free(tbuf); /* only after printing extra due to strtok use */
2148 if (msg_col)
2149 msg_putchar('\n');
2151 ui_breakcheck();
2152 if (got_int)
2154 got_int = FALSE; /* don't print any more matches */
2155 break;
2158 num++;
2159 } /* for all matches */
2161 vim_free(buf);
2162 } /* cs_print_tags_priv */
2166 * PRIVATE: cs_read_prompt
2168 * read a cscope prompt (basically, skip over the ">> ")
2170 static int
2171 cs_read_prompt(i)
2172 int i;
2174 int ch;
2175 char *buf = NULL; /* buffer for possible error message from cscope */
2176 int bufpos = 0;
2177 char *cs_emsg;
2178 int maxlen;
2179 static char *eprompt = "Press the RETURN key to continue:";
2180 int epromptlen = (int)strlen(eprompt);
2181 int n;
2183 cs_emsg = _("E609: Cscope error: %s");
2184 /* compute maximum allowed len for Cscope error message */
2185 maxlen = (int)(IOSIZE - strlen(cs_emsg));
2187 for (;;)
2189 while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
2190 /* if there is room and char is printable */
2191 if (bufpos < maxlen - 1 && vim_isprintc(ch))
2193 if (buf == NULL) /* lazy buffer allocation */
2194 buf = (char *)alloc(maxlen);
2195 if (buf != NULL)
2197 /* append character to the message */
2198 buf[bufpos++] = ch;
2199 buf[bufpos] = NUL;
2200 if (bufpos >= epromptlen
2201 && strcmp(&buf[bufpos - epromptlen], eprompt) == 0)
2203 /* remove eprompt from buf */
2204 buf[bufpos - epromptlen] = NUL;
2206 /* print message to user */
2207 (void)EMSG2(cs_emsg, buf);
2209 /* send RETURN to cscope */
2210 (void)putc('\n', csinfo[i].to_fp);
2211 (void)fflush(csinfo[i].to_fp);
2213 /* clear buf */
2214 bufpos = 0;
2215 buf[bufpos] = NUL;
2220 for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n)
2222 if (n > 0)
2223 ch = getc(csinfo[i].fr_fp);
2224 if (ch == EOF)
2226 PERROR("cs_read_prompt EOF");
2227 if (buf != NULL && buf[0] != NUL)
2228 (void)EMSG2(cs_emsg, buf);
2229 else if (p_csverbose)
2230 cs_reading_emsg(i); /* don't have additional information */
2231 cs_release_csp(i, TRUE);
2232 vim_free(buf);
2233 return CSCOPE_FAILURE;
2236 if (ch != CSCOPE_PROMPT[n])
2238 ch = EOF;
2239 break;
2243 if (ch == EOF)
2244 continue; /* didn't find the prompt */
2245 break; /* did find the prompt */
2248 vim_free(buf);
2249 return CSCOPE_SUCCESS;
2252 #if defined(UNIX) && defined(SIGALRM)
2254 * Used to catch and ignore SIGALRM below.
2256 static RETSIGTYPE
2257 sig_handler SIGDEFARG(sigarg)
2259 /* do nothing */
2260 SIGRETURN;
2262 #endif
2265 * PRIVATE: cs_release_csp
2267 * Does the actual free'ing for the cs ptr with an optional flag of whether
2268 * or not to free the filename. Called by cs_kill and cs_reset.
2270 static void
2271 cs_release_csp(i, freefnpp)
2272 int i;
2273 int freefnpp;
2276 * Trying to exit normally (not sure whether it is fit to UNIX cscope
2278 if (csinfo[i].to_fp != NULL)
2280 (void)fputs("q\n", csinfo[i].to_fp);
2281 (void)fflush(csinfo[i].to_fp);
2283 #if defined(UNIX)
2285 int waitpid_errno;
2286 int pstat;
2287 pid_t pid;
2289 # if defined(HAVE_SIGACTION)
2290 struct sigaction sa, old;
2292 /* Use sigaction() to limit the waiting time to two seconds. */
2293 sigemptyset(&sa.sa_mask);
2294 sa.sa_handler = sig_handler;
2295 # ifdef SA_NODEFER
2296 sa.sa_flags = SA_NODEFER;
2297 # else
2298 sa.sa_flags = 0;
2299 # endif
2300 sigaction(SIGALRM, &sa, &old);
2301 alarm(2); /* 2 sec timeout */
2303 /* Block until cscope exits or until timer expires */
2304 pid = waitpid(csinfo[i].pid, &pstat, 0);
2305 waitpid_errno = errno;
2307 /* cancel pending alarm if still there and restore signal */
2308 alarm(0);
2309 sigaction(SIGALRM, &old, NULL);
2310 # else
2311 int waited;
2313 /* Can't use sigaction(), loop for two seconds. First yield the CPU
2314 * to give cscope a chance to exit quickly. */
2315 sleep(0);
2316 for (waited = 0; waited < 40; ++waited)
2318 pid = waitpid(csinfo[i].pid, &pstat, WNOHANG);
2319 waitpid_errno = errno;
2320 if (pid != 0)
2321 break; /* break unless the process is still running */
2322 mch_delay(50L, FALSE); /* sleep 50 ms */
2324 # endif
2326 * If the cscope process is still running: kill it.
2327 * Safety check: If the PID would be zero here, the entire X session
2328 * would be killed. -1 and 1 are dangerous as well.
2330 if (pid < 0 && csinfo[i].pid > 1)
2332 # ifdef ECHILD
2333 int alive = TRUE;
2335 if (waitpid_errno == ECHILD)
2338 * When using 'vim -g', vim is forked and cscope process is
2339 * no longer a child process but a sibling. So waitpid()
2340 * fails with errno being ECHILD (No child processes).
2341 * Don't send SIGKILL to cscope immediately but wait
2342 * (polling) for it to exit normally as result of sending
2343 * the "q" command, hence giving it a chance to clean up
2344 * its temporary files.
2346 int waited;
2348 sleep(0);
2349 for (waited = 0; waited < 40; ++waited)
2351 /* Check whether cscope process is still alive */
2352 if (kill(csinfo[i].pid, 0) != 0)
2354 alive = FALSE; /* cscope process no longer exists */
2355 break;
2357 mch_delay(50L, FALSE); /* sleep 50ms */
2360 if (alive)
2361 # endif
2363 kill(csinfo[i].pid, SIGKILL);
2364 (void)waitpid(csinfo[i].pid, &pstat, 0);
2368 #else /* !UNIX */
2369 if (csinfo[i].hProc != NULL)
2371 /* Give cscope a chance to exit normally */
2372 if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
2373 TerminateProcess(csinfo[i].hProc, 0);
2374 CloseHandle(csinfo[i].hProc);
2376 #endif
2378 if (csinfo[i].fr_fp != NULL)
2379 (void)fclose(csinfo[i].fr_fp);
2380 if (csinfo[i].to_fp != NULL)
2381 (void)fclose(csinfo[i].to_fp);
2383 if (freefnpp)
2385 vim_free(csinfo[i].fname);
2386 vim_free(csinfo[i].ppath);
2387 vim_free(csinfo[i].flags);
2390 clear_csinfo(i);
2391 } /* cs_release_csp */
2395 * PRIVATE: cs_reset
2397 * calls cs_kill on all cscope connections then reinits
2399 static int
2400 cs_reset(eap)
2401 exarg_T *eap UNUSED;
2403 char **dblist = NULL, **pplist = NULL, **fllist = NULL;
2404 int i;
2405 char buf[20]; /* for sprintf " (#%d)" */
2407 if (csinfo_size == 0)
2408 return CSCOPE_SUCCESS;
2410 /* malloc our db and ppath list */
2411 dblist = (char **)alloc(csinfo_size * sizeof(char *));
2412 pplist = (char **)alloc(csinfo_size * sizeof(char *));
2413 fllist = (char **)alloc(csinfo_size * sizeof(char *));
2414 if (dblist == NULL || pplist == NULL || fllist == NULL)
2416 vim_free(dblist);
2417 vim_free(pplist);
2418 vim_free(fllist);
2419 return CSCOPE_FAILURE;
2422 for (i = 0; i < csinfo_size; i++)
2424 dblist[i] = csinfo[i].fname;
2425 pplist[i] = csinfo[i].ppath;
2426 fllist[i] = csinfo[i].flags;
2427 if (csinfo[i].fname != NULL)
2428 cs_release_csp(i, FALSE);
2431 /* rebuild the cscope connection list */
2432 for (i = 0; i < csinfo_size; i++)
2434 if (dblist[i] != NULL)
2436 cs_add_common(dblist[i], pplist[i], fllist[i]);
2437 if (p_csverbose)
2439 /* don't use smsg_attr() because we want to display the
2440 * connection number in the same line as
2441 * "Added cscope database..."
2443 sprintf(buf, " (#%d)", i);
2444 MSG_PUTS_ATTR(buf, hl_attr(HLF_R));
2447 vim_free(dblist[i]);
2448 vim_free(pplist[i]);
2449 vim_free(fllist[i]);
2451 vim_free(dblist);
2452 vim_free(pplist);
2453 vim_free(fllist);
2455 if (p_csverbose)
2456 MSG_ATTR(_("All cscope databases reset"), hl_attr(HLF_R) | MSG_HIST);
2457 return CSCOPE_SUCCESS;
2458 } /* cs_reset */
2462 * PRIVATE: cs_resolve_file
2464 * construct the full pathname to a file found in the cscope database.
2465 * (Prepends ppath, if there is one and if it's not already prepended,
2466 * otherwise just uses the name found.)
2468 * we need to prepend the prefix because on some cscope's (e.g., the one that
2469 * ships with Solaris 2.6), the output never has the prefix prepended.
2470 * contrast this with my development system (Digital Unix), which does.
2472 static char *
2473 cs_resolve_file(i, name)
2474 int i;
2475 char *name;
2477 char *fullname;
2478 int len;
2481 * ppath is freed when we destroy the cscope connection.
2482 * fullname is freed after cs_make_vim_style_matches, after it's been
2483 * copied into the tag buffer used by vim
2485 len = (int)(strlen(name) + 2);
2486 if (csinfo[i].ppath != NULL)
2487 len += (int)strlen(csinfo[i].ppath);
2489 if ((fullname = (char *)alloc(len)) == NULL)
2490 return NULL;
2493 * note/example: this won't work if the cscope output already starts
2494 * "../.." and the prefix path is also "../..". if something like this
2495 * happens, you are screwed up and need to fix how you're using cscope.
2497 if (csinfo[i].ppath != NULL &&
2498 (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) &&
2499 (name[0] != '/')
2500 #ifdef WIN32
2501 && name[0] != '\\' && name[1] != ':'
2502 #endif
2504 (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
2505 else
2506 (void)sprintf(fullname, "%s", name);
2508 return fullname;
2509 } /* cs_resolve_file */
2513 * PRIVATE: cs_show
2515 * show all cscope connections
2517 static int
2518 cs_show(eap)
2519 exarg_T *eap UNUSED;
2521 short i;
2522 if (cs_cnt_connections() == 0)
2523 MSG_PUTS(_("no cscope connections\n"));
2524 else
2526 MSG_PUTS_ATTR(
2527 _(" # pid database name prepend path\n"),
2528 hl_attr(HLF_T));
2529 for (i = 0; i < csinfo_size; i++)
2531 if (csinfo[i].fname == NULL)
2532 continue;
2534 if (csinfo[i].ppath != NULL)
2535 (void)smsg((char_u *)"%2d %-5ld %-34s %-32s",
2536 i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
2537 else
2538 (void)smsg((char_u *)"%2d %-5ld %-34s <none>",
2539 i, (long)csinfo[i].pid, csinfo[i].fname);
2543 wait_return(TRUE);
2544 return CSCOPE_SUCCESS;
2545 } /* cs_show */
2549 * PUBLIC: cs_end
2551 * Only called when VIM exits to quit any cscope sessions.
2553 void
2554 cs_end()
2556 int i;
2558 for (i = 0; i < csinfo_size; i++)
2559 cs_release_csp(i, TRUE);
2560 vim_free(csinfo);
2561 csinfo_size = 0;
2564 #endif /* FEAT_CSCOPE */
2566 /* the end */