xref: /vim-8.2.3635/src/if_cscope.c (revision 00a927d6)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * CSCOPE support for Vim added by Andy Kahn <[email protected]>
4  * Ported to Win32 by Sergey Khorev <[email protected]>
5  *
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.
8  *
9  * See README.txt for an overview of the Vim source code.
10  */
11 
12 #include "vim.h"
13 
14 #if defined(FEAT_CSCOPE) || defined(PROTO)
15 
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"
28 
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));
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));
66 
67 
68 static csinfo_T *   csinfo = NULL;
69 static int	    csinfo_size = 0;	/* number of items allocated in
70 					   csinfo[] */
71 
72 static int	    eap_arg_len;    /* length of eap->arg, set in
73 				       cs_lookup_cmd() */
74 static cscmd_T	    cs_cmds[] =
75 {
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 }
89 };
90 
91     static void
92 cs_usage_msg(x)
93     csid_e x;
94 {
95     (void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
96 }
97 
98 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
99 
100 static enum
101 {
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;
107 
108 /*
109  * Function given to ExpandGeneric() to obtain the cscope command
110  * expansion.
111  */
112     char_u *
113 get_cscope_name(xp, idx)
114     expand_T	*xp UNUSED;
115     int		idx;
116 {
117     int		current_idx;
118     int		i;
119 
120     switch (expand_what)
121     {
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:
135 	{
136 	    const char *query_type[] =
137 	    {
138 		"c", "d", "e", "f", "g", "i", "s", "t", NULL
139 	    };
140 
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];
146 	}
147     case EXP_CSCOPE_KILL:
148 	{
149 	    static char	connection[5];
150 
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++)
156 	    {
157 		if (csinfo[i].fname == NULL)
158 		    continue;
159 		if (current_idx++ == idx)
160 		{
161 		    vim_snprintf(connection, sizeof(connection), "%d", i);
162 		    return (char_u *)connection;
163 		}
164 	    }
165 	    return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
166 	}
167     default:
168 	return NULL;
169     }
170 }
171 
172 /*
173  * Handle command line completion for :cscope command.
174  */
175     void
176 set_context_in_cscope_cmd(xp, arg, cmdidx)
177     expand_T	*xp;
178     char_u	*arg;
179     cmdidx_T	cmdidx;
180 {
181     char_u	*p;
182 
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;
188 
189     /* (part of) subcommand already typed */
190     if (*arg != NUL)
191     {
192 	p = skiptowhite(arg);
193 	if (*p != NUL)		    /* past first word */
194 	{
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;
206 	}
207     }
208 }
209 
210 #endif /* FEAT_CMDL_COMPL */
211 
212 /*
213  * PRIVATE: do_cscope_general
214  *
215  * Find the command, print help if invalid, and then call the corresponding
216  * command function.
217  */
218     static void
219 do_cscope_general(eap, make_split)
220     exarg_T	*eap;
221     int		make_split; /* whether to split window */
222 {
223     cscmd_T *cmdp;
224 
225     if ((cmdp = cs_lookup_cmd(eap)) == NULL)
226     {
227 	cs_help(eap);
228 	return;
229     }
230 
231 #ifdef FEAT_WINDOWS
232     if (make_split)
233     {
234 	if (!cmdp->cansplit)
235 	{
236 	    (void)MSG_PUTS(_("This cscope command does not support splitting the window.\n"));
237 	    return;
238 	}
239 	postponed_split = -1;
240 	postponed_split_flags = cmdmod.split;
241 	postponed_split_tab = cmdmod.tab;
242     }
243 #endif
244 
245     cmdp->func(eap);
246 
247 #ifdef FEAT_WINDOWS
248     postponed_split_flags = 0;
249     postponed_split_tab = 0;
250 #endif
251 }
252 
253 /*
254  * PUBLIC: do_cscope
255  */
256     void
257 do_cscope(eap)
258     exarg_T *eap;
259 {
260     do_cscope_general(eap, FALSE);
261 }
262 
263 /*
264  * PUBLIC: do_scscope
265  *
266  * same as do_cscope, but splits window, too.
267  */
268     void
269 do_scscope(eap)
270     exarg_T *eap;
271 {
272     do_cscope_general(eap, TRUE);
273 }
274 
275 /*
276  * PUBLIC: do_cstag
277  *
278  */
279     void
280 do_cstag(eap)
281     exarg_T *eap;
282 {
283     int ret = FALSE;
284 
285     if (*eap->arg == NUL)
286     {
287 	(void)EMSG(_("E562: Usage: cstag <ident>"));
288 	return;
289     }
290 
291     switch (p_csto)
292     {
293     case 0 :
294 	if (cs_check_for_connections())
295 	{
296 	    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
297 				 FALSE);
298 	    if (ret == FALSE)
299 	    {
300 		cs_free_tags();
301 		if (msg_col)
302 		    msg_putchar('\n');
303 
304 		if (cs_check_for_tags())
305 		    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
306 	    }
307 	}
308 	else if (cs_check_for_tags())
309 	{
310 	    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
311 	}
312 	break;
313     case 1 :
314 	if (cs_check_for_tags())
315 	{
316 	    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
317 	    if (ret == FALSE)
318 	    {
319 		if (msg_col)
320 		    msg_putchar('\n');
321 
322 		if (cs_check_for_connections())
323 		{
324 		    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
325 					 FALSE, FALSE);
326 		    if (ret == FALSE)
327 			cs_free_tags();
328 		}
329 	    }
330 	}
331 	else if (cs_check_for_connections())
332 	{
333 	    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
334 				 FALSE);
335 	    if (ret == FALSE)
336 		cs_free_tags();
337 	}
338 	break;
339     default :
340 	break;
341     }
342 
343     if (!ret)
344     {
345 	(void)EMSG(_("E257: cstag: tag not found"));
346 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
347 	g_do_tagpreview = 0;
348 #endif
349     }
350 
351 } /* do_cscope */
352 
353 
354 /*
355  * PUBLIC: cs_find
356  *
357  * this simulates a vim_fgets(), but for cscope, returns the next line
358  * from the cscope output.  should only be called from find_tags()
359  *
360  * returns TRUE if eof, FALSE otherwise
361  */
362     int
363 cs_fgets(buf, size)
364     char_u	*buf;
365     int		size;
366 {
367     char *p;
368 
369     if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
370 	return TRUE;
371     vim_strncpy(buf, (char_u *)p, size - 1);
372 
373     return FALSE;
374 } /* cs_fgets */
375 
376 
377 /*
378  * PUBLIC: cs_free_tags
379  *
380  * called only from do_tag(), when popping the tag stack
381  */
382     void
383 cs_free_tags()
384 {
385     cs_manage_matches(NULL, NULL, -1, Free);
386 }
387 
388 
389 /*
390  * PUBLIC: cs_print_tags
391  *
392  * called from do_tag()
393  */
394     void
395 cs_print_tags()
396 {
397     cs_manage_matches(NULL, NULL, -1, Print);
398 }
399 
400 
401 /*
402  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
403  *
404  *		Checks for the existence of a |cscope| connection.  If no
405  *		parameters are specified, then the function returns:
406  *
407  *		0, if cscope was not available (not compiled in), or if there
408  *		are no cscope connections; or
409  *		1, if there is at least one cscope connection.
410  *
411  *		If parameters are specified, then the value of {num}
412  *		determines how existence of a cscope connection is checked:
413  *
414  *		{num}	Description of existence check
415  *		-----	------------------------------
416  *		0	Same as no parameters (e.g., "cscope_connection()").
417  *		1	Ignore {prepend}, and use partial string matches for
418  *			{dbpath}.
419  *		2	Ignore {prepend}, and use exact string matches for
420  *			{dbpath}.
421  *		3	Use {prepend}, use partial string matches for both
422  *			{dbpath} and {prepend}.
423  *		4	Use {prepend}, use exact string matches for both
424  *			{dbpath} and {prepend}.
425  *
426  *		Note: All string comparisons are case sensitive!
427  */
428 #if defined(FEAT_EVAL) || defined(PROTO)
429     int
430 cs_connection(num, dbpath, ppath)
431     int num;
432     char_u *dbpath;
433     char_u *ppath;
434 {
435     int i;
436 
437     if (num < 0 || num > 4 || (num > 0 && !dbpath))
438 	return FALSE;
439 
440     for (i = 0; i < csinfo_size; i++)
441     {
442 	if (!csinfo[i].fname)
443 	    continue;
444 
445 	if (num == 0)
446 	    return TRUE;
447 
448 	switch (num)
449 	{
450 	case 1:
451 	    if (strstr(csinfo[i].fname, (char *)dbpath))
452 		return TRUE;
453 	    break;
454 	case 2:
455 	    if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
456 		return TRUE;
457 	    break;
458 	case 3:
459 	    if (strstr(csinfo[i].fname, (char *)dbpath)
460 		    && ((!ppath && !csinfo[i].ppath)
461 			|| (ppath
462 			    && csinfo[i].ppath
463 			    && strstr(csinfo[i].ppath, (char *)ppath))))
464 		return TRUE;
465 	    break;
466 	case 4:
467 	    if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
468 		    && ((!ppath && !csinfo[i].ppath)
469 			|| (ppath
470 			    && csinfo[i].ppath
471 			    && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
472 		return TRUE;
473 	    break;
474 	}
475     }
476 
477     return FALSE;
478 } /* cs_connection */
479 #endif
480 
481 
482 /*
483  * PRIVATE functions
484  ****************************************************************************/
485 
486 /*
487  * PRIVATE: cs_add
488  *
489  * add cscope database or a directory name (to look for cscope.out)
490  * to the cscope connection list
491  *
492  * MAXPATHL 256
493  */
494     static int
495 cs_add(eap)
496     exarg_T *eap UNUSED;
497 {
498     char *fname, *ppath, *flags = NULL;
499 
500     if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL)
501     {
502 	cs_usage_msg(Add);
503 	return CSCOPE_FAILURE;
504     }
505     if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
506 	flags = strtok((char *)NULL, (const char *)" ");
507 
508     return cs_add_common(fname, ppath, flags);
509 }
510 
511     static void
512 cs_stat_emsg(fname)
513     char *fname;
514 {
515     char *stat_emsg = _("E563: stat(%s) error: %d");
516     char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10);
517 
518     if (buf != NULL)
519     {
520 	(void)sprintf(buf, stat_emsg, fname, errno);
521 	(void)EMSG(buf);
522 	vim_free(buf);
523     }
524     else
525 	(void)EMSG(_("E563: stat error"));
526 }
527 
528 
529 /*
530  * PRIVATE: cs_add_common
531  *
532  * the common routine to add a new cscope connection.  called by
533  * cs_add() and cs_reset().  i really don't like to do this, but this
534  * routine uses a number of goto statements.
535  */
536     static int
537 cs_add_common(arg1, arg2, flags)
538     char *arg1;	    /* filename - may contain environment variables */
539     char *arg2;	    /* prepend path - may contain environment variables */
540     char *flags;
541 {
542     struct stat statbuf;
543     int		ret;
544     char	*fname = NULL;
545     char	*fname2 = NULL;
546     char	*ppath = NULL;
547     int		i;
548 
549     /* get the filename (arg1), expand it, and try to stat it */
550     if ((fname = (char *)alloc(MAXPATHL + 1)) == NULL)
551 	goto add_err;
552 
553     expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
554     ret = stat(fname, &statbuf);
555     if (ret < 0)
556     {
557 staterr:
558 	if (p_csverbose)
559 	    cs_stat_emsg(fname);
560 	goto add_err;
561     }
562 
563     /* get the prepend path (arg2), expand it, and try to stat it */
564     if (arg2 != NULL)
565     {
566 	struct stat statbuf2;
567 
568 	if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
569 	    goto add_err;
570 
571 	expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
572 	ret = stat(ppath, &statbuf2);
573 	if (ret < 0)
574 	    goto staterr;
575     }
576 
577     /* if filename is a directory, append the cscope database name to it */
578     if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
579     {
580 	fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
581 	if (fname2 == NULL)
582 	    goto add_err;
583 
584 	while (fname[strlen(fname)-1] == '/'
585 #ifdef WIN32
586 		|| fname[strlen(fname)-1] == '\\'
587 #endif
588 		)
589 	{
590 	    fname[strlen(fname)-1] = '\0';
591 	    if (strlen(fname) == 0)
592 		break;
593 	}
594 	if (fname[0] == '\0')
595 	    (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
596 	else
597 	    (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
598 
599 	ret = stat(fname2, &statbuf);
600 	if (ret < 0)
601 	{
602 	    if (p_csverbose)
603 		cs_stat_emsg(fname2);
604 	    goto add_err;
605 	}
606 
607 	i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
608     }
609 #if defined(UNIX)
610     else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
611 #else
612 	/* WIN32 - substitute define S_ISREG from os_unix.h */
613     else if (((statbuf.st_mode) & S_IFMT) == S_IFREG)
614 #endif
615     {
616 	i = cs_insert_filelist(fname, ppath, flags, &statbuf);
617     }
618     else
619     {
620 	if (p_csverbose)
621 	    (void)EMSG2(
622 		_("E564: %s is not a directory or a valid cscope database"),
623 		fname);
624 	goto add_err;
625     }
626 
627     if (i != -1)
628     {
629 	if (cs_create_connection(i) == CSCOPE_FAILURE
630 		|| cs_read_prompt(i) == CSCOPE_FAILURE)
631 	{
632 	    cs_release_csp(i, TRUE);
633 	    goto add_err;
634 	}
635 
636 	if (p_csverbose)
637 	{
638 	    msg_clr_eos();
639 	    (void)smsg_attr(hl_attr(HLF_R),
640 			    (char_u *)_("Added cscope database %s"),
641 			    csinfo[i].fname);
642 	}
643     }
644 
645     vim_free(fname);
646     vim_free(fname2);
647     vim_free(ppath);
648     return CSCOPE_SUCCESS;
649 
650 add_err:
651     vim_free(fname2);
652     vim_free(fname);
653     vim_free(ppath);
654     return CSCOPE_FAILURE;
655 } /* cs_add_common */
656 
657 
658     static int
659 cs_check_for_connections()
660 {
661     return (cs_cnt_connections() > 0);
662 } /* cs_check_for_connections */
663 
664 
665     static int
666 cs_check_for_tags()
667 {
668     return (p_tags[0] != NUL && curbuf->b_p_tags != NULL);
669 } /* cs_check_for_tags */
670 
671 
672 /*
673  * PRIVATE: cs_cnt_connections
674  *
675  * count the number of cscope connections
676  */
677     static int
678 cs_cnt_connections()
679 {
680     short i;
681     short cnt = 0;
682 
683     for (i = 0; i < csinfo_size; i++)
684     {
685 	if (csinfo[i].fname != NULL)
686 	    cnt++;
687     }
688     return cnt;
689 } /* cs_cnt_connections */
690 
691     static void
692 cs_reading_emsg(idx)
693     int idx;	/* connection index */
694 {
695     EMSGN(_("E262: error reading cscope connection %ld"), idx);
696 }
697 
698 #define	CSREAD_BUFSIZE	2048
699 /*
700  * PRIVATE: cs_cnt_matches
701  *
702  * count the number of matches for a given cscope connection.
703  */
704     static int
705 cs_cnt_matches(idx)
706     int idx;
707 {
708     char *stok;
709     char *buf;
710     int nlines;
711 
712     buf = (char *)alloc(CSREAD_BUFSIZE);
713     if (buf == NULL)
714 	return 0;
715     for (;;)
716     {
717 	if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp))
718 	{
719 	    if (feof(csinfo[idx].fr_fp))
720 		errno = EIO;
721 
722 	    cs_reading_emsg(idx);
723 
724 	    vim_free(buf);
725 	    return -1;
726 	}
727 
728 	/*
729 	 * If the database is out of date, or there's some other problem,
730 	 * cscope will output error messages before the number-of-lines output.
731 	 * Display/discard any output that doesn't match what we want.
732 	 * Accept "\S*cscope: X lines", also matches "mlcscope".
733 	 */
734 	if ((stok = strtok(buf, (const char *)" ")) == NULL)
735 	    continue;
736 	if (strstr((const char *)stok, "cscope:") == NULL)
737 	    continue;
738 
739 	if ((stok = strtok(NULL, (const char *)" ")) == NULL)
740 	    continue;
741 	nlines = atoi(stok);
742 	if (nlines < 0)
743 	{
744 	    nlines = 0;
745 	    break;
746 	}
747 
748 	if ((stok = strtok(NULL, (const char *)" ")) == NULL)
749 	    continue;
750 	if (strncmp((const char *)stok, "lines", 5))
751 	    continue;
752 
753 	break;
754     }
755 
756     vim_free(buf);
757     return nlines;
758 } /* cs_cnt_matches */
759 
760 
761 /*
762  * PRIVATE: cs_create_cmd
763  *
764  * Creates the actual cscope command query from what the user entered.
765  */
766     static char *
767 cs_create_cmd(csoption, pattern)
768     char *csoption;
769     char *pattern;
770 {
771     char *cmd;
772     short search;
773     char *pat;
774 
775     switch (csoption[0])
776     {
777     case '0' : case 's' :
778 	search = 0;
779 	break;
780     case '1' : case 'g' :
781 	search = 1;
782 	break;
783     case '2' : case 'd' :
784 	search = 2;
785 	break;
786     case '3' : case 'c' :
787 	search = 3;
788 	break;
789     case '4' : case 't' :
790 	search = 4;
791 	break;
792     case '6' : case 'e' :
793 	search = 6;
794 	break;
795     case '7' : case 'f' :
796 	search = 7;
797 	break;
798     case '8' : case 'i' :
799 	search = 8;
800 	break;
801     default :
802 	(void)EMSG(_("E561: unknown cscope search type"));
803 	cs_usage_msg(Find);
804 	return NULL;
805     }
806 
807     /* Skip white space before the patter, except for text and pattern search,
808      * they may want to use the leading white space. */
809     pat = pattern;
810     if (search != 4 && search != 6)
811 	while vim_iswhite(*pat)
812 	    ++pat;
813 
814     if ((cmd = (char *)alloc((unsigned)(strlen(pat) + 2))) == NULL)
815 	return NULL;
816 
817     (void)sprintf(cmd, "%d%s", search, pat);
818 
819     return cmd;
820 } /* cs_create_cmd */
821 
822 
823 /*
824  * PRIVATE: cs_create_connection
825  *
826  * This piece of code was taken/adapted from nvi.  do we need to add
827  * the BSD license notice?
828  */
829     static int
830 cs_create_connection(i)
831     int i;
832 {
833 #ifdef UNIX
834     int		to_cs[2], from_cs[2];
835 #endif
836     int		len;
837     char	*prog, *cmd, *ppath = NULL;
838 #ifdef WIN32
839     int		fd;
840     SECURITY_ATTRIBUTES sa;
841     PROCESS_INFORMATION pi;
842     STARTUPINFO si;
843     BOOL	pipe_stdin = FALSE, pipe_stdout = FALSE;
844     HANDLE	stdin_rd, stdout_rd;
845     HANDLE	stdout_wr, stdin_wr;
846     BOOL	created;
847 # ifdef __BORLANDC__
848 #  define OPEN_OH_ARGTYPE long
849 # else
850 #  if (_MSC_VER >= 1300)
851 #   define OPEN_OH_ARGTYPE intptr_t
852 #  else
853 #   define OPEN_OH_ARGTYPE long
854 #  endif
855 # endif
856 #endif
857 
858 #if defined(UNIX)
859     /*
860      * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
861      * from_cs[0] and writes to to_cs[1].
862      */
863     to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
864     if (pipe(to_cs) < 0 || pipe(from_cs) < 0)
865     {
866 	(void)EMSG(_("E566: Could not create cscope pipes"));
867 err_closing:
868 	if (to_cs[0] != -1)
869 	    (void)close(to_cs[0]);
870 	if (to_cs[1] != -1)
871 	    (void)close(to_cs[1]);
872 	if (from_cs[0] != -1)
873 	    (void)close(from_cs[0]);
874 	if (from_cs[1] != -1)
875 	    (void)close(from_cs[1]);
876 	return CSCOPE_FAILURE;
877     }
878 
879     switch (csinfo[i].pid = fork())
880     {
881     case -1:
882 	(void)EMSG(_("E622: Could not fork for cscope"));
883 	goto err_closing;
884     case 0:				/* child: run cscope. */
885 	if (dup2(to_cs[0], STDIN_FILENO) == -1)
886 	    PERROR("cs_create_connection 1");
887 	if (dup2(from_cs[1], STDOUT_FILENO) == -1)
888 	    PERROR("cs_create_connection 2");
889 	if (dup2(from_cs[1], STDERR_FILENO) == -1)
890 	    PERROR("cs_create_connection 3");
891 
892 	/* close unused */
893 	(void)close(to_cs[1]);
894 	(void)close(from_cs[0]);
895 #else
896 	/* WIN32 */
897 	/* Create pipes to communicate with cscope */
898 	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
899 	sa.bInheritHandle = TRUE;
900 	sa.lpSecurityDescriptor = NULL;
901 
902 	if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
903 		|| !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0)))
904 	{
905 	    (void)EMSG(_("E566: Could not create cscope pipes"));
906 err_closing:
907 	    if (pipe_stdin)
908 	    {
909 		CloseHandle(stdin_rd);
910 		CloseHandle(stdin_wr);
911 	    }
912 	    if (pipe_stdout)
913 	    {
914 		CloseHandle(stdout_rd);
915 		CloseHandle(stdout_wr);
916 	    }
917 	    return CSCOPE_FAILURE;
918 	}
919 #endif
920 	/* expand the cscope exec for env var's */
921 	if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL)
922 	{
923 #ifdef UNIX
924 	    return CSCOPE_FAILURE;
925 #else
926 	    /* WIN32 */
927 	    goto err_closing;
928 #endif
929 	}
930 	expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
931 
932 	/* alloc space to hold the cscope command */
933 	len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32);
934 	if (csinfo[i].ppath)
935 	{
936 	    /* expand the prepend path for env var's */
937 	    if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
938 	    {
939 		vim_free(prog);
940 #ifdef UNIX
941 		return CSCOPE_FAILURE;
942 #else
943 		/* WIN32 */
944 		goto err_closing;
945 #endif
946 	    }
947 	    expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
948 
949 	    len += (int)strlen(ppath);
950 	}
951 
952 	if (csinfo[i].flags)
953 	    len += (int)strlen(csinfo[i].flags);
954 
955 	if ((cmd = (char *)alloc(len)) == NULL)
956 	{
957 	    vim_free(prog);
958 	    vim_free(ppath);
959 #ifdef UNIX
960 	    return CSCOPE_FAILURE;
961 #else
962 	    /* WIN32 */
963 	    goto err_closing;
964 #endif
965 	}
966 
967 	/* run the cscope command; is there execl for non-unix systems? */
968 #if defined(UNIX)
969 	(void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
970 #else
971 	/* WIN32 */
972 	(void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
973 #endif
974 	if (csinfo[i].ppath != NULL)
975 	{
976 	    (void)strcat(cmd, " -P");
977 	    (void)strcat(cmd, csinfo[i].ppath);
978 	}
979 	if (csinfo[i].flags != NULL)
980 	{
981 	    (void)strcat(cmd, " ");
982 	    (void)strcat(cmd, csinfo[i].flags);
983 	}
984 # ifdef UNIX
985       /* on Win32 we still need prog */
986 	vim_free(prog);
987 # endif
988 	vim_free(ppath);
989 
990 #if defined(UNIX)
991 	if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
992 	    PERROR(_("cs_create_connection exec failed"));
993 
994 	exit(127);
995 	/* NOTREACHED */
996     default:	/* parent. */
997 	/*
998 	 * Save the file descriptors for later duplication, and
999 	 * reopen as streams.
1000 	 */
1001 	if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
1002 	    PERROR(_("cs_create_connection: fdopen for to_fp failed"));
1003 	if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
1004 	    PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
1005 
1006 	/* close unused */
1007 	(void)close(to_cs[0]);
1008 	(void)close(from_cs[1]);
1009 
1010 	break;
1011     }
1012 
1013 #else
1014     /* WIN32 */
1015     /* Create a new process to run cscope and use pipes to talk with it */
1016     GetStartupInfo(&si);
1017     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1018     si.wShowWindow = SW_HIDE;  /* Hide child application window */
1019     si.hStdOutput = stdout_wr;
1020     si.hStdError  = stdout_wr;
1021     si.hStdInput  = stdin_rd;
1022     created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
1023 							NULL, NULL, &si, &pi);
1024     vim_free(prog);
1025     vim_free(cmd);
1026 
1027     if (!created)
1028     {
1029 	PERROR(_("cs_create_connection exec failed"));
1030 	(void)EMSG(_("E623: Could not spawn cscope process"));
1031 	goto err_closing;
1032     }
1033     /* else */
1034     csinfo[i].pid = pi.dwProcessId;
1035     csinfo[i].hProc = pi.hProcess;
1036     CloseHandle(pi.hThread);
1037 
1038     /* TODO - tidy up after failure to create files on pipe handles. */
1039     if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
1040 						      _O_TEXT|_O_APPEND)) < 0)
1041 	    || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
1042 	PERROR(_("cs_create_connection: fdopen for to_fp failed"));
1043     if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
1044 						      _O_TEXT|_O_RDONLY)) < 0)
1045 	    || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
1046 	PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
1047 
1048     /* Close handles for file descriptors inherited by the cscope process */
1049     CloseHandle(stdin_rd);
1050     CloseHandle(stdout_wr);
1051 
1052 #endif /* !UNIX */
1053 
1054     return CSCOPE_SUCCESS;
1055 } /* cs_create_connection */
1056 
1057 
1058 /*
1059  * PRIVATE: cs_find
1060  *
1061  * query cscope using command line interface.  parse the output and use tselect
1062  * to allow choices.  like Nvi, creates a pipe to send to/from query/cscope.
1063  *
1064  * returns TRUE if we jump to a tag or abort, FALSE if not.
1065  */
1066     static int
1067 cs_find(eap)
1068     exarg_T *eap;
1069 {
1070     char *opt, *pat;
1071 
1072     if (cs_check_for_connections() == FALSE)
1073     {
1074 	(void)EMSG(_("E567: no cscope connections"));
1075 	return FALSE;
1076     }
1077 
1078     if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL)
1079     {
1080 	cs_usage_msg(Find);
1081 	return FALSE;
1082     }
1083 
1084     pat = opt + strlen(opt) + 1;
1085     if (pat >= (char *)eap->arg + eap_arg_len)
1086     {
1087 	cs_usage_msg(Find);
1088 	return FALSE;
1089     }
1090 
1091     return cs_find_common(opt, pat, eap->forceit, TRUE,
1092 			  eap->cmdidx == CMD_lcscope);
1093 } /* cs_find */
1094 
1095 
1096 /*
1097  * PRIVATE: cs_find_common
1098  *
1099  * common code for cscope find, shared by cs_find() and do_cstag()
1100  */
1101     static int
1102 cs_find_common(opt, pat, forceit, verbose, use_ll)
1103     char *opt;
1104     char *pat;
1105     int forceit;
1106     int verbose;
1107     int	use_ll;
1108 {
1109     int i;
1110     char *cmd;
1111     int *nummatches;
1112     int totmatches;
1113 #ifdef FEAT_QUICKFIX
1114     char cmdletter;
1115     char *qfpos;
1116 
1117     /* get cmd letter */
1118     switch (opt[0])
1119     {
1120     case '0' :
1121 	cmdletter = 's';
1122 	break;
1123     case '1' :
1124 	cmdletter = 'g';
1125 	break;
1126     case '2' :
1127 	cmdletter = 'd';
1128 	break;
1129     case '3' :
1130 	cmdletter = 'c';
1131 	break;
1132     case '4' :
1133 	cmdletter = 't';
1134 	break;
1135     case '6' :
1136 	cmdletter = 'e';
1137 	break;
1138     case '7' :
1139 	cmdletter = 'f';
1140 	break;
1141     case '8' :
1142 	cmdletter = 'i';
1143 	break;
1144     default :
1145 	cmdletter = opt[0];
1146     }
1147 
1148     qfpos = (char *)vim_strchr(p_csqf, cmdletter);
1149     if (qfpos != NULL)
1150     {
1151 	qfpos++;
1152 	/* next symbol must be + or - */
1153 	if (strchr(CSQF_FLAGS, *qfpos) == NULL)
1154 	{
1155 	    char *nf = _("E469: invalid cscopequickfix flag %c for %c");
1156 	    char *buf = (char *)alloc((unsigned)strlen(nf));
1157 
1158 	    /* strlen will be enough because we use chars */
1159 	    if (buf != NULL)
1160 	    {
1161 		sprintf(buf, nf, *qfpos, *(qfpos-1));
1162 		(void)EMSG(buf);
1163 		vim_free(buf);
1164 	    }
1165 	    return FALSE;
1166 	}
1167 
1168 # ifdef FEAT_AUTOCMD
1169 	if (*qfpos != '0')
1170 	{
1171 	    apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)"cscope",
1172 					       curbuf->b_fname, TRUE, curbuf);
1173 #  ifdef FEAT_EVAL
1174 	    if (did_throw || force_abort)
1175 		return FALSE;
1176 #  endif
1177 	}
1178 # endif
1179     }
1180 #endif
1181 
1182     /* create the actual command to send to cscope */
1183     cmd = cs_create_cmd(opt, pat);
1184     if (cmd == NULL)
1185 	return FALSE;
1186 
1187     nummatches = (int *)alloc(sizeof(int)*csinfo_size);
1188     if (nummatches == NULL)
1189 	return FALSE;
1190 
1191     /* send query to all open connections, then count the total number
1192      * of matches so we can alloc matchesp all in one swell foop
1193      */
1194     for (i = 0; i < csinfo_size; i++)
1195 	nummatches[i] = 0;
1196     totmatches = 0;
1197     for (i = 0; i < csinfo_size; i++)
1198     {
1199 	if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
1200 	    continue;
1201 
1202 	/* send cmd to cscope */
1203 	(void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
1204 	(void)fflush(csinfo[i].to_fp);
1205 
1206 	nummatches[i] = cs_cnt_matches(i);
1207 
1208 	if (nummatches[i] > -1)
1209 	    totmatches += nummatches[i];
1210 
1211 	if (nummatches[i] == 0)
1212 	    (void)cs_read_prompt(i);
1213     }
1214     vim_free(cmd);
1215 
1216     if (totmatches == 0)
1217     {
1218 	char *nf = _("E259: no matches found for cscope query %s of %s");
1219 	char *buf;
1220 
1221 	if (!verbose)
1222 	{
1223 	    vim_free(nummatches);
1224 	    return FALSE;
1225 	}
1226 
1227 	buf = (char *)alloc((unsigned)(strlen(opt) + strlen(pat) + strlen(nf)));
1228 	if (buf == NULL)
1229 	    (void)EMSG(nf);
1230 	else
1231 	{
1232 	    sprintf(buf, nf, opt, pat);
1233 	    (void)EMSG(buf);
1234 	    vim_free(buf);
1235 	}
1236 	vim_free(nummatches);
1237 	return FALSE;
1238     }
1239 
1240 #ifdef FEAT_QUICKFIX
1241     if (qfpos != NULL && *qfpos != '0' && totmatches > 0)
1242     {
1243 	/* fill error list */
1244 	FILE	    *f;
1245 	char_u	    *tmp = vim_tempname('c');
1246 	qf_info_T   *qi = NULL;
1247 	win_T	    *wp = NULL;
1248 
1249 	f = mch_fopen((char *)tmp, "w");
1250 	if (f == NULL)
1251 	    EMSG2(_(e_notopen), tmp);
1252 	else
1253 	{
1254 	    cs_file_results(f, nummatches);
1255 	    fclose(f);
1256 	    if (use_ll)	    /* Use location list */
1257 		wp = curwin;
1258 	    /* '-' starts a new error list */
1259 	    if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
1260 							   *qfpos == '-') > 0)
1261 	    {
1262 # ifdef FEAT_WINDOWS
1263 		if (postponed_split != 0)
1264 		{
1265 		    win_split(postponed_split > 0 ? postponed_split : 0,
1266 						       postponed_split_flags);
1267 #  ifdef FEAT_SCROLLBIND
1268 		    curwin->w_p_scb = FALSE;
1269 #  endif
1270 		    postponed_split = 0;
1271 		}
1272 # endif
1273 
1274 # ifdef FEAT_AUTOCMD
1275 		apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope",
1276 					       curbuf->b_fname, TRUE, curbuf);
1277 # endif
1278 		if (use_ll)
1279 		    /*
1280 		     * In the location list window, use the displayed location
1281 		     * list. Otherwise, use the location list for the window.
1282 		     */
1283 		    qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
1284 			?  wp->w_llist_ref : wp->w_llist;
1285 		qf_jump(qi, 0, 0, forceit);
1286 	    }
1287 	}
1288 	mch_remove(tmp);
1289 	vim_free(tmp);
1290 	vim_free(nummatches);
1291 	return TRUE;
1292     }
1293     else
1294 #endif /* FEAT_QUICKFIX */
1295     {
1296 	char **matches = NULL, **contexts = NULL;
1297 	int matched = 0;
1298 
1299 	/* read output */
1300 	cs_fill_results((char *)pat, totmatches, nummatches, &matches,
1301 							 &contexts, &matched);
1302 	vim_free(nummatches);
1303 	if (matches == NULL)
1304 	    return FALSE;
1305 
1306 	(void)cs_manage_matches(matches, contexts, matched, Store);
1307 
1308 	return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
1309     }
1310 
1311 } /* cs_find_common */
1312 
1313 /*
1314  * PRIVATE: cs_help
1315  *
1316  * print help
1317  */
1318     static int
1319 cs_help(eap)
1320     exarg_T *eap UNUSED;
1321 {
1322     cscmd_T *cmdp = cs_cmds;
1323 
1324     (void)MSG_PUTS(_("cscope commands:\n"));
1325     while (cmdp->name != NULL)
1326     {
1327 	char *help = _(cmdp->help);
1328 	int  space_cnt = 30 - vim_strsize((char_u *)help);
1329 
1330 	/* Use %*s rather than %30s to ensure proper alignment in utf-8 */
1331 	if (space_cnt < 0)
1332 	    space_cnt = 0;
1333 	(void)smsg((char_u *)_("%-5s: %s%*s (Usage: %s)"),
1334 				      cmdp->name,
1335 				      help, space_cnt, " ",
1336 				      cmdp->usage);
1337 	if (strcmp(cmdp->name, "find") == 0)
1338 	    MSG_PUTS(_("\n"
1339 		       "       c: Find functions calling this function\n"
1340 		       "       d: Find functions called by this function\n"
1341 		       "       e: Find this egrep pattern\n"
1342 		       "       f: Find this file\n"
1343 		       "       g: Find this definition\n"
1344 		       "       i: Find files #including this file\n"
1345 		       "       s: Find this C symbol\n"
1346 		       "       t: Find assignments to\n"));
1347 
1348 	cmdp++;
1349     }
1350 
1351     wait_return(TRUE);
1352     return 0;
1353 } /* cs_help */
1354 
1355 
1356     static void
1357 clear_csinfo(i)
1358     int	    i;
1359 {
1360     csinfo[i].fname  = NULL;
1361     csinfo[i].ppath  = NULL;
1362     csinfo[i].flags  = NULL;
1363 #if defined(UNIX)
1364     csinfo[i].st_dev = (dev_t)0;
1365     csinfo[i].st_ino = (ino_t)0;
1366 #else
1367     csinfo[i].nVolume = 0;
1368     csinfo[i].nIndexHigh = 0;
1369     csinfo[i].nIndexLow = 0;
1370 #endif
1371     csinfo[i].pid    = 0;
1372     csinfo[i].fr_fp  = NULL;
1373     csinfo[i].to_fp  = NULL;
1374 #if defined(WIN32)
1375     csinfo[i].hProc = NULL;
1376 #endif
1377 }
1378 
1379 #ifndef UNIX
1380 static char *GetWin32Error __ARGS((void));
1381 
1382     static char *
1383 GetWin32Error()
1384 {
1385     char *msg = NULL;
1386     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
1387 	    NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL);
1388     if (msg != NULL)
1389     {
1390 	/* remove trailing \r\n */
1391 	char *pcrlf = strstr(msg, "\r\n");
1392 	if (pcrlf != NULL)
1393 	    *pcrlf = '\0';
1394     }
1395     return msg;
1396 }
1397 #endif
1398 
1399 /*
1400  * PRIVATE: cs_insert_filelist
1401  *
1402  * insert a new cscope database filename into the filelist
1403  */
1404     static int
1405 cs_insert_filelist(fname, ppath, flags, sb)
1406     char *fname;
1407     char *ppath;
1408     char *flags;
1409     struct stat *sb UNUSED;
1410 {
1411     short	i, j;
1412 #ifndef UNIX
1413     HANDLE	hFile;
1414     BY_HANDLE_FILE_INFORMATION bhfi;
1415 
1416     vim_memset(&bhfi, 0, sizeof(bhfi));
1417     /* On windows 9x GetFileInformationByHandle doesn't work, so skip it */
1418     if (!mch_windows95())
1419     {
1420 	hFile = CreateFile(fname, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
1421 						 FILE_ATTRIBUTE_NORMAL, NULL);
1422 	if (hFile == INVALID_HANDLE_VALUE)
1423 	{
1424 	    if (p_csverbose)
1425 	    {
1426 		char *cant_msg = _("E625: cannot open cscope database: %s");
1427 		char *winmsg = GetWin32Error();
1428 
1429 		if (winmsg != NULL)
1430 		{
1431 		    (void)EMSG2(cant_msg, winmsg);
1432 		    LocalFree(winmsg);
1433 		}
1434 		else
1435 		    /* subst filename if can't get error text */
1436 		    (void)EMSG2(cant_msg, fname);
1437 	    }
1438 	    return -1;
1439 	}
1440 	if (!GetFileInformationByHandle(hFile, &bhfi))
1441 	{
1442 	    CloseHandle(hFile);
1443 	    if (p_csverbose)
1444 		(void)EMSG(_("E626: cannot get cscope database information"));
1445 	    return -1;
1446 	}
1447 	CloseHandle(hFile);
1448     }
1449 #endif
1450 
1451     i = -1; /* can be set to the index of an empty item in csinfo */
1452     for (j = 0; j < csinfo_size; j++)
1453     {
1454 	if (csinfo[j].fname != NULL
1455 #if defined(UNIX)
1456 	    && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
1457 #else
1458 	    /* compare pathnames first */
1459 	    && ((fullpathcmp(csinfo[j].fname, fname, FALSE) & FPC_SAME)
1460 		/* if not Windows 9x, test index file attributes too */
1461 		|| (!mch_windows95()
1462 		    && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
1463 		    && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
1464 		    && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
1465 #endif
1466 	    )
1467 	{
1468 	    if (p_csverbose)
1469 		(void)EMSG(_("E568: duplicate cscope database not added"));
1470 	    return -1;
1471 	}
1472 
1473 	if (csinfo[j].fname == NULL && i == -1)
1474 	    i = j; /* remember first empty entry */
1475     }
1476 
1477     if (i == -1)
1478     {
1479 	i = csinfo_size;
1480 	if (csinfo_size == 0)
1481 	{
1482 	    /* First time allocation: allocate only 1 connection. It should
1483 	     * be enough for most users.  If more is needed, csinfo will be
1484 	     * reallocated. */
1485 	    csinfo_size = 1;
1486 	    csinfo = (csinfo_T *)alloc_clear(sizeof(csinfo_T));
1487 	}
1488 	else
1489 	{
1490 	    /* Reallocate space for more connections. */
1491 	    csinfo_size *= 2;
1492 	    csinfo = vim_realloc(csinfo, sizeof(csinfo_T)*csinfo_size);
1493 	}
1494 	if (csinfo == NULL)
1495 	    return -1;
1496 	for (j = csinfo_size/2; j < csinfo_size; j++)
1497 	    clear_csinfo(j);
1498     }
1499 
1500     if ((csinfo[i].fname = (char *)alloc((unsigned)strlen(fname)+1)) == NULL)
1501 	return -1;
1502 
1503     (void)strcpy(csinfo[i].fname, (const char *)fname);
1504 
1505     if (ppath != NULL)
1506     {
1507 	if ((csinfo[i].ppath = (char *)alloc((unsigned)strlen(ppath) + 1)) == NULL)
1508 	{
1509 	    vim_free(csinfo[i].fname);
1510 	    csinfo[i].fname = NULL;
1511 	    return -1;
1512 	}
1513 	(void)strcpy(csinfo[i].ppath, (const char *)ppath);
1514     } else
1515 	csinfo[i].ppath = NULL;
1516 
1517     if (flags != NULL)
1518     {
1519 	if ((csinfo[i].flags = (char *)alloc((unsigned)strlen(flags) + 1)) == NULL)
1520 	{
1521 	    vim_free(csinfo[i].fname);
1522 	    vim_free(csinfo[i].ppath);
1523 	    csinfo[i].fname = NULL;
1524 	    csinfo[i].ppath = NULL;
1525 	    return -1;
1526 	}
1527 	(void)strcpy(csinfo[i].flags, (const char *)flags);
1528     } else
1529 	csinfo[i].flags = NULL;
1530 
1531 #if defined(UNIX)
1532     csinfo[i].st_dev = sb->st_dev;
1533     csinfo[i].st_ino = sb->st_ino;
1534 
1535 #else
1536     csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
1537     csinfo[i].nIndexLow = bhfi.nFileIndexLow;
1538     csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
1539 #endif
1540     return i;
1541 } /* cs_insert_filelist */
1542 
1543 
1544 /*
1545  * PRIVATE: cs_lookup_cmd
1546  *
1547  * find cscope command in command table
1548  */
1549     static cscmd_T *
1550 cs_lookup_cmd(eap)
1551     exarg_T *eap;
1552 {
1553     cscmd_T *cmdp;
1554     char *stok;
1555     size_t len;
1556 
1557     if (eap->arg == NULL)
1558 	return NULL;
1559 
1560     /* Store length of eap->arg before it gets modified by strtok(). */
1561     eap_arg_len = (int)STRLEN(eap->arg);
1562 
1563     if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
1564 	return NULL;
1565 
1566     len = strlen(stok);
1567     for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp)
1568     {
1569 	if (strncmp((const char *)(stok), cmdp->name, len) == 0)
1570 	    return (cmdp);
1571     }
1572     return NULL;
1573 } /* cs_lookup_cmd */
1574 
1575 
1576 /*
1577  * PRIVATE: cs_kill
1578  *
1579  * nuke em
1580  */
1581     static int
1582 cs_kill(eap)
1583     exarg_T *eap UNUSED;
1584 {
1585     char *stok;
1586     short i;
1587 
1588     if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL)
1589     {
1590 	cs_usage_msg(Kill);
1591 	return CSCOPE_FAILURE;
1592     }
1593 
1594     /* only single digit positive and negative integers are allowed */
1595     if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0])))
1596 	    || (strlen(stok) < 3 && stok[0] == '-'
1597 					      && VIM_ISDIGIT((int)(stok[1]))))
1598 	i = atoi(stok);
1599     else
1600     {
1601 	/* It must be part of a name.  We will try to find a match
1602 	 * within all the names in the csinfo data structure
1603 	 */
1604 	for (i = 0; i < csinfo_size; i++)
1605 	{
1606 	    if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
1607 		break;
1608 	}
1609     }
1610 
1611     if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL))
1612     {
1613 	if (p_csverbose)
1614 	    (void)EMSG2(_("E261: cscope connection %s not found"), stok);
1615     }
1616     else
1617     {
1618 	if (i == -1)
1619 	{
1620 	    for (i = 0; i < csinfo_size; i++)
1621 	    {
1622 		if (csinfo[i].fname)
1623 		    cs_kill_execute(i, csinfo[i].fname);
1624 	    }
1625 	}
1626 	else
1627 	    cs_kill_execute(i, stok);
1628     }
1629 
1630     return 0;
1631 } /* cs_kill */
1632 
1633 
1634 /*
1635  * PRIVATE: cs_kill_execute
1636  *
1637  * Actually kills a specific cscope connection.
1638  */
1639     static void
1640 cs_kill_execute(i, cname)
1641     int i;	    /* cscope table index */
1642     char *cname;    /* cscope database name */
1643 {
1644     if (p_csverbose)
1645     {
1646 	msg_clr_eos();
1647 	(void)smsg_attr(hl_attr(HLF_R) | MSG_HIST,
1648 		(char_u *)_("cscope connection %s closed"), cname);
1649     }
1650     cs_release_csp(i, TRUE);
1651 }
1652 
1653 
1654 /*
1655  * PRIVATE: cs_make_vim_style_matches
1656  *
1657  * convert the cscope output into into a ctags style entry (as might be found
1658  * in a ctags tags file).  there's one catch though: cscope doesn't tell you
1659  * the type of the tag you are looking for.  for example, in Darren Hiebert's
1660  * ctags (the one that comes with vim), #define's use a line number to find the
1661  * tag in a file while function definitions use a regexp search pattern.
1662  *
1663  * i'm going to always use the line number because cscope does something
1664  * quirky (and probably other things i don't know about):
1665  *
1666  *     if you have "#  define" in your source file, which is
1667  *     perfectly legal, cscope thinks you have "#define".  this
1668  *     will result in a failed regexp search. :(
1669  *
1670  * besides, even if this particular case didn't happen, the search pattern
1671  * would still have to be modified to escape all the special regular expression
1672  * characters to comply with ctags formatting.
1673  */
1674     static char *
1675 cs_make_vim_style_matches(fname, slno, search, tagstr)
1676     char *fname;
1677     char *slno;
1678     char *search;
1679     char *tagstr;
1680 {
1681     /* vim style is ctags:
1682      *
1683      *	    <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
1684      *
1685      * but as mentioned above, we'll always use the line number and
1686      * put the search pattern (if one exists) as "extra"
1687      *
1688      * buf is used as part of vim's method of handling tags, and
1689      * (i think) vim frees it when you pop your tags and get replaced
1690      * by new ones on the tag stack.
1691      */
1692     char *buf;
1693     int amt;
1694 
1695     if (search != NULL)
1696     {
1697 	amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6);
1698 	if ((buf = (char *)alloc(amt)) == NULL)
1699 	    return NULL;
1700 
1701 	(void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
1702     }
1703     else
1704     {
1705 	amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + 5);
1706 	if ((buf = (char *)alloc(amt)) == NULL)
1707 	    return NULL;
1708 
1709 	(void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
1710     }
1711 
1712     return buf;
1713 } /* cs_make_vim_style_matches */
1714 
1715 
1716 /*
1717  * PRIVATE: cs_manage_matches
1718  *
1719  * this is kind of hokey, but i don't see an easy way round this..
1720  *
1721  * Store: keep a ptr to the (malloc'd) memory of matches originally
1722  * generated from cs_find().  the matches are originally lines directly
1723  * from cscope output, but transformed to look like something out of a
1724  * ctags.  see cs_make_vim_style_matches for more details.
1725  *
1726  * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
1727  * the next line from the cscope output.  it basically keeps track of which
1728  * lines have been "used" and returns the next one.
1729  *
1730  * Free: frees up everything and resets
1731  *
1732  * Print: prints the tags
1733  */
1734     static char *
1735 cs_manage_matches(matches, contexts, totmatches, cmd)
1736     char **matches;
1737     char **contexts;
1738     int totmatches;
1739     mcmd_e cmd;
1740 {
1741     static char **mp = NULL;
1742     static char **cp = NULL;
1743     static int cnt = -1;
1744     static int next = -1;
1745     char *p = NULL;
1746 
1747     switch (cmd)
1748     {
1749     case Store:
1750 	assert(matches != NULL);
1751 	assert(totmatches > 0);
1752 	if (mp != NULL || cp != NULL)
1753 	    (void)cs_manage_matches(NULL, NULL, -1, Free);
1754 	mp = matches;
1755 	cp = contexts;
1756 	cnt = totmatches;
1757 	next = 0;
1758 	break;
1759     case Get:
1760 	if (next >= cnt)
1761 	    return NULL;
1762 
1763 	p = mp[next];
1764 	next++;
1765 	break;
1766     case Free:
1767 	if (mp != NULL)
1768 	{
1769 	    if (cnt > 0)
1770 		while (cnt--)
1771 		{
1772 		    vim_free(mp[cnt]);
1773 		    if (cp != NULL)
1774 			vim_free(cp[cnt]);
1775 		}
1776 	    vim_free(mp);
1777 	    vim_free(cp);
1778 	}
1779 	mp = NULL;
1780 	cp = NULL;
1781 	cnt = 0;
1782 	next = 0;
1783 	break;
1784     case Print:
1785 	cs_print_tags_priv(mp, cp, cnt);
1786 	break;
1787     default:	/* should not reach here */
1788 	(void)EMSG(_("E570: fatal error in cs_manage_matches"));
1789 	return NULL;
1790     }
1791 
1792     return p;
1793 } /* cs_manage_matches */
1794 
1795 
1796 /*
1797  * PRIVATE: cs_parse_results
1798  *
1799  * parse cscope output
1800  */
1801     static char *
1802 cs_parse_results(cnumber, buf, bufsize, context, linenumber, search)
1803     int cnumber;
1804     char *buf;
1805     int bufsize;
1806     char **context;
1807     char **linenumber;
1808     char **search;
1809 {
1810     int ch;
1811     char *p;
1812     char *name;
1813 
1814     if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL)
1815     {
1816 	if (feof(csinfo[cnumber].fr_fp))
1817 	    errno = EIO;
1818 
1819 	cs_reading_emsg(cnumber);
1820 
1821 	return NULL;
1822     }
1823 
1824 	/* If the line's too long for the buffer, discard it. */
1825     if ((p = strchr(buf, '\n')) == NULL)
1826     {
1827 	while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
1828 	    ;
1829 	return NULL;
1830     }
1831     *p = '\0';
1832 
1833     /*
1834      * cscope output is in the following format:
1835      *
1836      *	<filename> <context> <line number> <pattern>
1837      */
1838     if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
1839 	return NULL;
1840     if ((*context = strtok(NULL, (const char *)" ")) == NULL)
1841 	return NULL;
1842     if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
1843 	return NULL;
1844     *search = *linenumber + strlen(*linenumber) + 1;	/* +1 to skip \0 */
1845 
1846     /* --- nvi ---
1847      * If the file is older than the cscope database, that is,
1848      * the database was built since the file was last modified,
1849      * or there wasn't a search string, use the line number.
1850      */
1851     if (strcmp(*search, "<unknown>") == 0)
1852 	*search = NULL;
1853 
1854     name = cs_resolve_file(cnumber, name);
1855     return name;
1856 }
1857 
1858 #ifdef FEAT_QUICKFIX
1859 /*
1860  * PRIVATE: cs_file_results
1861  *
1862  * write cscope find results to file
1863  */
1864     static void
1865 cs_file_results(f, nummatches_a)
1866     FILE *f;
1867     int *nummatches_a;
1868 {
1869     int i, j;
1870     char *buf;
1871     char *search, *slno;
1872     char *fullname;
1873     char *cntx;
1874     char *context;
1875 
1876     buf = (char *)alloc(CSREAD_BUFSIZE);
1877     if (buf == NULL)
1878 	return;
1879 
1880     for (i = 0; i < csinfo_size; i++)
1881     {
1882 	if (nummatches_a[i] < 1)
1883 	    continue;
1884 
1885 	for (j = 0; j < nummatches_a[i]; j++)
1886 	{
1887 	   if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1888 			   &slno, &search)) == NULL)
1889 	       continue;
1890 
1891 	   context = (char *)alloc((unsigned)strlen(cntx)+5);
1892 	   if (context == NULL)
1893 	       continue;
1894 
1895 	   if (strcmp(cntx, "<global>")==0)
1896 	       strcpy(context, "<<global>>");
1897 	   else
1898 	       sprintf(context, "<<%s>>", cntx);
1899 
1900 	   if (search == NULL)
1901 	       fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
1902 	   else
1903 	       fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
1904 
1905 	   vim_free(context);
1906 	   vim_free(fullname);
1907 	} /* for all matches */
1908 
1909 	(void)cs_read_prompt(i);
1910 
1911     } /* for all cscope connections */
1912     vim_free(buf);
1913 }
1914 #endif
1915 
1916 /*
1917  * PRIVATE: cs_fill_results
1918  *
1919  * get parsed cscope output and calls cs_make_vim_style_matches to convert
1920  * into ctags format
1921  * When there are no matches sets "*matches_p" to NULL.
1922  */
1923     static void
1924 cs_fill_results(tagstr, totmatches, nummatches_a, matches_p, cntxts_p, matched)
1925     char *tagstr;
1926     int totmatches;
1927     int *nummatches_a;
1928     char ***matches_p;
1929     char ***cntxts_p;
1930     int *matched;
1931 {
1932     int i, j;
1933     char *buf;
1934     char *search, *slno;
1935     int totsofar = 0;
1936     char **matches = NULL;
1937     char **cntxts = NULL;
1938     char *fullname;
1939     char *cntx;
1940 
1941     assert(totmatches > 0);
1942 
1943     buf = (char *)alloc(CSREAD_BUFSIZE);
1944     if (buf == NULL)
1945 	return;
1946 
1947     if ((matches = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
1948 	goto parse_out;
1949     if ((cntxts = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
1950 	goto parse_out;
1951 
1952     for (i = 0; i < csinfo_size; i++)
1953     {
1954 	if (nummatches_a[i] < 1)
1955 	    continue;
1956 
1957 	for (j = 0; j < nummatches_a[i]; j++)
1958 	{
1959 	   if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1960 			   &slno, &search)) == NULL)
1961 		continue;
1962 
1963 	    matches[totsofar] = cs_make_vim_style_matches(fullname, slno,
1964 							  search, tagstr);
1965 
1966 	    vim_free(fullname);
1967 
1968 	    if (strcmp(cntx, "<global>") == 0)
1969 		cntxts[totsofar] = NULL;
1970 	    else
1971 		/* note: if vim_strsave returns NULL, then the context
1972 		 * will be "<global>", which is misleading.
1973 		 */
1974 		cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
1975 
1976 	    if (matches[totsofar] != NULL)
1977 		totsofar++;
1978 
1979 	} /* for all matches */
1980 
1981 	(void)cs_read_prompt(i);
1982 
1983     } /* for all cscope connections */
1984 
1985 parse_out:
1986     if (totsofar == 0)
1987     {
1988 	/* No matches, free the arrays and return NULL in "*matches_p". */
1989 	vim_free(matches);
1990 	matches = NULL;
1991 	vim_free(cntxts);
1992 	cntxts = NULL;
1993     }
1994     *matched = totsofar;
1995     *matches_p = matches;
1996     *cntxts_p = cntxts;
1997 
1998     vim_free(buf);
1999 } /* cs_fill_results */
2000 
2001 
2002 /* get the requested path components */
2003     static char *
2004 cs_pathcomponents(path)
2005     char	*path;
2006 {
2007     int		i;
2008     char	*s;
2009 
2010     if (p_cspc == 0)
2011 	return path;
2012 
2013     s = path + strlen(path) - 1;
2014     for (i = 0; i < p_cspc; ++i)
2015 	while (s > path && *--s != '/'
2016 #ifdef WIN32
2017 		&& *--s != '\\'
2018 #endif
2019 		)
2020 	    ;
2021     if ((s > path && *s == '/')
2022 #ifdef WIN32
2023 	|| (s > path && *s == '\\')
2024 #endif
2025 	    )
2026 	++s;
2027     return s;
2028 }
2029 
2030 /*
2031  * PRIVATE: cs_print_tags_priv
2032  *
2033  * called from cs_manage_matches()
2034  */
2035     static void
2036 cs_print_tags_priv(matches, cntxts, num_matches)
2037     char **matches;
2038     char **cntxts;
2039     int num_matches;
2040 {
2041     char	*buf = NULL;
2042     int		bufsize = 0; /* Track available bufsize */
2043     int		newsize = 0;
2044     char	*ptag;
2045     char	*fname, *lno, *extra, *tbuf;
2046     int		i, idx, num;
2047     char	*globalcntx = "GLOBAL";
2048     char	*cntxformat = " <<%s>>";
2049     char	*context;
2050     char	*cstag_msg = _("Cscope tag: %s");
2051     char	*csfmt_str = "%4d %6s  ";
2052 
2053     assert (num_matches > 0);
2054 
2055     if ((tbuf = (char *)alloc((unsigned)strlen(matches[0]) + 1)) == NULL)
2056 	return;
2057 
2058     strcpy(tbuf, matches[0]);
2059     ptag = strtok(tbuf, "\t");
2060 
2061     newsize = (int)(strlen(cstag_msg) + strlen(ptag));
2062     buf = (char *)alloc(newsize);
2063     if (buf != NULL)
2064     {
2065 	bufsize = newsize;
2066 	(void)sprintf(buf, cstag_msg, ptag);
2067 	MSG_PUTS_ATTR(buf, hl_attr(HLF_T));
2068     }
2069 
2070     vim_free(tbuf);
2071 
2072     MSG_PUTS_ATTR(_("\n   #   line"), hl_attr(HLF_T));    /* strlen is 7 */
2073     msg_advance(msg_col + 2);
2074     MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T));
2075 
2076     num = 1;
2077     for (i = 0; i < num_matches; i++)
2078     {
2079 	idx = i;
2080 
2081 	/* if we really wanted to, we could avoid this malloc and strcpy
2082 	 * by parsing matches[i] on the fly and placing stuff into buf
2083 	 * directly, but that's too much of a hassle
2084 	 */
2085 	if ((tbuf = (char *)alloc((unsigned)strlen(matches[idx]) + 1)) == NULL)
2086 	    continue;
2087 	(void)strcpy(tbuf, matches[idx]);
2088 
2089 	if (strtok(tbuf, (const char *)"\t") == NULL)
2090 	    continue;
2091 	if ((fname = strtok(NULL, (const char *)"\t")) == NULL)
2092 	    continue;
2093 	if ((lno = strtok(NULL, (const char *)"\t")) == NULL)
2094 	    continue;
2095 	extra = strtok(NULL, (const char *)"\t");
2096 
2097 	lno[strlen(lno)-2] = '\0';  /* ignore ;" at the end */
2098 
2099 	/* hopefully 'num' (num of matches) will be less than 10^16 */
2100 	newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno));
2101 	if (bufsize < newsize)
2102 	{
2103 	    buf = (char *)vim_realloc(buf, newsize);
2104 	    if (buf == NULL)
2105 		bufsize = 0;
2106 	    else
2107 		bufsize = newsize;
2108 	}
2109 	if (buf != NULL)
2110 	{
2111 	    /* csfmt_str = "%4d %6s  "; */
2112 	    (void)sprintf(buf, csfmt_str, num, lno);
2113 	    MSG_PUTS_ATTR(buf, hl_attr(HLF_CM));
2114 	}
2115 	MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM));
2116 
2117 	/* compute the required space for the context */
2118 	if (cntxts[idx] != NULL)
2119 	    context = cntxts[idx];
2120 	else
2121 	    context = globalcntx;
2122 	newsize = (int)(strlen(context) + strlen(cntxformat));
2123 
2124 	if (bufsize < newsize)
2125 	{
2126 	    buf = (char *)vim_realloc(buf, newsize);
2127 	    if (buf == NULL)
2128 		bufsize = 0;
2129 	    else
2130 		bufsize = newsize;
2131 	}
2132 	if (buf != NULL)
2133 	{
2134 	    (void)sprintf(buf, cntxformat, context);
2135 
2136 	    /* print the context only if it fits on the same line */
2137 	    if (msg_col + (int)strlen(buf) >= (int)Columns)
2138 		msg_putchar('\n');
2139 	    msg_advance(12);
2140 	    MSG_PUTS_LONG(buf);
2141 	    msg_putchar('\n');
2142 	}
2143 	if (extra != NULL)
2144 	{
2145 	    msg_advance(13);
2146 	    MSG_PUTS_LONG(extra);
2147 	}
2148 
2149 	vim_free(tbuf); /* only after printing extra due to strtok use */
2150 
2151 	if (msg_col)
2152 	    msg_putchar('\n');
2153 
2154 	ui_breakcheck();
2155 	if (got_int)
2156 	{
2157 	    got_int = FALSE;	/* don't print any more matches */
2158 	    break;
2159 	}
2160 
2161 	num++;
2162     } /* for all matches */
2163 
2164     vim_free(buf);
2165 } /* cs_print_tags_priv */
2166 
2167 
2168 /*
2169  * PRIVATE: cs_read_prompt
2170  *
2171  * read a cscope prompt (basically, skip over the ">> ")
2172  */
2173     static int
2174 cs_read_prompt(i)
2175     int i;
2176 {
2177     int		ch;
2178     char	*buf = NULL; /* buffer for possible error message from cscope */
2179     int		bufpos = 0;
2180     char	*cs_emsg;
2181     int		maxlen;
2182     static char *eprompt = "Press the RETURN key to continue:";
2183     int		epromptlen = (int)strlen(eprompt);
2184     int		n;
2185 
2186     cs_emsg = _("E609: Cscope error: %s");
2187     /* compute maximum allowed len for Cscope error message */
2188     maxlen = (int)(IOSIZE - strlen(cs_emsg));
2189 
2190     for (;;)
2191     {
2192 	while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
2193 	    /* if there is room and char is printable */
2194 	    if (bufpos < maxlen - 1 && vim_isprintc(ch))
2195 	    {
2196 		if (buf == NULL) /* lazy buffer allocation */
2197 		    buf = (char *)alloc(maxlen);
2198 		if (buf != NULL)
2199 		{
2200 		    /* append character to the message */
2201 		    buf[bufpos++] = ch;
2202 		    buf[bufpos] = NUL;
2203 		    if (bufpos >= epromptlen
2204 			    && strcmp(&buf[bufpos - epromptlen], eprompt) == 0)
2205 		    {
2206 			/* remove eprompt from buf */
2207 			buf[bufpos - epromptlen] = NUL;
2208 
2209 			/* print message to user */
2210 			(void)EMSG2(cs_emsg, buf);
2211 
2212 			/* send RETURN to cscope */
2213 			(void)putc('\n', csinfo[i].to_fp);
2214 			(void)fflush(csinfo[i].to_fp);
2215 
2216 			/* clear buf */
2217 			bufpos = 0;
2218 			buf[bufpos] = NUL;
2219 		    }
2220 		}
2221 	    }
2222 
2223 	for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n)
2224 	{
2225 	    if (n > 0)
2226 		ch = getc(csinfo[i].fr_fp);
2227 	    if (ch == EOF)
2228 	    {
2229 		PERROR("cs_read_prompt EOF");
2230 		if (buf != NULL && buf[0] != NUL)
2231 		    (void)EMSG2(cs_emsg, buf);
2232 		else if (p_csverbose)
2233 		    cs_reading_emsg(i); /* don't have additional information */
2234 		cs_release_csp(i, TRUE);
2235 		vim_free(buf);
2236 		return CSCOPE_FAILURE;
2237 	    }
2238 
2239 	    if (ch != CSCOPE_PROMPT[n])
2240 	    {
2241 		ch = EOF;
2242 		break;
2243 	    }
2244 	}
2245 
2246 	if (ch == EOF)
2247 	    continue;	    /* didn't find the prompt */
2248 	break;		    /* did find the prompt */
2249     }
2250 
2251     vim_free(buf);
2252     return CSCOPE_SUCCESS;
2253 }
2254 
2255 #if defined(UNIX) && defined(SIGALRM)
2256 /*
2257  * Used to catch and ignore SIGALRM below.
2258  */
2259     static RETSIGTYPE
2260 sig_handler SIGDEFARG(sigarg)
2261 {
2262     /* do nothing */
2263     SIGRETURN;
2264 }
2265 #endif
2266 
2267 /*
2268  * PRIVATE: cs_release_csp
2269  *
2270  * Does the actual free'ing for the cs ptr with an optional flag of whether
2271  * or not to free the filename.  Called by cs_kill and cs_reset.
2272  */
2273     static void
2274 cs_release_csp(i, freefnpp)
2275     int i;
2276     int freefnpp;
2277 {
2278     /*
2279      * Trying to exit normally (not sure whether it is fit to UNIX cscope
2280      */
2281     if (csinfo[i].to_fp != NULL)
2282     {
2283 	(void)fputs("q\n", csinfo[i].to_fp);
2284 	(void)fflush(csinfo[i].to_fp);
2285     }
2286 #if defined(UNIX)
2287     {
2288 	int waitpid_errno;
2289 	int pstat;
2290 	pid_t pid;
2291 
2292 # if defined(HAVE_SIGACTION)
2293 	struct sigaction sa, old;
2294 
2295 	/* Use sigaction() to limit the waiting time to two seconds. */
2296 	sigemptyset(&sa.sa_mask);
2297 	sa.sa_handler = sig_handler;
2298 #  ifdef SA_NODEFER
2299 	sa.sa_flags = SA_NODEFER;
2300 #  else
2301 	sa.sa_flags = 0;
2302 #  endif
2303 	sigaction(SIGALRM, &sa, &old);
2304 	alarm(2); /* 2 sec timeout */
2305 
2306 	/* Block until cscope exits or until timer expires */
2307 	pid = waitpid(csinfo[i].pid, &pstat, 0);
2308 	waitpid_errno = errno;
2309 
2310 	/* cancel pending alarm if still there and restore signal */
2311 	alarm(0);
2312 	sigaction(SIGALRM, &old, NULL);
2313 # else
2314 	int waited;
2315 
2316 	/* Can't use sigaction(), loop for two seconds.  First yield the CPU
2317 	 * to give cscope a chance to exit quickly. */
2318 	sleep(0);
2319 	for (waited = 0; waited < 40; ++waited)
2320 	{
2321 	    pid = waitpid(csinfo[i].pid, &pstat, WNOHANG);
2322 	    waitpid_errno = errno;
2323 	    if (pid != 0)
2324 		break;  /* break unless the process is still running */
2325 	    mch_delay(50L, FALSE); /* sleep 50 ms */
2326 	}
2327 # endif
2328 	/*
2329 	 * If the cscope process is still running: kill it.
2330 	 * Safety check: If the PID would be zero here, the entire X session
2331 	 * would be killed.  -1 and 1 are dangerous as well.
2332 	 */
2333 	if (pid < 0 && csinfo[i].pid > 1)
2334 	{
2335 # ifdef ECHILD
2336 	    int alive = TRUE;
2337 
2338 	    if (waitpid_errno == ECHILD)
2339 	    {
2340 		/*
2341 		 * When using 'vim -g', vim is forked and cscope process is
2342 		 * no longer a child process but a sibling.  So waitpid()
2343 		 * fails with errno being ECHILD (No child processes).
2344 		 * Don't send SIGKILL to cscope immediately but wait
2345 		 * (polling) for it to exit normally as result of sending
2346 		 * the "q" command, hence giving it a chance to clean up
2347 		 * its temporary files.
2348 		 */
2349 		int waited;
2350 
2351 		sleep(0);
2352 		for (waited = 0; waited < 40; ++waited)
2353 		{
2354 		    /* Check whether cscope process is still alive */
2355 		    if (kill(csinfo[i].pid, 0) != 0)
2356 		    {
2357 			alive = FALSE; /* cscope process no longer exists */
2358 			break;
2359 		    }
2360 		    mch_delay(50L, FALSE); /* sleep 50ms */
2361 		}
2362 	    }
2363 	    if (alive)
2364 # endif
2365 	    {
2366 		kill(csinfo[i].pid, SIGKILL);
2367 		(void)waitpid(csinfo[i].pid, &pstat, 0);
2368 	    }
2369 	}
2370     }
2371 #else  /* !UNIX */
2372     if (csinfo[i].hProc != NULL)
2373     {
2374 	/* Give cscope a chance to exit normally */
2375 	if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
2376 	    TerminateProcess(csinfo[i].hProc, 0);
2377 	CloseHandle(csinfo[i].hProc);
2378     }
2379 #endif
2380 
2381     if (csinfo[i].fr_fp != NULL)
2382 	(void)fclose(csinfo[i].fr_fp);
2383     if (csinfo[i].to_fp != NULL)
2384 	(void)fclose(csinfo[i].to_fp);
2385 
2386     if (freefnpp)
2387     {
2388 	vim_free(csinfo[i].fname);
2389 	vim_free(csinfo[i].ppath);
2390 	vim_free(csinfo[i].flags);
2391     }
2392 
2393     clear_csinfo(i);
2394 } /* cs_release_csp */
2395 
2396 
2397 /*
2398  * PRIVATE: cs_reset
2399  *
2400  * calls cs_kill on all cscope connections then reinits
2401  */
2402     static int
2403 cs_reset(eap)
2404     exarg_T *eap UNUSED;
2405 {
2406     char	**dblist = NULL, **pplist = NULL, **fllist = NULL;
2407     int	i;
2408     char buf[20]; /* for sprintf " (#%d)" */
2409 
2410     if (csinfo_size == 0)
2411 	return CSCOPE_SUCCESS;
2412 
2413     /* malloc our db and ppath list */
2414     dblist = (char **)alloc(csinfo_size * sizeof(char *));
2415     pplist = (char **)alloc(csinfo_size * sizeof(char *));
2416     fllist = (char **)alloc(csinfo_size * sizeof(char *));
2417     if (dblist == NULL || pplist == NULL || fllist == NULL)
2418     {
2419 	vim_free(dblist);
2420 	vim_free(pplist);
2421 	vim_free(fllist);
2422 	return CSCOPE_FAILURE;
2423     }
2424 
2425     for (i = 0; i < csinfo_size; i++)
2426     {
2427 	dblist[i] = csinfo[i].fname;
2428 	pplist[i] = csinfo[i].ppath;
2429 	fllist[i] = csinfo[i].flags;
2430 	if (csinfo[i].fname != NULL)
2431 	    cs_release_csp(i, FALSE);
2432     }
2433 
2434     /* rebuild the cscope connection list */
2435     for (i = 0; i < csinfo_size; i++)
2436     {
2437 	if (dblist[i] != NULL)
2438 	{
2439 	    cs_add_common(dblist[i], pplist[i], fllist[i]);
2440 	    if (p_csverbose)
2441 	    {
2442 		/* don't use smsg_attr() because we want to display the
2443 		 * connection number in the same line as
2444 		 * "Added cscope database..."
2445 		 */
2446 		sprintf(buf, " (#%d)", i);
2447 		MSG_PUTS_ATTR(buf, hl_attr(HLF_R));
2448 	    }
2449 	}
2450 	vim_free(dblist[i]);
2451 	vim_free(pplist[i]);
2452 	vim_free(fllist[i]);
2453     }
2454     vim_free(dblist);
2455     vim_free(pplist);
2456     vim_free(fllist);
2457 
2458     if (p_csverbose)
2459 	MSG_ATTR(_("All cscope databases reset"), hl_attr(HLF_R) | MSG_HIST);
2460     return CSCOPE_SUCCESS;
2461 } /* cs_reset */
2462 
2463 
2464 /*
2465  * PRIVATE: cs_resolve_file
2466  *
2467  * construct the full pathname to a file found in the cscope database.
2468  * (Prepends ppath, if there is one and if it's not already prepended,
2469  * otherwise just uses the name found.)
2470  *
2471  * we need to prepend the prefix because on some cscope's (e.g., the one that
2472  * ships with Solaris 2.6), the output never has the prefix prepended.
2473  * contrast this with my development system (Digital Unix), which does.
2474  */
2475     static char *
2476 cs_resolve_file(i, name)
2477     int i;
2478     char *name;
2479 {
2480     char *fullname;
2481     int len;
2482 
2483     /*
2484      * ppath is freed when we destroy the cscope connection.
2485      * fullname is freed after cs_make_vim_style_matches, after it's been
2486      * copied into the tag buffer used by vim
2487      */
2488     len = (int)(strlen(name) + 2);
2489     if (csinfo[i].ppath != NULL)
2490 	len += (int)strlen(csinfo[i].ppath);
2491 
2492     if ((fullname = (char *)alloc(len)) == NULL)
2493 	return NULL;
2494 
2495     /*
2496      * note/example: this won't work if the cscope output already starts
2497      * "../.." and the prefix path is also "../..".  if something like this
2498      * happens, you are screwed up and need to fix how you're using cscope.
2499      */
2500     if (csinfo[i].ppath != NULL &&
2501 	(strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) &&
2502 	(name[0] != '/')
2503 #ifdef WIN32
2504 	&& name[0] != '\\' && name[1] != ':'
2505 #endif
2506 	)
2507 	(void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
2508     else
2509 	(void)sprintf(fullname, "%s", name);
2510 
2511     return fullname;
2512 } /* cs_resolve_file */
2513 
2514 
2515 /*
2516  * PRIVATE: cs_show
2517  *
2518  * show all cscope connections
2519  */
2520     static int
2521 cs_show(eap)
2522     exarg_T *eap UNUSED;
2523 {
2524     short i;
2525     if (cs_cnt_connections() == 0)
2526 	MSG_PUTS(_("no cscope connections\n"));
2527     else
2528     {
2529 	MSG_PUTS_ATTR(
2530 	    _(" # pid    database name                       prepend path\n"),
2531 	    hl_attr(HLF_T));
2532 	for (i = 0; i < csinfo_size; i++)
2533 	{
2534 	    if (csinfo[i].fname == NULL)
2535 		continue;
2536 
2537 	    if (csinfo[i].ppath != NULL)
2538 		(void)smsg((char_u *)"%2d %-5ld  %-34s  %-32s",
2539 		    i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
2540 	    else
2541 		(void)smsg((char_u *)"%2d %-5ld  %-34s  <none>",
2542 			   i, (long)csinfo[i].pid, csinfo[i].fname);
2543 	}
2544     }
2545 
2546     wait_return(TRUE);
2547     return CSCOPE_SUCCESS;
2548 } /* cs_show */
2549 
2550 
2551 /*
2552  * PUBLIC: cs_end
2553  *
2554  * Only called when VIM exits to quit any cscope sessions.
2555  */
2556     void
2557 cs_end()
2558 {
2559     int i;
2560 
2561     for (i = 0; i < csinfo_size; i++)
2562 	cs_release_csp(i, TRUE);
2563     vim_free(csinfo);
2564     csinfo_size = 0;
2565 }
2566 
2567 #endif	/* FEAT_CSCOPE */
2568 
2569 /* the end */
2570