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