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