xref: /vim-8.2.3635/src/if_cscope.c (revision 3c5904d2)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * CSCOPE support for Vim added by Andy Kahn <[email protected]>
42ce06f6eSBram Moolenaar  * Ported to Win32 by Sergey Khorev <[email protected]>
5071d4279SBram Moolenaar  *
6071d4279SBram Moolenaar  * The basic idea/structure of cscope for Vim was borrowed from Nvi.  There
7071d4279SBram Moolenaar  * might be a few lines of code that look similar to what Nvi has.
8071d4279SBram Moolenaar  *
9071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
10071d4279SBram Moolenaar  */
11071d4279SBram Moolenaar 
12071d4279SBram Moolenaar #include "vim.h"
13071d4279SBram Moolenaar 
14071d4279SBram Moolenaar #if defined(FEAT_CSCOPE) || defined(PROTO)
15071d4279SBram Moolenaar 
16071d4279SBram Moolenaar #include <sys/types.h>
17071d4279SBram Moolenaar #include <sys/stat.h>
18071d4279SBram Moolenaar #if defined(UNIX)
19071d4279SBram Moolenaar # include <sys/wait.h>
20071d4279SBram Moolenaar #endif
21071d4279SBram Moolenaar #include "if_cscope.h"
22071d4279SBram Moolenaar 
2392b8b2d3SBram Moolenaar static int	    cs_add(exarg_T *eap);
2492b8b2d3SBram Moolenaar static int	    cs_add_common(char *, char *, char *);
2592b8b2d3SBram Moolenaar static int	    cs_check_for_connections(void);
2692b8b2d3SBram Moolenaar static int	    cs_check_for_tags(void);
2792b8b2d3SBram Moolenaar static int	    cs_cnt_connections(void);
2892b8b2d3SBram Moolenaar static int	    cs_create_connection(int i);
29c716c306SBram Moolenaar #ifdef FEAT_QUICKFIX
3092b8b2d3SBram Moolenaar static void	    cs_file_results(FILE *, int *);
31c716c306SBram Moolenaar #endif
3292b8b2d3SBram Moolenaar static void	    cs_fill_results(char *, int , int *, char ***,
3392b8b2d3SBram Moolenaar 			char ***, int *);
3492b8b2d3SBram Moolenaar static int	    cs_find(exarg_T *eap);
3592b8b2d3SBram Moolenaar static int	    cs_find_common(char *opt, char *pat, int, int, int, char_u *cmdline);
3692b8b2d3SBram Moolenaar static int	    cs_help(exarg_T *eap);
3792b8b2d3SBram Moolenaar static int	    cs_insert_filelist(char *, char *, char *,
388767f52fSBram Moolenaar 			stat_T *);
3992b8b2d3SBram Moolenaar static int	    cs_kill(exarg_T *eap);
4092b8b2d3SBram Moolenaar static void	    cs_kill_execute(int, char *);
4192b8b2d3SBram Moolenaar static cscmd_T *    cs_lookup_cmd(exarg_T *eap);
4292b8b2d3SBram Moolenaar static char *	    cs_make_vim_style_matches(char *, char *,
4392b8b2d3SBram Moolenaar 			char *, char *);
4492b8b2d3SBram Moolenaar static char *	    cs_manage_matches(char **, char **, int, mcmd_e);
4592b8b2d3SBram Moolenaar static void	    cs_print_tags_priv(char **, char **, int);
4692b8b2d3SBram Moolenaar static int	    cs_read_prompt(int);
4792b8b2d3SBram Moolenaar static void	    cs_release_csp(int, int freefnpp);
4892b8b2d3SBram Moolenaar static int	    cs_reset(exarg_T *eap);
4992b8b2d3SBram Moolenaar static char *	    cs_resolve_file(int, char *);
5092b8b2d3SBram Moolenaar static int	    cs_show(exarg_T *eap);
51071d4279SBram Moolenaar 
52071d4279SBram Moolenaar 
539fa49da7SBram Moolenaar static csinfo_T *   csinfo = NULL;
542ab2e860SBram Moolenaar static int	    csinfo_size = 0;	// number of items allocated in
552ab2e860SBram Moolenaar 					// csinfo[]
569fa49da7SBram Moolenaar 
572ab2e860SBram Moolenaar static int	    eap_arg_len;    // length of eap->arg, set in
582ab2e860SBram Moolenaar 				    // cs_lookup_cmd()
59071d4279SBram Moolenaar static cscmd_T	    cs_cmds[] =
60071d4279SBram Moolenaar {
61071d4279SBram Moolenaar     { "add",	cs_add,
62071d4279SBram Moolenaar 		N_("Add a new database"),     "add file|dir [pre-path] [flags]", 0 },
63071d4279SBram Moolenaar     { "find",	cs_find,
6480632db6SBram Moolenaar 		N_("Query for a pattern"),    "find a|c|d|e|f|g|i|s|t name", 1 },
65071d4279SBram Moolenaar     { "help",	cs_help,
66071d4279SBram Moolenaar 		N_("Show this message"),      "help", 0 },
67071d4279SBram Moolenaar     { "kill",	cs_kill,
68071d4279SBram Moolenaar 		N_("Kill a connection"),      "kill #", 0 },
69071d4279SBram Moolenaar     { "reset",	cs_reset,
70071d4279SBram Moolenaar 		N_("Reinit all connections"), "reset", 0 },
71071d4279SBram Moolenaar     { "show",	cs_show,
72071d4279SBram Moolenaar 		N_("Show connections"),       "show", 0 },
73af0167faSBram Moolenaar     { NULL, NULL, NULL, NULL, 0 }
74071d4279SBram Moolenaar };
75071d4279SBram Moolenaar 
76071d4279SBram Moolenaar     static void
cs_usage_msg(csid_e x)7768c2f638SBram Moolenaar cs_usage_msg(csid_e x)
78071d4279SBram Moolenaar {
79f9e3e09fSBram Moolenaar     (void)semsg(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
80071d4279SBram Moolenaar }
81071d4279SBram Moolenaar 
82f4580d80SBram Moolenaar static enum
83f4580d80SBram Moolenaar {
842ab2e860SBram Moolenaar     EXP_CSCOPE_SUBCMD,	// expand ":cscope" sub-commands
852ab2e860SBram Moolenaar     EXP_SCSCOPE_SUBCMD,	// expand ":scscope" sub-commands
862ab2e860SBram Moolenaar     EXP_CSCOPE_FIND,	// expand ":cscope find" arguments
872ab2e860SBram Moolenaar     EXP_CSCOPE_KILL	// expand ":cscope kill" arguments
88f4580d80SBram Moolenaar } expand_what;
89f4580d80SBram Moolenaar 
90f4580d80SBram Moolenaar /*
91f4580d80SBram Moolenaar  * Function given to ExpandGeneric() to obtain the cscope command
92f4580d80SBram Moolenaar  * expansion.
93f4580d80SBram Moolenaar  */
94f4580d80SBram Moolenaar     char_u *
get_cscope_name(expand_T * xp UNUSED,int idx)9568c2f638SBram Moolenaar get_cscope_name(expand_T *xp UNUSED, int idx)
96f4580d80SBram Moolenaar {
977bfef80fSBram Moolenaar     int		current_idx;
987bfef80fSBram Moolenaar     int		i;
997bfef80fSBram Moolenaar 
100f4580d80SBram Moolenaar     switch (expand_what)
101f4580d80SBram Moolenaar     {
102f4580d80SBram Moolenaar     case EXP_CSCOPE_SUBCMD:
1032ab2e860SBram Moolenaar 	// Complete with sub-commands of ":cscope":
1042ab2e860SBram Moolenaar 	// add, find, help, kill, reset, show
105f4580d80SBram Moolenaar 	return (char_u *)cs_cmds[idx].name;
1067bfef80fSBram Moolenaar     case EXP_SCSCOPE_SUBCMD:
1072ab2e860SBram Moolenaar 	// Complete with sub-commands of ":scscope": same sub-commands as
1082ab2e860SBram Moolenaar 	// ":cscope" but skip commands which don't support split windows
1097bfef80fSBram Moolenaar 	for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++)
1107bfef80fSBram Moolenaar 	    if (cs_cmds[i].cansplit)
1117bfef80fSBram Moolenaar 		if (current_idx++ == idx)
1127bfef80fSBram Moolenaar 		    break;
1137bfef80fSBram Moolenaar 	return (char_u *)cs_cmds[i].name;
114f4580d80SBram Moolenaar     case EXP_CSCOPE_FIND:
115f4580d80SBram Moolenaar 	{
116f4580d80SBram Moolenaar 	    const char *query_type[] =
117f4580d80SBram Moolenaar 	    {
11880632db6SBram Moolenaar 		"a", "c", "d", "e", "f", "g", "i", "s", "t", NULL
119f4580d80SBram Moolenaar 	    };
120f4580d80SBram Moolenaar 
1212ab2e860SBram Moolenaar 	    // Complete with query type of ":cscope find {query_type}".
1222ab2e860SBram Moolenaar 	    // {query_type} can be letters (c, d, ... a) or numbers (0, 1,
1232ab2e860SBram Moolenaar 	    // ..., 9) but only complete with letters, since numbers are
1242ab2e860SBram Moolenaar 	    // redundant.
125f4580d80SBram Moolenaar 	    return (char_u *)query_type[idx];
126f4580d80SBram Moolenaar 	}
127f4580d80SBram Moolenaar     case EXP_CSCOPE_KILL:
128f4580d80SBram Moolenaar 	{
1299fa49da7SBram Moolenaar 	    static char	connection[5];
130f4580d80SBram Moolenaar 
1312ab2e860SBram Moolenaar 	    // ":cscope kill" accepts connection numbers or partial names of
1322ab2e860SBram Moolenaar 	    // the pathname of the cscope database as argument.  Only complete
1332ab2e860SBram Moolenaar 	    // with connection numbers. -1 can also be used to kill all
1342ab2e860SBram Moolenaar 	    // connections.
1359fa49da7SBram Moolenaar 	    for (i = 0, current_idx = 0; i < csinfo_size; i++)
136f4580d80SBram Moolenaar 	    {
137f4580d80SBram Moolenaar 		if (csinfo[i].fname == NULL)
138f4580d80SBram Moolenaar 		    continue;
139f4580d80SBram Moolenaar 		if (current_idx++ == idx)
140f4580d80SBram Moolenaar 		{
1419fa49da7SBram Moolenaar 		    vim_snprintf(connection, sizeof(connection), "%d", i);
1429fa49da7SBram Moolenaar 		    return (char_u *)connection;
143f4580d80SBram Moolenaar 		}
144f4580d80SBram Moolenaar 	    }
145f4580d80SBram Moolenaar 	    return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
146f4580d80SBram Moolenaar 	}
147f4580d80SBram Moolenaar     default:
148f4580d80SBram Moolenaar 	return NULL;
149f4580d80SBram Moolenaar     }
150f4580d80SBram Moolenaar }
151f4580d80SBram Moolenaar 
152f4580d80SBram Moolenaar /*
153f4580d80SBram Moolenaar  * Handle command line completion for :cscope command.
154f4580d80SBram Moolenaar  */
155f4580d80SBram Moolenaar     void
set_context_in_cscope_cmd(expand_T * xp,char_u * arg,cmdidx_T cmdidx)15668c2f638SBram Moolenaar set_context_in_cscope_cmd(
15768c2f638SBram Moolenaar     expand_T	*xp,
15868c2f638SBram Moolenaar     char_u	*arg,
15968c2f638SBram Moolenaar     cmdidx_T	cmdidx)
160f4580d80SBram Moolenaar {
161f4580d80SBram Moolenaar     char_u	*p;
162f4580d80SBram Moolenaar 
1632ab2e860SBram Moolenaar     // Default: expand subcommands
164f4580d80SBram Moolenaar     xp->xp_context = EXPAND_CSCOPE;
165f4580d80SBram Moolenaar     xp->xp_pattern = arg;
1667bfef80fSBram Moolenaar     expand_what = (cmdidx == CMD_scscope)
1677bfef80fSBram Moolenaar 			? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
168f4580d80SBram Moolenaar 
1692ab2e860SBram Moolenaar     // (part of) subcommand already typed
170f4580d80SBram Moolenaar     if (*arg != NUL)
171f4580d80SBram Moolenaar     {
172f4580d80SBram Moolenaar 	p = skiptowhite(arg);
1732ab2e860SBram Moolenaar 	if (*p != NUL)		    // past first word
174f4580d80SBram Moolenaar 	{
175f4580d80SBram Moolenaar 	    xp->xp_pattern = skipwhite(p);
176f4580d80SBram Moolenaar 	    if (*skiptowhite(xp->xp_pattern) != NUL)
177f4580d80SBram Moolenaar 		xp->xp_context = EXPAND_NOTHING;
178f4580d80SBram Moolenaar 	    else if (STRNICMP(arg, "add", p - arg) == 0)
179f4580d80SBram Moolenaar 		xp->xp_context = EXPAND_FILES;
180f4580d80SBram Moolenaar 	    else if (STRNICMP(arg, "kill", p - arg) == 0)
181f4580d80SBram Moolenaar 		expand_what = EXP_CSCOPE_KILL;
182f4580d80SBram Moolenaar 	    else if (STRNICMP(arg, "find", p - arg) == 0)
183f4580d80SBram Moolenaar 		expand_what = EXP_CSCOPE_FIND;
184f4580d80SBram Moolenaar 	    else
185f4580d80SBram Moolenaar 		xp->xp_context = EXPAND_NOTHING;
186f4580d80SBram Moolenaar 	}
187f4580d80SBram Moolenaar     }
188f4580d80SBram Moolenaar }
189f4580d80SBram Moolenaar 
190071d4279SBram Moolenaar /*
191f4580d80SBram Moolenaar  * Find the command, print help if invalid, and then call the corresponding
192f4580d80SBram Moolenaar  * command function.
193071d4279SBram Moolenaar  */
194071d4279SBram Moolenaar     static void
do_cscope_general(exarg_T * eap,int make_split UNUSED)19568c2f638SBram Moolenaar do_cscope_general(
19668c2f638SBram Moolenaar     exarg_T	*eap,
1972ab2e860SBram Moolenaar     int		make_split UNUSED) // whether to split window
198071d4279SBram Moolenaar {
199071d4279SBram Moolenaar     cscmd_T *cmdp;
200071d4279SBram Moolenaar 
201071d4279SBram Moolenaar     if ((cmdp = cs_lookup_cmd(eap)) == NULL)
202071d4279SBram Moolenaar     {
203071d4279SBram Moolenaar 	cs_help(eap);
204071d4279SBram Moolenaar 	return;
205071d4279SBram Moolenaar     }
206071d4279SBram Moolenaar 
207071d4279SBram Moolenaar     if (make_split)
208071d4279SBram Moolenaar     {
209071d4279SBram Moolenaar 	if (!cmdp->cansplit)
210071d4279SBram Moolenaar 	{
21132526b3cSBram Moolenaar 	    (void)msg_puts(_("This cscope command does not support splitting the window.\n"));
212071d4279SBram Moolenaar 	    return;
213071d4279SBram Moolenaar 	}
214071d4279SBram Moolenaar 	postponed_split = -1;
215e1004401SBram Moolenaar 	postponed_split_flags = cmdmod.cmod_split;
216e1004401SBram Moolenaar 	postponed_split_tab = cmdmod.cmod_tab;
217071d4279SBram Moolenaar     }
218071d4279SBram Moolenaar 
219071d4279SBram Moolenaar     cmdp->func(eap);
220071d4279SBram Moolenaar 
221071d4279SBram Moolenaar     postponed_split_flags = 0;
222d326ce83SBram Moolenaar     postponed_split_tab = 0;
223071d4279SBram Moolenaar }
224071d4279SBram Moolenaar 
225071d4279SBram Moolenaar /*
226d4db7719SBram Moolenaar  * Implementation of ":cscope" and ":lcscope"
227071d4279SBram Moolenaar  */
228071d4279SBram Moolenaar     void
ex_cscope(exarg_T * eap)229d4db7719SBram Moolenaar ex_cscope(exarg_T *eap)
230071d4279SBram Moolenaar {
231071d4279SBram Moolenaar     do_cscope_general(eap, FALSE);
232071d4279SBram Moolenaar }
233071d4279SBram Moolenaar 
234071d4279SBram Moolenaar /*
235d4db7719SBram Moolenaar  * Implementation of ":scscope". Same as ex_cscope(), but splits window, too.
236071d4279SBram Moolenaar  */
237071d4279SBram Moolenaar     void
ex_scscope(exarg_T * eap)238d4db7719SBram Moolenaar ex_scscope(exarg_T *eap)
239071d4279SBram Moolenaar {
240071d4279SBram Moolenaar     do_cscope_general(eap, TRUE);
241071d4279SBram Moolenaar }
242071d4279SBram Moolenaar 
243071d4279SBram Moolenaar /*
244d4db7719SBram Moolenaar  * Implementation of ":cstag"
245071d4279SBram Moolenaar  */
246071d4279SBram Moolenaar     void
ex_cstag(exarg_T * eap)247d4db7719SBram Moolenaar ex_cstag(exarg_T *eap)
248071d4279SBram Moolenaar {
249071d4279SBram Moolenaar     int ret = FALSE;
250071d4279SBram Moolenaar 
251446cb837SBram Moolenaar     if (*eap->arg == NUL)
252071d4279SBram Moolenaar     {
253f9e3e09fSBram Moolenaar 	(void)emsg(_("E562: Usage: cstag <ident>"));
254071d4279SBram Moolenaar 	return;
255071d4279SBram Moolenaar     }
256071d4279SBram Moolenaar 
257071d4279SBram Moolenaar     switch (p_csto)
258071d4279SBram Moolenaar     {
259071d4279SBram Moolenaar     case 0 :
260071d4279SBram Moolenaar 	if (cs_check_for_connections())
261071d4279SBram Moolenaar 	{
262c7453f52SBram Moolenaar 	    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
2637fd73200SBram Moolenaar 						       FALSE, *eap->cmdlinep);
264071d4279SBram Moolenaar 	    if (ret == FALSE)
265071d4279SBram Moolenaar 	    {
266071d4279SBram Moolenaar 		cs_free_tags();
267071d4279SBram Moolenaar 		if (msg_col)
268071d4279SBram Moolenaar 		    msg_putchar('\n');
269071d4279SBram Moolenaar 
270071d4279SBram Moolenaar 		if (cs_check_for_tags())
271071d4279SBram Moolenaar 		    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
272071d4279SBram Moolenaar 	    }
273071d4279SBram Moolenaar 	}
274071d4279SBram Moolenaar 	else if (cs_check_for_tags())
275071d4279SBram Moolenaar 	{
276071d4279SBram Moolenaar 	    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
277071d4279SBram Moolenaar 	}
278071d4279SBram Moolenaar 	break;
279071d4279SBram Moolenaar     case 1 :
280071d4279SBram Moolenaar 	if (cs_check_for_tags())
281071d4279SBram Moolenaar 	{
282071d4279SBram Moolenaar 	    ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
283071d4279SBram Moolenaar 	    if (ret == FALSE)
284071d4279SBram Moolenaar 	    {
285071d4279SBram Moolenaar 		if (msg_col)
286071d4279SBram Moolenaar 		    msg_putchar('\n');
287071d4279SBram Moolenaar 
288071d4279SBram Moolenaar 		if (cs_check_for_connections())
289071d4279SBram Moolenaar 		{
290071d4279SBram Moolenaar 		    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
2917fd73200SBram Moolenaar 						FALSE, FALSE, *eap->cmdlinep);
292071d4279SBram Moolenaar 		    if (ret == FALSE)
293071d4279SBram Moolenaar 			cs_free_tags();
294071d4279SBram Moolenaar 		}
295071d4279SBram Moolenaar 	    }
296071d4279SBram Moolenaar 	}
297071d4279SBram Moolenaar 	else if (cs_check_for_connections())
298071d4279SBram Moolenaar 	{
299c7453f52SBram Moolenaar 	    ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
3007fd73200SBram Moolenaar 						       FALSE, *eap->cmdlinep);
301071d4279SBram Moolenaar 	    if (ret == FALSE)
302071d4279SBram Moolenaar 		cs_free_tags();
303071d4279SBram Moolenaar 	}
304071d4279SBram Moolenaar 	break;
305071d4279SBram Moolenaar     default :
306071d4279SBram Moolenaar 	break;
307071d4279SBram Moolenaar     }
308071d4279SBram Moolenaar 
309071d4279SBram Moolenaar     if (!ret)
310071d4279SBram Moolenaar     {
311f9e3e09fSBram Moolenaar 	(void)emsg(_("E257: cstag: tag not found"));
3124033c55eSBram Moolenaar #if defined(FEAT_QUICKFIX)
313071d4279SBram Moolenaar 	g_do_tagpreview = 0;
314071d4279SBram Moolenaar #endif
315071d4279SBram Moolenaar     }
316071d4279SBram Moolenaar 
317d4db7719SBram Moolenaar }
318071d4279SBram Moolenaar 
319071d4279SBram Moolenaar 
320071d4279SBram Moolenaar /*
321d4db7719SBram Moolenaar  * This simulates a vim_fgets(), but for cscope, returns the next line
322071d4279SBram Moolenaar  * from the cscope output.  should only be called from find_tags()
323071d4279SBram Moolenaar  *
324071d4279SBram Moolenaar  * returns TRUE if eof, FALSE otherwise
325071d4279SBram Moolenaar  */
326071d4279SBram Moolenaar     int
cs_fgets(char_u * buf,int size)32768c2f638SBram Moolenaar cs_fgets(char_u *buf, int size)
328071d4279SBram Moolenaar {
329071d4279SBram Moolenaar     char *p;
330071d4279SBram Moolenaar 
331071d4279SBram Moolenaar     if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
332071d4279SBram Moolenaar 	return TRUE;
333d2ac984aSBram Moolenaar     vim_strncpy(buf, (char_u *)p, size - 1);
334071d4279SBram Moolenaar 
335071d4279SBram Moolenaar     return FALSE;
3362ab2e860SBram Moolenaar }
337071d4279SBram Moolenaar 
338071d4279SBram Moolenaar 
339071d4279SBram Moolenaar /*
340d4db7719SBram Moolenaar  * Called only from do_tag(), when popping the tag stack.
341071d4279SBram Moolenaar  */
342071d4279SBram Moolenaar     void
cs_free_tags(void)34368c2f638SBram Moolenaar cs_free_tags(void)
344071d4279SBram Moolenaar {
345071d4279SBram Moolenaar     cs_manage_matches(NULL, NULL, -1, Free);
346071d4279SBram Moolenaar }
347071d4279SBram Moolenaar 
348071d4279SBram Moolenaar 
349071d4279SBram Moolenaar /*
350d4db7719SBram Moolenaar  * Called from do_tag().
351071d4279SBram Moolenaar  */
352071d4279SBram Moolenaar     void
cs_print_tags(void)35368c2f638SBram Moolenaar cs_print_tags(void)
354071d4279SBram Moolenaar {
355071d4279SBram Moolenaar     cs_manage_matches(NULL, NULL, -1, Print);
356071d4279SBram Moolenaar }
357071d4279SBram Moolenaar 
358071d4279SBram Moolenaar 
359071d4279SBram Moolenaar /*
360071d4279SBram Moolenaar  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
361071d4279SBram Moolenaar  *
362071d4279SBram Moolenaar  *		Checks for the existence of a |cscope| connection.  If no
363071d4279SBram Moolenaar  *		parameters are specified, then the function returns:
364071d4279SBram Moolenaar  *
365071d4279SBram Moolenaar  *		0, if cscope was not available (not compiled in), or if there
366071d4279SBram Moolenaar  *		are no cscope connections; or
367071d4279SBram Moolenaar  *		1, if there is at least one cscope connection.
368071d4279SBram Moolenaar  *
369071d4279SBram Moolenaar  *		If parameters are specified, then the value of {num}
370071d4279SBram Moolenaar  *		determines how existence of a cscope connection is checked:
371071d4279SBram Moolenaar  *
372071d4279SBram Moolenaar  *		{num}	Description of existence check
373071d4279SBram Moolenaar  *		-----	------------------------------
374071d4279SBram Moolenaar  *		0	Same as no parameters (e.g., "cscope_connection()").
375071d4279SBram Moolenaar  *		1	Ignore {prepend}, and use partial string matches for
376071d4279SBram Moolenaar  *			{dbpath}.
377071d4279SBram Moolenaar  *		2	Ignore {prepend}, and use exact string matches for
378071d4279SBram Moolenaar  *			{dbpath}.
379071d4279SBram Moolenaar  *		3	Use {prepend}, use partial string matches for both
380071d4279SBram Moolenaar  *			{dbpath} and {prepend}.
381071d4279SBram Moolenaar  *		4	Use {prepend}, use exact string matches for both
382071d4279SBram Moolenaar  *			{dbpath} and {prepend}.
383071d4279SBram Moolenaar  *
384071d4279SBram Moolenaar  *		Note: All string comparisons are case sensitive!
385071d4279SBram Moolenaar  */
386071d4279SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
387af7645d3SBram Moolenaar     static int
cs_connection(int num,char_u * dbpath,char_u * ppath)38868c2f638SBram Moolenaar cs_connection(int num, char_u *dbpath, char_u *ppath)
389071d4279SBram Moolenaar {
390071d4279SBram Moolenaar     int i;
391071d4279SBram Moolenaar 
392071d4279SBram Moolenaar     if (num < 0 || num > 4 || (num > 0 && !dbpath))
393071d4279SBram Moolenaar 	return FALSE;
394071d4279SBram Moolenaar 
3959fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
396071d4279SBram Moolenaar     {
397071d4279SBram Moolenaar 	if (!csinfo[i].fname)
398071d4279SBram Moolenaar 	    continue;
399071d4279SBram Moolenaar 
400071d4279SBram Moolenaar 	if (num == 0)
401071d4279SBram Moolenaar 	    return TRUE;
402071d4279SBram Moolenaar 
403071d4279SBram Moolenaar 	switch (num)
404071d4279SBram Moolenaar 	{
405071d4279SBram Moolenaar 	case 1:
406071d4279SBram Moolenaar 	    if (strstr(csinfo[i].fname, (char *)dbpath))
407071d4279SBram Moolenaar 		return TRUE;
408071d4279SBram Moolenaar 	    break;
409071d4279SBram Moolenaar 	case 2:
410071d4279SBram Moolenaar 	    if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
411071d4279SBram Moolenaar 		return TRUE;
412071d4279SBram Moolenaar 	    break;
413071d4279SBram Moolenaar 	case 3:
414071d4279SBram Moolenaar 	    if (strstr(csinfo[i].fname, (char *)dbpath)
415071d4279SBram Moolenaar 		    && ((!ppath && !csinfo[i].ppath)
416071d4279SBram Moolenaar 			|| (ppath
417071d4279SBram Moolenaar 			    && csinfo[i].ppath
418071d4279SBram Moolenaar 			    && strstr(csinfo[i].ppath, (char *)ppath))))
419071d4279SBram Moolenaar 		return TRUE;
420071d4279SBram Moolenaar 	    break;
421071d4279SBram Moolenaar 	case 4:
422071d4279SBram Moolenaar 	    if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
423071d4279SBram Moolenaar 		    && ((!ppath && !csinfo[i].ppath)
424071d4279SBram Moolenaar 			|| (ppath
425071d4279SBram Moolenaar 			    && csinfo[i].ppath
426071d4279SBram Moolenaar 			    && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
427071d4279SBram Moolenaar 		return TRUE;
428071d4279SBram Moolenaar 	    break;
429071d4279SBram Moolenaar 	}
430071d4279SBram Moolenaar     }
431071d4279SBram Moolenaar 
432071d4279SBram Moolenaar     return FALSE;
433af7645d3SBram Moolenaar }
434af7645d3SBram Moolenaar 
435071d4279SBram Moolenaar #endif
436071d4279SBram Moolenaar 
437071d4279SBram Moolenaar 
438071d4279SBram Moolenaar /*
439071d4279SBram Moolenaar  * PRIVATE functions
440071d4279SBram Moolenaar  ****************************************************************************/
441071d4279SBram Moolenaar 
442071d4279SBram Moolenaar /*
443d4db7719SBram Moolenaar  * Add cscope database or a directory name (to look for cscope.out)
444d4db7719SBram Moolenaar  * to the cscope connection list.
445071d4279SBram Moolenaar  */
446071d4279SBram Moolenaar     static int
cs_add(exarg_T * eap UNUSED)44768c2f638SBram Moolenaar cs_add(exarg_T *eap UNUSED)
448071d4279SBram Moolenaar {
449071d4279SBram Moolenaar     char *fname, *ppath, *flags = NULL;
450071d4279SBram Moolenaar 
451071d4279SBram Moolenaar     if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL)
452071d4279SBram Moolenaar     {
453071d4279SBram Moolenaar 	cs_usage_msg(Add);
454071d4279SBram Moolenaar 	return CSCOPE_FAILURE;
455071d4279SBram Moolenaar     }
456071d4279SBram Moolenaar     if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
457071d4279SBram Moolenaar 	flags = strtok((char *)NULL, (const char *)" ");
458071d4279SBram Moolenaar 
459071d4279SBram Moolenaar     return cs_add_common(fname, ppath, flags);
460071d4279SBram Moolenaar }
461071d4279SBram Moolenaar 
462071d4279SBram Moolenaar     static void
cs_stat_emsg(char * fname)46368c2f638SBram Moolenaar cs_stat_emsg(char *fname)
464071d4279SBram Moolenaar {
465*3c5904d2SJames McCoy     int err = errno;
466*3c5904d2SJames McCoy     (void)semsg(_("E563: stat(%s) error: %d"), fname, err);
467071d4279SBram Moolenaar }
468071d4279SBram Moolenaar 
469071d4279SBram Moolenaar 
470071d4279SBram Moolenaar /*
471d4db7719SBram Moolenaar  * The common routine to add a new cscope connection.  Called by
472d4db7719SBram Moolenaar  * cs_add() and cs_reset().  I really don't like to do this, but this
473071d4279SBram Moolenaar  * routine uses a number of goto statements.
474071d4279SBram Moolenaar  */
475071d4279SBram Moolenaar     static int
cs_add_common(char * arg1,char * arg2,char * flags)47668c2f638SBram Moolenaar cs_add_common(
4772ab2e860SBram Moolenaar     char *arg1,	    // filename - may contain environment variables
4782ab2e860SBram Moolenaar     char *arg2,	    // prepend path - may contain environment variables
47968c2f638SBram Moolenaar     char *flags)
480071d4279SBram Moolenaar {
4818767f52fSBram Moolenaar     stat_T	statbuf;
482071d4279SBram Moolenaar     int		ret;
483071d4279SBram Moolenaar     char	*fname = NULL;
484071d4279SBram Moolenaar     char	*fname2 = NULL;
485071d4279SBram Moolenaar     char	*ppath = NULL;
486071d4279SBram Moolenaar     int		i;
487cab465a6SBram Moolenaar     int		len;
488cab465a6SBram Moolenaar     int		usedlen = 0;
489cab465a6SBram Moolenaar     char_u	*fbuf = NULL;
490071d4279SBram Moolenaar 
4912ab2e860SBram Moolenaar     // get the filename (arg1), expand it, and try to stat it
492c799fe20SBram Moolenaar     if ((fname = alloc(MAXPATHL + 1)) == NULL)
493071d4279SBram Moolenaar 	goto add_err;
494071d4279SBram Moolenaar 
495071d4279SBram Moolenaar     expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
496cab465a6SBram Moolenaar     len = (int)STRLEN(fname);
497cab465a6SBram Moolenaar     fbuf = (char_u *)fname;
49800136dc3SBram Moolenaar     (void)modify_fname((char_u *)":p", FALSE, &usedlen,
499cab465a6SBram Moolenaar 					      (char_u **)&fname, &fbuf, &len);
500cab465a6SBram Moolenaar     if (fname == NULL)
501cab465a6SBram Moolenaar 	goto add_err;
502cab465a6SBram Moolenaar     fname = (char *)vim_strnsave((char_u *)fname, len);
503cab465a6SBram Moolenaar     vim_free(fbuf);
504b005cd80SBram Moolenaar 
5058767f52fSBram Moolenaar     ret = mch_stat(fname, &statbuf);
506071d4279SBram Moolenaar     if (ret < 0)
507071d4279SBram Moolenaar     {
508071d4279SBram Moolenaar staterr:
509071d4279SBram Moolenaar 	if (p_csverbose)
510071d4279SBram Moolenaar 	    cs_stat_emsg(fname);
511071d4279SBram Moolenaar 	goto add_err;
512071d4279SBram Moolenaar     }
513071d4279SBram Moolenaar 
5142ab2e860SBram Moolenaar     // get the prepend path (arg2), expand it, and try to stat it
515071d4279SBram Moolenaar     if (arg2 != NULL)
516071d4279SBram Moolenaar     {
5178767f52fSBram Moolenaar 	stat_T	    statbuf2;
518071d4279SBram Moolenaar 
519c799fe20SBram Moolenaar 	if ((ppath = alloc(MAXPATHL + 1)) == NULL)
520071d4279SBram Moolenaar 	    goto add_err;
521071d4279SBram Moolenaar 
522071d4279SBram Moolenaar 	expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
5238767f52fSBram Moolenaar 	ret = mch_stat(ppath, &statbuf2);
524071d4279SBram Moolenaar 	if (ret < 0)
525071d4279SBram Moolenaar 	    goto staterr;
526071d4279SBram Moolenaar     }
527071d4279SBram Moolenaar 
5282ab2e860SBram Moolenaar     // if filename is a directory, append the cscope database name to it
529d569bb02SBram Moolenaar     if (S_ISDIR(statbuf.st_mode))
530071d4279SBram Moolenaar     {
531c799fe20SBram Moolenaar 	fname2 = alloc(strlen(CSCOPE_DBFILE) + strlen(fname) + 2);
532071d4279SBram Moolenaar 	if (fname2 == NULL)
533071d4279SBram Moolenaar 	    goto add_err;
534071d4279SBram Moolenaar 
535071d4279SBram Moolenaar 	while (fname[strlen(fname)-1] == '/'
5364f97475dSBram Moolenaar #ifdef MSWIN
537071d4279SBram Moolenaar 		|| fname[strlen(fname)-1] == '\\'
538071d4279SBram Moolenaar #endif
539071d4279SBram Moolenaar 		)
540071d4279SBram Moolenaar 	{
541071d4279SBram Moolenaar 	    fname[strlen(fname)-1] = '\0';
54264404479SBram Moolenaar 	    if (fname[0] == '\0')
543071d4279SBram Moolenaar 		break;
544071d4279SBram Moolenaar 	}
545071d4279SBram Moolenaar 	if (fname[0] == '\0')
546071d4279SBram Moolenaar 	    (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
547071d4279SBram Moolenaar 	else
548071d4279SBram Moolenaar 	    (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
549071d4279SBram Moolenaar 
5508767f52fSBram Moolenaar 	ret = mch_stat(fname2, &statbuf);
551071d4279SBram Moolenaar 	if (ret < 0)
552071d4279SBram Moolenaar 	{
553071d4279SBram Moolenaar 	    if (p_csverbose)
554071d4279SBram Moolenaar 		cs_stat_emsg(fname2);
555071d4279SBram Moolenaar 	    goto add_err;
556071d4279SBram Moolenaar 	}
557071d4279SBram Moolenaar 
558071d4279SBram Moolenaar 	i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
559071d4279SBram Moolenaar     }
560071d4279SBram Moolenaar     else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
561071d4279SBram Moolenaar     {
562071d4279SBram Moolenaar 	i = cs_insert_filelist(fname, ppath, flags, &statbuf);
563071d4279SBram Moolenaar     }
564071d4279SBram Moolenaar     else
565071d4279SBram Moolenaar     {
566071d4279SBram Moolenaar 	if (p_csverbose)
567f9e3e09fSBram Moolenaar 	    (void)semsg(
568071d4279SBram Moolenaar 		_("E564: %s is not a directory or a valid cscope database"),
569071d4279SBram Moolenaar 		fname);
570071d4279SBram Moolenaar 	goto add_err;
571071d4279SBram Moolenaar     }
572071d4279SBram Moolenaar 
573071d4279SBram Moolenaar     if (i != -1)
574071d4279SBram Moolenaar     {
575071d4279SBram Moolenaar 	if (cs_create_connection(i) == CSCOPE_FAILURE
576071d4279SBram Moolenaar 		|| cs_read_prompt(i) == CSCOPE_FAILURE)
577071d4279SBram Moolenaar 	{
578071d4279SBram Moolenaar 	    cs_release_csp(i, TRUE);
579071d4279SBram Moolenaar 	    goto add_err;
580071d4279SBram Moolenaar 	}
581071d4279SBram Moolenaar 
582071d4279SBram Moolenaar 	if (p_csverbose)
583071d4279SBram Moolenaar 	{
584071d4279SBram Moolenaar 	    msg_clr_eos();
5858820b486SBram Moolenaar 	    (void)smsg_attr(HL_ATTR(HLF_R),
586f9e3e09fSBram Moolenaar 			    _("Added cscope database %s"),
587071d4279SBram Moolenaar 			    csinfo[i].fname);
588071d4279SBram Moolenaar 	}
589071d4279SBram Moolenaar     }
590071d4279SBram Moolenaar 
591071d4279SBram Moolenaar     vim_free(fname);
592071d4279SBram Moolenaar     vim_free(fname2);
593071d4279SBram Moolenaar     vim_free(ppath);
594071d4279SBram Moolenaar     return CSCOPE_SUCCESS;
595071d4279SBram Moolenaar 
596071d4279SBram Moolenaar add_err:
597071d4279SBram Moolenaar     vim_free(fname2);
598071d4279SBram Moolenaar     vim_free(fname);
599071d4279SBram Moolenaar     vim_free(ppath);
600071d4279SBram Moolenaar     return CSCOPE_FAILURE;
6012ab2e860SBram Moolenaar }
602071d4279SBram Moolenaar 
603071d4279SBram Moolenaar 
604071d4279SBram Moolenaar     static int
cs_check_for_connections(void)60568c2f638SBram Moolenaar cs_check_for_connections(void)
606071d4279SBram Moolenaar {
607071d4279SBram Moolenaar     return (cs_cnt_connections() > 0);
6082ab2e860SBram Moolenaar }
609071d4279SBram Moolenaar 
610071d4279SBram Moolenaar 
611071d4279SBram Moolenaar     static int
cs_check_for_tags(void)61268c2f638SBram Moolenaar cs_check_for_tags(void)
613071d4279SBram Moolenaar {
61475c50c46SBram Moolenaar     return (p_tags[0] != NUL && curbuf->b_p_tags != NULL);
6152ab2e860SBram Moolenaar }
616071d4279SBram Moolenaar 
617071d4279SBram Moolenaar 
618071d4279SBram Moolenaar /*
619d4db7719SBram Moolenaar  * Count the number of cscope connections.
620071d4279SBram Moolenaar  */
621071d4279SBram Moolenaar     static int
cs_cnt_connections(void)62268c2f638SBram Moolenaar cs_cnt_connections(void)
623071d4279SBram Moolenaar {
624071d4279SBram Moolenaar     short i;
625071d4279SBram Moolenaar     short cnt = 0;
626071d4279SBram Moolenaar 
6279fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
628071d4279SBram Moolenaar     {
629071d4279SBram Moolenaar 	if (csinfo[i].fname != NULL)
630071d4279SBram Moolenaar 	    cnt++;
631071d4279SBram Moolenaar     }
632071d4279SBram Moolenaar     return cnt;
6332ab2e860SBram Moolenaar }
634071d4279SBram Moolenaar 
635071d4279SBram Moolenaar     static void
cs_reading_emsg(int idx)63668c2f638SBram Moolenaar cs_reading_emsg(
6372ab2e860SBram Moolenaar     int idx)	// connection index
638071d4279SBram Moolenaar {
639b5443cc4SBram Moolenaar     semsg(_("E262: error reading cscope connection %d"), idx);
640071d4279SBram Moolenaar }
641071d4279SBram Moolenaar 
642071d4279SBram Moolenaar #define	CSREAD_BUFSIZE	2048
643071d4279SBram Moolenaar /*
644d4db7719SBram Moolenaar  * Count the number of matches for a given cscope connection.
645071d4279SBram Moolenaar  */
646071d4279SBram Moolenaar     static int
cs_cnt_matches(int idx)64768c2f638SBram Moolenaar cs_cnt_matches(int idx)
648071d4279SBram Moolenaar {
649071d4279SBram Moolenaar     char *stok;
650071d4279SBram Moolenaar     char *buf;
6511274d334SBram Moolenaar     int nlines = 0;
652071d4279SBram Moolenaar 
653c799fe20SBram Moolenaar     buf = alloc(CSREAD_BUFSIZE);
654071d4279SBram Moolenaar     if (buf == NULL)
655071d4279SBram Moolenaar 	return 0;
656071d4279SBram Moolenaar     for (;;)
657071d4279SBram Moolenaar     {
658071d4279SBram Moolenaar 	if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp))
659071d4279SBram Moolenaar 	{
660071d4279SBram Moolenaar 	    if (feof(csinfo[idx].fr_fp))
661071d4279SBram Moolenaar 		errno = EIO;
662071d4279SBram Moolenaar 
663071d4279SBram Moolenaar 	    cs_reading_emsg(idx);
664071d4279SBram Moolenaar 
665071d4279SBram Moolenaar 	    vim_free(buf);
666071d4279SBram Moolenaar 	    return -1;
667071d4279SBram Moolenaar 	}
668071d4279SBram Moolenaar 
669071d4279SBram Moolenaar 	/*
670071d4279SBram Moolenaar 	 * If the database is out of date, or there's some other problem,
671071d4279SBram Moolenaar 	 * cscope will output error messages before the number-of-lines output.
672071d4279SBram Moolenaar 	 * Display/discard any output that doesn't match what we want.
67384c4d79aSBram Moolenaar 	 * Accept "\S*cscope: X lines", also matches "mlcscope".
6741274d334SBram Moolenaar 	 * Bail out for the "Unable to search" error.
675071d4279SBram Moolenaar 	 */
676a172b63aSBram Moolenaar 	if (strstr((const char *)buf, "Unable to search database") != NULL)
6771274d334SBram Moolenaar 	    break;
678071d4279SBram Moolenaar 	if ((stok = strtok(buf, (const char *)" ")) == NULL)
679071d4279SBram Moolenaar 	    continue;
68084c4d79aSBram Moolenaar 	if (strstr((const char *)stok, "cscope:") == NULL)
681071d4279SBram Moolenaar 	    continue;
682071d4279SBram Moolenaar 
683071d4279SBram Moolenaar 	if ((stok = strtok(NULL, (const char *)" ")) == NULL)
684071d4279SBram Moolenaar 	    continue;
685071d4279SBram Moolenaar 	nlines = atoi(stok);
686071d4279SBram Moolenaar 	if (nlines < 0)
687071d4279SBram Moolenaar 	{
688071d4279SBram Moolenaar 	    nlines = 0;
689071d4279SBram Moolenaar 	    break;
690071d4279SBram Moolenaar 	}
691071d4279SBram Moolenaar 
692071d4279SBram Moolenaar 	if ((stok = strtok(NULL, (const char *)" ")) == NULL)
693071d4279SBram Moolenaar 	    continue;
694071d4279SBram Moolenaar 	if (strncmp((const char *)stok, "lines", 5))
695071d4279SBram Moolenaar 	    continue;
696071d4279SBram Moolenaar 
697071d4279SBram Moolenaar 	break;
698071d4279SBram Moolenaar     }
699071d4279SBram Moolenaar 
700071d4279SBram Moolenaar     vim_free(buf);
701071d4279SBram Moolenaar     return nlines;
7022ab2e860SBram Moolenaar }
703071d4279SBram Moolenaar 
704071d4279SBram Moolenaar 
705071d4279SBram Moolenaar /*
706071d4279SBram Moolenaar  * Creates the actual cscope command query from what the user entered.
707071d4279SBram Moolenaar  */
708071d4279SBram Moolenaar     static char *
cs_create_cmd(char * csoption,char * pattern)70968c2f638SBram Moolenaar cs_create_cmd(char *csoption, char *pattern)
710071d4279SBram Moolenaar {
711071d4279SBram Moolenaar     char *cmd;
712071d4279SBram Moolenaar     short search;
71380b6a0e8SBram Moolenaar     char *pat;
714071d4279SBram Moolenaar 
715071d4279SBram Moolenaar     switch (csoption[0])
716071d4279SBram Moolenaar     {
717071d4279SBram Moolenaar     case '0' : case 's' :
718071d4279SBram Moolenaar 	search = 0;
719071d4279SBram Moolenaar 	break;
720071d4279SBram Moolenaar     case '1' : case 'g' :
721071d4279SBram Moolenaar 	search = 1;
722071d4279SBram Moolenaar 	break;
723071d4279SBram Moolenaar     case '2' : case 'd' :
724071d4279SBram Moolenaar 	search = 2;
725071d4279SBram Moolenaar 	break;
726071d4279SBram Moolenaar     case '3' : case 'c' :
727071d4279SBram Moolenaar 	search = 3;
728071d4279SBram Moolenaar 	break;
729071d4279SBram Moolenaar     case '4' : case 't' :
730071d4279SBram Moolenaar 	search = 4;
731071d4279SBram Moolenaar 	break;
732071d4279SBram Moolenaar     case '6' : case 'e' :
733071d4279SBram Moolenaar 	search = 6;
734071d4279SBram Moolenaar 	break;
735071d4279SBram Moolenaar     case '7' : case 'f' :
736071d4279SBram Moolenaar 	search = 7;
737071d4279SBram Moolenaar 	break;
738071d4279SBram Moolenaar     case '8' : case 'i' :
739071d4279SBram Moolenaar 	search = 8;
740071d4279SBram Moolenaar 	break;
741b12e7ef9SBram Moolenaar     case '9' : case 'a' :
742b12e7ef9SBram Moolenaar 	search = 9;
743b12e7ef9SBram Moolenaar 	break;
744071d4279SBram Moolenaar     default :
745f9e3e09fSBram Moolenaar 	(void)emsg(_("E561: unknown cscope search type"));
746071d4279SBram Moolenaar 	cs_usage_msg(Find);
747071d4279SBram Moolenaar 	return NULL;
748071d4279SBram Moolenaar     }
749071d4279SBram Moolenaar 
7502ab2e860SBram Moolenaar     // Skip white space before the patter, except for text and pattern search,
7512ab2e860SBram Moolenaar     // they may want to use the leading white space.
75280b6a0e8SBram Moolenaar     pat = pattern;
75380b6a0e8SBram Moolenaar     if (search != 4 && search != 6)
7541c465444SBram Moolenaar 	while VIM_ISWHITE(*pat)
75580b6a0e8SBram Moolenaar 	    ++pat;
75680b6a0e8SBram Moolenaar 
757c799fe20SBram Moolenaar     if ((cmd = alloc(strlen(pat) + 2)) == NULL)
758071d4279SBram Moolenaar 	return NULL;
759071d4279SBram Moolenaar 
76080b6a0e8SBram Moolenaar     (void)sprintf(cmd, "%d%s", search, pat);
761071d4279SBram Moolenaar 
762071d4279SBram Moolenaar     return cmd;
7632ab2e860SBram Moolenaar }
764071d4279SBram Moolenaar 
765071d4279SBram Moolenaar 
766071d4279SBram Moolenaar /*
767071d4279SBram Moolenaar  * This piece of code was taken/adapted from nvi.  do we need to add
768071d4279SBram Moolenaar  * the BSD license notice?
769071d4279SBram Moolenaar  */
770071d4279SBram Moolenaar     static int
cs_create_connection(int i)77168c2f638SBram Moolenaar cs_create_connection(int i)
772071d4279SBram Moolenaar {
77302b06313SBram Moolenaar #ifdef UNIX
77402b06313SBram Moolenaar     int		to_cs[2], from_cs[2];
775071d4279SBram Moolenaar #endif
77602b06313SBram Moolenaar     int		len;
77702b06313SBram Moolenaar     char	*prog, *cmd, *ppath = NULL;
7784f97475dSBram Moolenaar #ifdef MSWIN
77902b06313SBram Moolenaar     int		fd;
78002b06313SBram Moolenaar     SECURITY_ATTRIBUTES sa;
78102b06313SBram Moolenaar     PROCESS_INFORMATION pi;
78202b06313SBram Moolenaar     STARTUPINFO si;
78302b06313SBram Moolenaar     BOOL	pipe_stdin = FALSE, pipe_stdout = FALSE;
78402b06313SBram Moolenaar     HANDLE	stdin_rd, stdout_rd;
78502b06313SBram Moolenaar     HANDLE	stdout_wr, stdin_wr;
78602b06313SBram Moolenaar     BOOL	created;
787cea912afSBram Moolenaar # if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
7885365c4d5SBram Moolenaar #  define OPEN_OH_ARGTYPE intptr_t
7895365c4d5SBram Moolenaar # else
7905365c4d5SBram Moolenaar #  define OPEN_OH_ARGTYPE long
7915365c4d5SBram Moolenaar # endif
7925365c4d5SBram Moolenaar #endif
793071d4279SBram Moolenaar 
79402b06313SBram Moolenaar #if defined(UNIX)
795071d4279SBram Moolenaar     /*
796071d4279SBram Moolenaar      * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
797071d4279SBram Moolenaar      * from_cs[0] and writes to to_cs[1].
798071d4279SBram Moolenaar      */
799071d4279SBram Moolenaar     to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
800071d4279SBram Moolenaar     if (pipe(to_cs) < 0 || pipe(from_cs) < 0)
801071d4279SBram Moolenaar     {
802f9e3e09fSBram Moolenaar 	(void)emsg(_("E566: Could not create cscope pipes"));
803071d4279SBram Moolenaar err_closing:
804071d4279SBram Moolenaar 	if (to_cs[0] != -1)
805071d4279SBram Moolenaar 	    (void)close(to_cs[0]);
806071d4279SBram Moolenaar 	if (to_cs[1] != -1)
807071d4279SBram Moolenaar 	    (void)close(to_cs[1]);
808071d4279SBram Moolenaar 	if (from_cs[0] != -1)
809071d4279SBram Moolenaar 	    (void)close(from_cs[0]);
810071d4279SBram Moolenaar 	if (from_cs[1] != -1)
811071d4279SBram Moolenaar 	    (void)close(from_cs[1]);
812071d4279SBram Moolenaar 	return CSCOPE_FAILURE;
813071d4279SBram Moolenaar     }
814071d4279SBram Moolenaar 
815071d4279SBram Moolenaar     switch (csinfo[i].pid = fork())
816071d4279SBram Moolenaar     {
817071d4279SBram Moolenaar     case -1:
818f9e3e09fSBram Moolenaar 	(void)emsg(_("E622: Could not fork for cscope"));
819071d4279SBram Moolenaar 	goto err_closing;
8202ab2e860SBram Moolenaar     case 0:				// child: run cscope.
821071d4279SBram Moolenaar 	if (dup2(to_cs[0], STDIN_FILENO) == -1)
822071d4279SBram Moolenaar 	    PERROR("cs_create_connection 1");
823071d4279SBram Moolenaar 	if (dup2(from_cs[1], STDOUT_FILENO) == -1)
824071d4279SBram Moolenaar 	    PERROR("cs_create_connection 2");
825071d4279SBram Moolenaar 	if (dup2(from_cs[1], STDERR_FILENO) == -1)
826071d4279SBram Moolenaar 	    PERROR("cs_create_connection 3");
827071d4279SBram Moolenaar 
8282ab2e860SBram Moolenaar 	// close unused
829071d4279SBram Moolenaar 	(void)close(to_cs[1]);
830071d4279SBram Moolenaar 	(void)close(from_cs[0]);
831071d4279SBram Moolenaar #else
8322ab2e860SBram Moolenaar 	// MSWIN
8332ab2e860SBram Moolenaar 	// Create pipes to communicate with cscope
83402b06313SBram Moolenaar 	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
83502b06313SBram Moolenaar 	sa.bInheritHandle = TRUE;
83602b06313SBram Moolenaar 	sa.lpSecurityDescriptor = NULL;
83702b06313SBram Moolenaar 
83802b06313SBram Moolenaar 	if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
83902b06313SBram Moolenaar 		|| !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0)))
84002b06313SBram Moolenaar 	{
841f9e3e09fSBram Moolenaar 	    (void)emsg(_("E566: Could not create cscope pipes"));
84202b06313SBram Moolenaar err_closing:
84302b06313SBram Moolenaar 	    if (pipe_stdin)
84402b06313SBram Moolenaar 	    {
84502b06313SBram Moolenaar 		CloseHandle(stdin_rd);
84602b06313SBram Moolenaar 		CloseHandle(stdin_wr);
84702b06313SBram Moolenaar 	    }
84802b06313SBram Moolenaar 	    if (pipe_stdout)
84902b06313SBram Moolenaar 	    {
85002b06313SBram Moolenaar 		CloseHandle(stdout_rd);
85102b06313SBram Moolenaar 		CloseHandle(stdout_wr);
85202b06313SBram Moolenaar 	    }
85302b06313SBram Moolenaar 	    return CSCOPE_FAILURE;
85402b06313SBram Moolenaar 	}
855071d4279SBram Moolenaar #endif
8562ab2e860SBram Moolenaar 	// expand the cscope exec for env var's
857c799fe20SBram Moolenaar 	if ((prog = alloc(MAXPATHL + 1)) == NULL)
858071d4279SBram Moolenaar 	{
859071d4279SBram Moolenaar #ifdef UNIX
860071d4279SBram Moolenaar 	    return CSCOPE_FAILURE;
861071d4279SBram Moolenaar #else
8622ab2e860SBram Moolenaar 	    // MSWIN
863071d4279SBram Moolenaar 	    goto err_closing;
864071d4279SBram Moolenaar #endif
865071d4279SBram Moolenaar 	}
866071d4279SBram Moolenaar 	expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
867071d4279SBram Moolenaar 
8682ab2e860SBram Moolenaar 	// alloc space to hold the cscope command
869a93fa7eeSBram Moolenaar 	len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32);
870071d4279SBram Moolenaar 	if (csinfo[i].ppath)
871071d4279SBram Moolenaar 	{
8722ab2e860SBram Moolenaar 	    // expand the prepend path for env var's
873c799fe20SBram Moolenaar 	    if ((ppath = alloc(MAXPATHL + 1)) == NULL)
874071d4279SBram Moolenaar 	    {
875071d4279SBram Moolenaar 		vim_free(prog);
876071d4279SBram Moolenaar #ifdef UNIX
877071d4279SBram Moolenaar 		return CSCOPE_FAILURE;
878071d4279SBram Moolenaar #else
8792ab2e860SBram Moolenaar 		// MSWIN
880071d4279SBram Moolenaar 		goto err_closing;
881071d4279SBram Moolenaar #endif
882071d4279SBram Moolenaar 	    }
883071d4279SBram Moolenaar 	    expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
884071d4279SBram Moolenaar 
885a93fa7eeSBram Moolenaar 	    len += (int)strlen(ppath);
886071d4279SBram Moolenaar 	}
887071d4279SBram Moolenaar 
888071d4279SBram Moolenaar 	if (csinfo[i].flags)
889a93fa7eeSBram Moolenaar 	    len += (int)strlen(csinfo[i].flags);
890071d4279SBram Moolenaar 
891c799fe20SBram Moolenaar 	if ((cmd = alloc(len)) == NULL)
892071d4279SBram Moolenaar 	{
893071d4279SBram Moolenaar 	    vim_free(prog);
894071d4279SBram Moolenaar 	    vim_free(ppath);
895071d4279SBram Moolenaar #ifdef UNIX
896071d4279SBram Moolenaar 	    return CSCOPE_FAILURE;
897071d4279SBram Moolenaar #else
8982ab2e860SBram Moolenaar 	    // MSWIN
899071d4279SBram Moolenaar 	    goto err_closing;
900071d4279SBram Moolenaar #endif
901071d4279SBram Moolenaar 	}
902071d4279SBram Moolenaar 
9032ab2e860SBram Moolenaar 	// run the cscope command; is there execl for non-unix systems?
904071d4279SBram Moolenaar #if defined(UNIX)
905071d4279SBram Moolenaar 	(void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
906071d4279SBram Moolenaar #else
9072ab2e860SBram Moolenaar 	// MSWIN
908071d4279SBram Moolenaar 	(void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
909071d4279SBram Moolenaar #endif
910071d4279SBram Moolenaar 	if (csinfo[i].ppath != NULL)
911071d4279SBram Moolenaar 	{
912071d4279SBram Moolenaar 	    (void)strcat(cmd, " -P");
913071d4279SBram Moolenaar 	    (void)strcat(cmd, csinfo[i].ppath);
914071d4279SBram Moolenaar 	}
915071d4279SBram Moolenaar 	if (csinfo[i].flags != NULL)
916071d4279SBram Moolenaar 	{
917071d4279SBram Moolenaar 	    (void)strcat(cmd, " ");
918071d4279SBram Moolenaar 	    (void)strcat(cmd, csinfo[i].flags);
919071d4279SBram Moolenaar 	}
920071d4279SBram Moolenaar # ifdef UNIX
9212ab2e860SBram Moolenaar 	// on Win32 we still need prog
922071d4279SBram Moolenaar 	vim_free(prog);
923071d4279SBram Moolenaar # endif
924071d4279SBram Moolenaar 	vim_free(ppath);
925071d4279SBram Moolenaar 
926071d4279SBram Moolenaar #if defined(UNIX)
92785e932f2SBram Moolenaar # if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
9282ab2e860SBram Moolenaar 	// Change our process group to avoid cscope receiving SIGWINCH.
92985e932f2SBram Moolenaar #  if defined(HAVE_SETSID)
93085e932f2SBram Moolenaar 	(void)setsid();
93185e932f2SBram Moolenaar #  else
93285e932f2SBram Moolenaar 	if (setpgid(0, 0) == -1)
93385e932f2SBram Moolenaar 	    PERROR(_("cs_create_connection setpgid failed"));
93485e932f2SBram Moolenaar #  endif
93585e932f2SBram Moolenaar # endif
936856b9fefSBram Moolenaar 	if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
937071d4279SBram Moolenaar 	    PERROR(_("cs_create_connection exec failed"));
938071d4279SBram Moolenaar 
939071d4279SBram Moolenaar 	exit(127);
9402ab2e860SBram Moolenaar 	// NOTREACHED
9412ab2e860SBram Moolenaar     default:	// parent.
942071d4279SBram Moolenaar 	/*
943071d4279SBram Moolenaar 	 * Save the file descriptors for later duplication, and
944071d4279SBram Moolenaar 	 * reopen as streams.
945071d4279SBram Moolenaar 	 */
946071d4279SBram Moolenaar 	if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
947071d4279SBram Moolenaar 	    PERROR(_("cs_create_connection: fdopen for to_fp failed"));
948071d4279SBram Moolenaar 	if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
949071d4279SBram Moolenaar 	    PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
950071d4279SBram Moolenaar 
9512ab2e860SBram Moolenaar 	// close unused
952071d4279SBram Moolenaar 	(void)close(to_cs[0]);
953071d4279SBram Moolenaar 	(void)close(from_cs[1]);
954071d4279SBram Moolenaar 
955071d4279SBram Moolenaar 	break;
956071d4279SBram Moolenaar     }
95702b06313SBram Moolenaar 
958071d4279SBram Moolenaar #else
9592ab2e860SBram Moolenaar     // MSWIN
9602ab2e860SBram Moolenaar     // Create a new process to run cscope and use pipes to talk with it
96102b06313SBram Moolenaar     GetStartupInfo(&si);
96202b06313SBram Moolenaar     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
9632ab2e860SBram Moolenaar     si.wShowWindow = SW_HIDE;  // Hide child application window
96402b06313SBram Moolenaar     si.hStdOutput = stdout_wr;
96502b06313SBram Moolenaar     si.hStdError  = stdout_wr;
96602b06313SBram Moolenaar     si.hStdInput  = stdin_rd;
96702b06313SBram Moolenaar     created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
96802b06313SBram Moolenaar 							NULL, NULL, &si, &pi);
96902b06313SBram Moolenaar     vim_free(prog);
97002b06313SBram Moolenaar     vim_free(cmd);
97102b06313SBram Moolenaar 
97202b06313SBram Moolenaar     if (!created)
97302b06313SBram Moolenaar     {
97402b06313SBram Moolenaar 	PERROR(_("cs_create_connection exec failed"));
975f9e3e09fSBram Moolenaar 	(void)emsg(_("E623: Could not spawn cscope process"));
97602b06313SBram Moolenaar 	goto err_closing;
97702b06313SBram Moolenaar     }
9782ab2e860SBram Moolenaar     // else
97902b06313SBram Moolenaar     csinfo[i].pid = pi.dwProcessId;
98002b06313SBram Moolenaar     csinfo[i].hProc = pi.hProcess;
98102b06313SBram Moolenaar     CloseHandle(pi.hThread);
98202b06313SBram Moolenaar 
9832ab2e860SBram Moolenaar     // TODO - tidy up after failure to create files on pipe handles.
9845365c4d5SBram Moolenaar     if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
9855365c4d5SBram Moolenaar 						      _O_TEXT|_O_APPEND)) < 0)
98602b06313SBram Moolenaar 	    || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
98702b06313SBram Moolenaar 	PERROR(_("cs_create_connection: fdopen for to_fp failed"));
9885365c4d5SBram Moolenaar     if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
9895365c4d5SBram Moolenaar 						      _O_TEXT|_O_RDONLY)) < 0)
99002b06313SBram Moolenaar 	    || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
99102b06313SBram Moolenaar 	PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
99202b06313SBram Moolenaar 
9932ab2e860SBram Moolenaar     // Close handles for file descriptors inherited by the cscope process
99402b06313SBram Moolenaar     CloseHandle(stdin_rd);
99502b06313SBram Moolenaar     CloseHandle(stdout_wr);
99602b06313SBram Moolenaar 
9972ab2e860SBram Moolenaar #endif // !UNIX
99802b06313SBram Moolenaar 
999071d4279SBram Moolenaar     return CSCOPE_SUCCESS;
10002ab2e860SBram Moolenaar }
1001071d4279SBram Moolenaar 
1002071d4279SBram Moolenaar 
1003071d4279SBram Moolenaar /*
1004cde88547SBram Moolenaar  * Query cscope using command line interface.  Parse the output and use tselect
1005cde88547SBram Moolenaar  * to allow choices.  Like Nvi, creates a pipe to send to/from query/cscope.
1006071d4279SBram Moolenaar  *
1007071d4279SBram Moolenaar  * returns TRUE if we jump to a tag or abort, FALSE if not.
1008071d4279SBram Moolenaar  */
1009071d4279SBram Moolenaar     static int
cs_find(exarg_T * eap)101068c2f638SBram Moolenaar cs_find(exarg_T *eap)
1011071d4279SBram Moolenaar {
1012071d4279SBram Moolenaar     char *opt, *pat;
10137fd73200SBram Moolenaar     int i;
1014071d4279SBram Moolenaar 
1015071d4279SBram Moolenaar     if (cs_check_for_connections() == FALSE)
1016071d4279SBram Moolenaar     {
1017f9e3e09fSBram Moolenaar 	(void)emsg(_("E567: no cscope connections"));
1018071d4279SBram Moolenaar 	return FALSE;
1019071d4279SBram Moolenaar     }
1020071d4279SBram Moolenaar 
1021071d4279SBram Moolenaar     if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL)
1022071d4279SBram Moolenaar     {
1023071d4279SBram Moolenaar 	cs_usage_msg(Find);
1024071d4279SBram Moolenaar 	return FALSE;
1025071d4279SBram Moolenaar     }
1026071d4279SBram Moolenaar 
1027071d4279SBram Moolenaar     pat = opt + strlen(opt) + 1;
1028d2ac984aSBram Moolenaar     if (pat >= (char *)eap->arg + eap_arg_len)
1029071d4279SBram Moolenaar     {
1030071d4279SBram Moolenaar 	cs_usage_msg(Find);
1031071d4279SBram Moolenaar 	return FALSE;
1032071d4279SBram Moolenaar     }
1033071d4279SBram Moolenaar 
10347fd73200SBram Moolenaar     /*
10357fd73200SBram Moolenaar      * Let's replace the NULs written by strtok() with spaces - we need the
10367fd73200SBram Moolenaar      * spaces to correctly display the quickfix/location list window's title.
10377fd73200SBram Moolenaar      */
10387fd73200SBram Moolenaar     for (i = 0; i < eap_arg_len; ++i)
10397fd73200SBram Moolenaar 	if (NUL == eap->arg[i])
10407fd73200SBram Moolenaar 	    eap->arg[i] = ' ';
10417fd73200SBram Moolenaar 
1042c7453f52SBram Moolenaar     return cs_find_common(opt, pat, eap->forceit, TRUE,
10437fd73200SBram Moolenaar 				  eap->cmdidx == CMD_lcscope, *eap->cmdlinep);
10442ab2e860SBram Moolenaar }
1045071d4279SBram Moolenaar 
1046071d4279SBram Moolenaar 
1047071d4279SBram Moolenaar /*
1048d4db7719SBram Moolenaar  * Common code for cscope find, shared by cs_find() and ex_cstag().
1049071d4279SBram Moolenaar  */
1050071d4279SBram Moolenaar     static int
cs_find_common(char * opt,char * pat,int forceit,int verbose,int use_ll UNUSED,char_u * cmdline UNUSED)105168c2f638SBram Moolenaar cs_find_common(
105268c2f638SBram Moolenaar     char *opt,
105368c2f638SBram Moolenaar     char *pat,
105468c2f638SBram Moolenaar     int forceit,
105568c2f638SBram Moolenaar     int verbose,
105668c2f638SBram Moolenaar     int	use_ll UNUSED,
105768c2f638SBram Moolenaar     char_u *cmdline UNUSED)
1058071d4279SBram Moolenaar {
1059071d4279SBram Moolenaar     int i;
1060071d4279SBram Moolenaar     char *cmd;
10619fa49da7SBram Moolenaar     int *nummatches;
10629fa49da7SBram Moolenaar     int totmatches;
1063071d4279SBram Moolenaar #ifdef FEAT_QUICKFIX
1064071d4279SBram Moolenaar     char cmdletter;
1065071d4279SBram Moolenaar     char *qfpos;
1066f1eeae94SBram Moolenaar 
10672ab2e860SBram Moolenaar     // get cmd letter
1068f1eeae94SBram Moolenaar     switch (opt[0])
1069f1eeae94SBram Moolenaar     {
1070f1eeae94SBram Moolenaar     case '0' :
1071f1eeae94SBram Moolenaar 	cmdletter = 's';
1072f1eeae94SBram Moolenaar 	break;
1073f1eeae94SBram Moolenaar     case '1' :
1074f1eeae94SBram Moolenaar 	cmdletter = 'g';
1075f1eeae94SBram Moolenaar 	break;
1076f1eeae94SBram Moolenaar     case '2' :
1077f1eeae94SBram Moolenaar 	cmdletter = 'd';
1078f1eeae94SBram Moolenaar 	break;
1079f1eeae94SBram Moolenaar     case '3' :
1080f1eeae94SBram Moolenaar 	cmdletter = 'c';
1081f1eeae94SBram Moolenaar 	break;
1082f1eeae94SBram Moolenaar     case '4' :
1083f1eeae94SBram Moolenaar 	cmdletter = 't';
1084f1eeae94SBram Moolenaar 	break;
1085f1eeae94SBram Moolenaar     case '6' :
1086f1eeae94SBram Moolenaar 	cmdletter = 'e';
1087f1eeae94SBram Moolenaar 	break;
1088f1eeae94SBram Moolenaar     case '7' :
1089f1eeae94SBram Moolenaar 	cmdletter = 'f';
1090f1eeae94SBram Moolenaar 	break;
1091f1eeae94SBram Moolenaar     case '8' :
1092f1eeae94SBram Moolenaar 	cmdletter = 'i';
1093f1eeae94SBram Moolenaar 	break;
1094b12e7ef9SBram Moolenaar     case '9' :
1095b12e7ef9SBram Moolenaar 	cmdletter = 'a';
1096b12e7ef9SBram Moolenaar 	break;
1097f1eeae94SBram Moolenaar     default :
1098f1eeae94SBram Moolenaar 	cmdletter = opt[0];
1099f1eeae94SBram Moolenaar     }
1100f1eeae94SBram Moolenaar 
1101f1eeae94SBram Moolenaar     qfpos = (char *)vim_strchr(p_csqf, cmdletter);
1102f1eeae94SBram Moolenaar     if (qfpos != NULL)
1103f1eeae94SBram Moolenaar     {
1104f1eeae94SBram Moolenaar 	qfpos++;
11052ab2e860SBram Moolenaar 	// next symbol must be + or -
1106f1eeae94SBram Moolenaar 	if (strchr(CSQF_FLAGS, *qfpos) == NULL)
1107f1eeae94SBram Moolenaar 	{
1108*3c5904d2SJames McCoy 	    (void)semsg(_("E469: invalid cscopequickfix flag %c for %c"), *qfpos, *(qfpos - 1));
1109f1eeae94SBram Moolenaar 	    return FALSE;
1110f1eeae94SBram Moolenaar 	}
1111f1eeae94SBram Moolenaar 
111221662be2SBram Moolenaar 	if (*qfpos != '0'
111321662be2SBram Moolenaar 		&& apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)"cscope",
111421662be2SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf))
1115f1eeae94SBram Moolenaar 	{
1116f1eeae94SBram Moolenaar # ifdef FEAT_EVAL
111721662be2SBram Moolenaar 	    if (aborting())
1118f1eeae94SBram Moolenaar 		return FALSE;
1119f1eeae94SBram Moolenaar # endif
1120f1eeae94SBram Moolenaar 	}
1121f1eeae94SBram Moolenaar     }
1122071d4279SBram Moolenaar #endif
1123071d4279SBram Moolenaar 
11242ab2e860SBram Moolenaar     // create the actual command to send to cscope
1125071d4279SBram Moolenaar     cmd = cs_create_cmd(opt, pat);
1126071d4279SBram Moolenaar     if (cmd == NULL)
1127071d4279SBram Moolenaar 	return FALSE;
1128071d4279SBram Moolenaar 
1129c799fe20SBram Moolenaar     nummatches = ALLOC_MULT(int, csinfo_size);
11309fa49da7SBram Moolenaar     if (nummatches == NULL)
1131cde88547SBram Moolenaar     {
1132cde88547SBram Moolenaar 	vim_free(cmd);
11339fa49da7SBram Moolenaar 	return FALSE;
1134cde88547SBram Moolenaar     }
11359fa49da7SBram Moolenaar 
11362ab2e860SBram Moolenaar     // Send query to all open connections, then count the total number
11372ab2e860SBram Moolenaar     // of matches so we can alloc all in one swell foop.
11389fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
1139071d4279SBram Moolenaar 	nummatches[i] = 0;
1140071d4279SBram Moolenaar     totmatches = 0;
11419fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
1142071d4279SBram Moolenaar     {
1143508b9e89SBram Moolenaar 	if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
1144071d4279SBram Moolenaar 	    continue;
1145071d4279SBram Moolenaar 
11462ab2e860SBram Moolenaar 	// send cmd to cscope
1147071d4279SBram Moolenaar 	(void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
1148071d4279SBram Moolenaar 	(void)fflush(csinfo[i].to_fp);
1149071d4279SBram Moolenaar 
1150071d4279SBram Moolenaar 	nummatches[i] = cs_cnt_matches(i);
1151071d4279SBram Moolenaar 
1152071d4279SBram Moolenaar 	if (nummatches[i] > -1)
1153071d4279SBram Moolenaar 	    totmatches += nummatches[i];
1154071d4279SBram Moolenaar 
1155071d4279SBram Moolenaar 	if (nummatches[i] == 0)
1156071d4279SBram Moolenaar 	    (void)cs_read_prompt(i);
1157071d4279SBram Moolenaar     }
1158071d4279SBram Moolenaar     vim_free(cmd);
1159071d4279SBram Moolenaar 
1160071d4279SBram Moolenaar     if (totmatches == 0)
1161071d4279SBram Moolenaar     {
1162*3c5904d2SJames McCoy 	if (verbose)
1163*3c5904d2SJames McCoy 	    (void)semsg(_("E259: no matches found for cscope query %s of %s"), opt, pat);
11649fa49da7SBram Moolenaar 	vim_free(nummatches);
1165071d4279SBram Moolenaar 	return FALSE;
1166071d4279SBram Moolenaar     }
1167071d4279SBram Moolenaar 
1168071d4279SBram Moolenaar #ifdef FEAT_QUICKFIX
1169293ee4d4SBram Moolenaar     if (qfpos != NULL && *qfpos != '0' && totmatches > 0)
1170071d4279SBram Moolenaar     {
11712ab2e860SBram Moolenaar 	// fill error list
1172071d4279SBram Moolenaar 	FILE	    *f;
1173e5c421cfSBram Moolenaar 	char_u	    *tmp = vim_tempname('c', TRUE);
1174c7453f52SBram Moolenaar 	qf_info_T   *qi = NULL;
1175c7453f52SBram Moolenaar 	win_T	    *wp = NULL;
1176071d4279SBram Moolenaar 
1177bfd8fc05SBram Moolenaar 	f = mch_fopen((char *)tmp, "w");
11780cae8470SBram Moolenaar 	if (f == NULL)
1179f9e3e09fSBram Moolenaar 	    semsg(_(e_notopen), tmp);
11800cae8470SBram Moolenaar 	else
11810cae8470SBram Moolenaar 	{
1182071d4279SBram Moolenaar 	    cs_file_results(f, nummatches);
1183071d4279SBram Moolenaar 	    fclose(f);
11842ab2e860SBram Moolenaar 	    if (use_ll)	    // Use location list
1185c7453f52SBram Moolenaar 		wp = curwin;
11862ab2e860SBram Moolenaar 	    // '-' starts a new error list
11870cae8470SBram Moolenaar 	    if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
11882c7292dcSBram Moolenaar 					  *qfpos == '-', cmdline, NULL) > 0)
1189071d4279SBram Moolenaar 	    {
1190071d4279SBram Moolenaar 		if (postponed_split != 0)
1191071d4279SBram Moolenaar 		{
1192cde88547SBram Moolenaar 		    (void)win_split(postponed_split > 0 ? postponed_split : 0,
1193071d4279SBram Moolenaar 						       postponed_split_flags);
11943368ea21SBram Moolenaar 		    RESET_BINDING(curwin);
1195071d4279SBram Moolenaar 		    postponed_split = 0;
1196071d4279SBram Moolenaar 		}
1197f1eeae94SBram Moolenaar 
1198f1eeae94SBram Moolenaar 		apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope",
1199f1eeae94SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf);
1200c7453f52SBram Moolenaar 		if (use_ll)
1201c7453f52SBram Moolenaar 		    /*
1202c7453f52SBram Moolenaar 		     * In the location list window, use the displayed location
1203c7453f52SBram Moolenaar 		     * list. Otherwise, use the location list for the window.
1204c7453f52SBram Moolenaar 		     */
12050cae8470SBram Moolenaar 		    qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
12060cae8470SBram Moolenaar 			?  wp->w_llist_ref : wp->w_llist;
1207c7453f52SBram Moolenaar 		qf_jump(qi, 0, 0, forceit);
1208071d4279SBram Moolenaar 	    }
12090cae8470SBram Moolenaar 	}
1210071d4279SBram Moolenaar 	mch_remove(tmp);
1211071d4279SBram Moolenaar 	vim_free(tmp);
12129fa49da7SBram Moolenaar 	vim_free(nummatches);
1213071d4279SBram Moolenaar 	return TRUE;
1214071d4279SBram Moolenaar     }
1215071d4279SBram Moolenaar     else
12162ab2e860SBram Moolenaar #endif // FEAT_QUICKFIX
1217071d4279SBram Moolenaar     {
121889d4032cSBram Moolenaar 	char **matches = NULL, **contexts = NULL;
121989d4032cSBram Moolenaar 	int matched = 0;
122089d4032cSBram Moolenaar 
12212ab2e860SBram Moolenaar 	// read output
1222dfa5e464S=?UTF-8?q?Dundar=20G=C3=B6c?= 	cs_fill_results(pat, totmatches, nummatches, &matches,
1223071d4279SBram Moolenaar 							 &contexts, &matched);
12249fa49da7SBram Moolenaar 	vim_free(nummatches);
1225071d4279SBram Moolenaar 	if (matches == NULL)
1226071d4279SBram Moolenaar 	    return FALSE;
1227071d4279SBram Moolenaar 
12285c06f8b0SBram Moolenaar 	(void)cs_manage_matches(matches, contexts, matched, Store);
1229071d4279SBram Moolenaar 
1230071d4279SBram Moolenaar 	return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
1231071d4279SBram Moolenaar     }
1232071d4279SBram Moolenaar 
12332ab2e860SBram Moolenaar }
1234071d4279SBram Moolenaar 
1235071d4279SBram Moolenaar /*
1236d4db7719SBram Moolenaar  * Print help.
1237071d4279SBram Moolenaar  */
1238071d4279SBram Moolenaar     static int
cs_help(exarg_T * eap UNUSED)123968c2f638SBram Moolenaar cs_help(exarg_T *eap UNUSED)
1240071d4279SBram Moolenaar {
1241071d4279SBram Moolenaar     cscmd_T *cmdp = cs_cmds;
1242071d4279SBram Moolenaar 
124332526b3cSBram Moolenaar     (void)msg_puts(_("cscope commands:\n"));
1244071d4279SBram Moolenaar     while (cmdp->name != NULL)
1245071d4279SBram Moolenaar     {
1246db867d50SBram Moolenaar 	char *help = _(cmdp->help);
1247db867d50SBram Moolenaar 	int  space_cnt = 30 - vim_strsize((char_u *)help);
1248db867d50SBram Moolenaar 
12492ab2e860SBram Moolenaar 	// Use %*s rather than %30s to ensure proper alignment in utf-8
1250db867d50SBram Moolenaar 	if (space_cnt < 0)
1251db867d50SBram Moolenaar 	    space_cnt = 0;
1252f9e3e09fSBram Moolenaar 	(void)smsg(_("%-5s: %s%*s (Usage: %s)"),
1253db867d50SBram Moolenaar 				      cmdp->name,
1254db867d50SBram Moolenaar 				      help, space_cnt, " ",
1255db867d50SBram Moolenaar 				      cmdp->usage);
1256071d4279SBram Moolenaar 	if (strcmp(cmdp->name, "find") == 0)
125732526b3cSBram Moolenaar 	    msg_puts(_("\n"
125880632db6SBram Moolenaar 		       "       a: Find assignments to this symbol\n"
1259627943d3SBram Moolenaar 		       "       c: Find functions calling this function\n"
1260627943d3SBram Moolenaar 		       "       d: Find functions called by this function\n"
1261627943d3SBram Moolenaar 		       "       e: Find this egrep pattern\n"
1262627943d3SBram Moolenaar 		       "       f: Find this file\n"
1263627943d3SBram Moolenaar 		       "       g: Find this definition\n"
1264627943d3SBram Moolenaar 		       "       i: Find files #including this file\n"
1265627943d3SBram Moolenaar 		       "       s: Find this C symbol\n"
126680632db6SBram Moolenaar 		       "       t: Find this text string\n"));
1267627943d3SBram Moolenaar 
1268071d4279SBram Moolenaar 	cmdp++;
1269071d4279SBram Moolenaar     }
1270071d4279SBram Moolenaar 
1271071d4279SBram Moolenaar     wait_return(TRUE);
1272071d4279SBram Moolenaar     return 0;
12732ab2e860SBram Moolenaar }
1274071d4279SBram Moolenaar 
1275071d4279SBram Moolenaar 
1276071d4279SBram Moolenaar     static void
clear_csinfo(int i)127768c2f638SBram Moolenaar clear_csinfo(int i)
1278071d4279SBram Moolenaar {
1279071d4279SBram Moolenaar     csinfo[i].fname  = NULL;
1280071d4279SBram Moolenaar     csinfo[i].ppath  = NULL;
1281071d4279SBram Moolenaar     csinfo[i].flags  = NULL;
1282071d4279SBram Moolenaar #if defined(UNIX)
1283071d4279SBram Moolenaar     csinfo[i].st_dev = (dev_t)0;
1284071d4279SBram Moolenaar     csinfo[i].st_ino = (ino_t)0;
1285071d4279SBram Moolenaar #else
1286071d4279SBram Moolenaar     csinfo[i].nVolume = 0;
1287071d4279SBram Moolenaar     csinfo[i].nIndexHigh = 0;
1288071d4279SBram Moolenaar     csinfo[i].nIndexLow = 0;
1289071d4279SBram Moolenaar #endif
1290446cb837SBram Moolenaar     csinfo[i].pid    = 0;
1291071d4279SBram Moolenaar     csinfo[i].fr_fp  = NULL;
1292071d4279SBram Moolenaar     csinfo[i].to_fp  = NULL;
12934f97475dSBram Moolenaar #if defined(MSWIN)
129475c50c46SBram Moolenaar     csinfo[i].hProc = NULL;
129575c50c46SBram Moolenaar #endif
1296071d4279SBram Moolenaar }
1297071d4279SBram Moolenaar 
1298071d4279SBram Moolenaar /*
1299d4db7719SBram Moolenaar  * Insert a new cscope database filename into the filelist.
1300071d4279SBram Moolenaar  */
1301071d4279SBram Moolenaar     static int
cs_insert_filelist(char * fname,char * ppath,char * flags,stat_T * sb UNUSED)130268c2f638SBram Moolenaar cs_insert_filelist(
130368c2f638SBram Moolenaar     char *fname,
130468c2f638SBram Moolenaar     char *ppath,
130568c2f638SBram Moolenaar     char *flags,
13068767f52fSBram Moolenaar     stat_T *sb UNUSED)
1307071d4279SBram Moolenaar {
1308071d4279SBram Moolenaar     short	i, j;
1309071d4279SBram Moolenaar #ifndef UNIX
1310071d4279SBram Moolenaar     BY_HANDLE_FILE_INFORMATION bhfi;
1311071d4279SBram Moolenaar 
13126aa2cd4bSBram Moolenaar     switch (win32_fileinfo((char_u *)fname, &bhfi))
1313071d4279SBram Moolenaar     {
13142ab2e860SBram Moolenaar 	case FILEINFO_ENC_FAIL:		// enc_to_utf16() failed
13152ab2e860SBram Moolenaar 	case FILEINFO_READ_FAIL:	// CreateFile() failed
1316071d4279SBram Moolenaar 	    if (p_csverbose)
1317071d4279SBram Moolenaar 	    {
1318071d4279SBram Moolenaar 		char *cant_msg = _("E625: cannot open cscope database: %s");
1319071d4279SBram Moolenaar 		char *winmsg = GetWin32Error();
1320071d4279SBram Moolenaar 
1321071d4279SBram Moolenaar 		if (winmsg != NULL)
1322071d4279SBram Moolenaar 		{
1323f9e3e09fSBram Moolenaar 		    (void)semsg(cant_msg, winmsg);
1324071d4279SBram Moolenaar 		    LocalFree(winmsg);
1325071d4279SBram Moolenaar 		}
1326071d4279SBram Moolenaar 		else
13272ab2e860SBram Moolenaar 		    // subst filename if can't get error text
1328f9e3e09fSBram Moolenaar 		    (void)semsg(cant_msg, fname);
1329071d4279SBram Moolenaar 	    }
1330071d4279SBram Moolenaar 	    return -1;
13311c32dff7SBram Moolenaar 
13322ab2e860SBram Moolenaar 	case FILEINFO_INFO_FAIL:    // GetFileInformationByHandle() failed
1333071d4279SBram Moolenaar 	    if (p_csverbose)
1334f9e3e09fSBram Moolenaar 		(void)emsg(_("E626: cannot get cscope database information"));
1335071d4279SBram Moolenaar 	    return -1;
1336071d4279SBram Moolenaar     }
1337071d4279SBram Moolenaar #endif
1338071d4279SBram Moolenaar 
13392ab2e860SBram Moolenaar     i = -1; // can be set to the index of an empty item in csinfo
13409fa49da7SBram Moolenaar     for (j = 0; j < csinfo_size; j++)
1341071d4279SBram Moolenaar     {
1342071d4279SBram Moolenaar 	if (csinfo[j].fname != NULL
1343071d4279SBram Moolenaar #if defined(UNIX)
1344071d4279SBram Moolenaar 	    && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
1345071d4279SBram Moolenaar #else
134699499b1cSBram Moolenaar 	    // compare pathnames first
13476aa2cd4bSBram Moolenaar 	    && ((fullpathcmp((char_u *)csinfo[j].fname,
134899499b1cSBram Moolenaar 			(char_u *)fname, FALSE, TRUE) & FPC_SAME)
134999499b1cSBram Moolenaar 		// test index file attributes too
1350cea912afSBram Moolenaar 		|| (csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
1351071d4279SBram Moolenaar 		    && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
1352071d4279SBram Moolenaar 		    && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
1353071d4279SBram Moolenaar #endif
1354071d4279SBram Moolenaar 	    )
1355071d4279SBram Moolenaar 	{
1356071d4279SBram Moolenaar 	    if (p_csverbose)
1357f9e3e09fSBram Moolenaar 		(void)emsg(_("E568: duplicate cscope database not added"));
1358071d4279SBram Moolenaar 	    return -1;
1359071d4279SBram Moolenaar 	}
1360071d4279SBram Moolenaar 
1361071d4279SBram Moolenaar 	if (csinfo[j].fname == NULL && i == -1)
13622ab2e860SBram Moolenaar 	    i = j; // remember first empty entry
1363071d4279SBram Moolenaar     }
1364071d4279SBram Moolenaar 
1365071d4279SBram Moolenaar     if (i == -1)
1366071d4279SBram Moolenaar     {
13679fa49da7SBram Moolenaar 	i = csinfo_size;
13689fa49da7SBram Moolenaar 	if (csinfo_size == 0)
13699fa49da7SBram Moolenaar 	{
13702ab2e860SBram Moolenaar 	    // First time allocation: allocate only 1 connection. It should
13712ab2e860SBram Moolenaar 	    // be enough for most users.  If more is needed, csinfo will be
13722ab2e860SBram Moolenaar 	    // reallocated.
13739fa49da7SBram Moolenaar 	    csinfo_size = 1;
1374c799fe20SBram Moolenaar 	    csinfo = ALLOC_CLEAR_ONE(csinfo_T);
13759fa49da7SBram Moolenaar 	}
13769fa49da7SBram Moolenaar 	else
13779fa49da7SBram Moolenaar 	{
13789abd5c65SBram Moolenaar 	    csinfo_T *t_csinfo = csinfo;
13799abd5c65SBram Moolenaar 
13802ab2e860SBram Moolenaar 	    // Reallocate space for more connections.
13819fa49da7SBram Moolenaar 	    csinfo_size *= 2;
13829fa49da7SBram Moolenaar 	    csinfo = vim_realloc(csinfo, sizeof(csinfo_T)*csinfo_size);
13839abd5c65SBram Moolenaar 	    if (csinfo == NULL)
13849abd5c65SBram Moolenaar 	    {
13859abd5c65SBram Moolenaar 		vim_free(t_csinfo);
13869abd5c65SBram Moolenaar 		csinfo_size = 0;
13879abd5c65SBram Moolenaar 	    }
13889fa49da7SBram Moolenaar 	}
13899fa49da7SBram Moolenaar 	if (csinfo == NULL)
1390071d4279SBram Moolenaar 	    return -1;
13919fa49da7SBram Moolenaar 	for (j = csinfo_size/2; j < csinfo_size; j++)
13929fa49da7SBram Moolenaar 	    clear_csinfo(j);
1393071d4279SBram Moolenaar     }
1394071d4279SBram Moolenaar 
1395c799fe20SBram Moolenaar     if ((csinfo[i].fname = alloc(strlen(fname)+1)) == NULL)
1396071d4279SBram Moolenaar 	return -1;
1397071d4279SBram Moolenaar 
1398071d4279SBram Moolenaar     (void)strcpy(csinfo[i].fname, (const char *)fname);
1399071d4279SBram Moolenaar 
1400071d4279SBram Moolenaar     if (ppath != NULL)
1401071d4279SBram Moolenaar     {
1402c799fe20SBram Moolenaar 	if ((csinfo[i].ppath = alloc(strlen(ppath) + 1)) == NULL)
1403071d4279SBram Moolenaar 	{
1404d23a8236SBram Moolenaar 	    VIM_CLEAR(csinfo[i].fname);
1405071d4279SBram Moolenaar 	    return -1;
1406071d4279SBram Moolenaar 	}
1407071d4279SBram Moolenaar 	(void)strcpy(csinfo[i].ppath, (const char *)ppath);
1408071d4279SBram Moolenaar     } else
1409071d4279SBram Moolenaar 	csinfo[i].ppath = NULL;
1410071d4279SBram Moolenaar 
1411071d4279SBram Moolenaar     if (flags != NULL)
1412071d4279SBram Moolenaar     {
1413c799fe20SBram Moolenaar 	if ((csinfo[i].flags = alloc(strlen(flags) + 1)) == NULL)
1414071d4279SBram Moolenaar 	{
1415d23a8236SBram Moolenaar 	    VIM_CLEAR(csinfo[i].fname);
1416d23a8236SBram Moolenaar 	    VIM_CLEAR(csinfo[i].ppath);
1417071d4279SBram Moolenaar 	    return -1;
1418071d4279SBram Moolenaar 	}
1419071d4279SBram Moolenaar 	(void)strcpy(csinfo[i].flags, (const char *)flags);
1420071d4279SBram Moolenaar     } else
1421071d4279SBram Moolenaar 	csinfo[i].flags = NULL;
1422071d4279SBram Moolenaar 
1423071d4279SBram Moolenaar #if defined(UNIX)
1424071d4279SBram Moolenaar     csinfo[i].st_dev = sb->st_dev;
1425071d4279SBram Moolenaar     csinfo[i].st_ino = sb->st_ino;
1426071d4279SBram Moolenaar 
1427071d4279SBram Moolenaar #else
1428071d4279SBram Moolenaar     csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
1429071d4279SBram Moolenaar     csinfo[i].nIndexLow = bhfi.nFileIndexLow;
1430071d4279SBram Moolenaar     csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
1431071d4279SBram Moolenaar #endif
1432071d4279SBram Moolenaar     return i;
14332ab2e860SBram Moolenaar }
1434071d4279SBram Moolenaar 
1435071d4279SBram Moolenaar 
1436071d4279SBram Moolenaar /*
1437d4db7719SBram Moolenaar  * Find cscope command in command table.
1438071d4279SBram Moolenaar  */
1439071d4279SBram Moolenaar     static cscmd_T *
cs_lookup_cmd(exarg_T * eap)144068c2f638SBram Moolenaar cs_lookup_cmd(exarg_T *eap)
1441071d4279SBram Moolenaar {
1442071d4279SBram Moolenaar     cscmd_T *cmdp;
1443071d4279SBram Moolenaar     char *stok;
1444071d4279SBram Moolenaar     size_t len;
1445071d4279SBram Moolenaar 
1446071d4279SBram Moolenaar     if (eap->arg == NULL)
1447071d4279SBram Moolenaar 	return NULL;
1448071d4279SBram Moolenaar 
14492ab2e860SBram Moolenaar     // Store length of eap->arg before it gets modified by strtok().
1450cb4cef22SBram Moolenaar     eap_arg_len = (int)STRLEN(eap->arg);
1451d2ac984aSBram Moolenaar 
1452071d4279SBram Moolenaar     if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
1453071d4279SBram Moolenaar 	return NULL;
1454071d4279SBram Moolenaar 
1455071d4279SBram Moolenaar     len = strlen(stok);
1456071d4279SBram Moolenaar     for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp)
1457071d4279SBram Moolenaar     {
1458071d4279SBram Moolenaar 	if (strncmp((const char *)(stok), cmdp->name, len) == 0)
1459071d4279SBram Moolenaar 	    return (cmdp);
1460071d4279SBram Moolenaar     }
1461071d4279SBram Moolenaar     return NULL;
14622ab2e860SBram Moolenaar }
1463071d4279SBram Moolenaar 
1464071d4279SBram Moolenaar 
1465071d4279SBram Moolenaar /*
1466d4db7719SBram Moolenaar  * Nuke em.
1467071d4279SBram Moolenaar  */
1468071d4279SBram Moolenaar     static int
cs_kill(exarg_T * eap UNUSED)146968c2f638SBram Moolenaar cs_kill(exarg_T *eap UNUSED)
1470071d4279SBram Moolenaar {
1471071d4279SBram Moolenaar     char *stok;
1472071d4279SBram Moolenaar     short i;
1473071d4279SBram Moolenaar 
1474071d4279SBram Moolenaar     if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL)
1475071d4279SBram Moolenaar     {
1476071d4279SBram Moolenaar 	cs_usage_msg(Kill);
1477071d4279SBram Moolenaar 	return CSCOPE_FAILURE;
1478071d4279SBram Moolenaar     }
1479071d4279SBram Moolenaar 
14802ab2e860SBram Moolenaar     // only single digit positive and negative integers are allowed
1481071d4279SBram Moolenaar     if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0])))
1482071d4279SBram Moolenaar 	    || (strlen(stok) < 3 && stok[0] == '-'
1483071d4279SBram Moolenaar 					      && VIM_ISDIGIT((int)(stok[1]))))
1484071d4279SBram Moolenaar 	i = atoi(stok);
1485071d4279SBram Moolenaar     else
1486071d4279SBram Moolenaar     {
14872ab2e860SBram Moolenaar 	// It must be part of a name.  We will try to find a match
14882ab2e860SBram Moolenaar 	// within all the names in the csinfo data structure
14899fa49da7SBram Moolenaar 	for (i = 0; i < csinfo_size; i++)
1490071d4279SBram Moolenaar 	{
1491071d4279SBram Moolenaar 	    if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
1492071d4279SBram Moolenaar 		break;
1493071d4279SBram Moolenaar 	}
1494071d4279SBram Moolenaar     }
1495071d4279SBram Moolenaar 
14969fa49da7SBram Moolenaar     if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL))
1497071d4279SBram Moolenaar     {
1498071d4279SBram Moolenaar 	if (p_csverbose)
1499f9e3e09fSBram Moolenaar 	    (void)semsg(_("E261: cscope connection %s not found"), stok);
1500071d4279SBram Moolenaar     }
1501071d4279SBram Moolenaar     else
1502071d4279SBram Moolenaar     {
1503071d4279SBram Moolenaar 	if (i == -1)
1504071d4279SBram Moolenaar 	{
15059fa49da7SBram Moolenaar 	    for (i = 0; i < csinfo_size; i++)
1506071d4279SBram Moolenaar 	    {
1507071d4279SBram Moolenaar 		if (csinfo[i].fname)
1508071d4279SBram Moolenaar 		    cs_kill_execute(i, csinfo[i].fname);
1509071d4279SBram Moolenaar 	    }
1510071d4279SBram Moolenaar 	}
1511071d4279SBram Moolenaar 	else
1512071d4279SBram Moolenaar 	    cs_kill_execute(i, stok);
1513071d4279SBram Moolenaar     }
1514071d4279SBram Moolenaar 
1515071d4279SBram Moolenaar     return 0;
15162ab2e860SBram Moolenaar }
1517071d4279SBram Moolenaar 
1518071d4279SBram Moolenaar 
1519071d4279SBram Moolenaar /*
1520071d4279SBram Moolenaar  * Actually kills a specific cscope connection.
1521071d4279SBram Moolenaar  */
1522071d4279SBram Moolenaar     static void
cs_kill_execute(int i,char * cname)152368c2f638SBram Moolenaar cs_kill_execute(
15242ab2e860SBram Moolenaar     int i,	    // cscope table index
15252ab2e860SBram Moolenaar     char *cname)    // cscope database name
1526071d4279SBram Moolenaar {
1527071d4279SBram Moolenaar     if (p_csverbose)
1528071d4279SBram Moolenaar     {
1529071d4279SBram Moolenaar 	msg_clr_eos();
15308820b486SBram Moolenaar 	(void)smsg_attr(HL_ATTR(HLF_R) | MSG_HIST,
1531f9e3e09fSBram Moolenaar 			_("cscope connection %s closed"), cname);
1532071d4279SBram Moolenaar     }
1533071d4279SBram Moolenaar     cs_release_csp(i, TRUE);
1534071d4279SBram Moolenaar }
1535071d4279SBram Moolenaar 
1536071d4279SBram Moolenaar 
1537071d4279SBram Moolenaar /*
1538d4db7719SBram Moolenaar  * Convert the cscope output into a ctags style entry (as might be found
1539071d4279SBram Moolenaar  * in a ctags tags file).  there's one catch though: cscope doesn't tell you
1540071d4279SBram Moolenaar  * the type of the tag you are looking for.  for example, in Darren Hiebert's
1541071d4279SBram Moolenaar  * ctags (the one that comes with vim), #define's use a line number to find the
1542071d4279SBram Moolenaar  * tag in a file while function definitions use a regexp search pattern.
1543071d4279SBram Moolenaar  *
1544d4db7719SBram Moolenaar  * I'm going to always use the line number because cscope does something
1545071d4279SBram Moolenaar  * quirky (and probably other things i don't know about):
1546071d4279SBram Moolenaar  *
1547071d4279SBram Moolenaar  *     if you have "#  define" in your source file, which is
1548071d4279SBram Moolenaar  *     perfectly legal, cscope thinks you have "#define".  this
1549071d4279SBram Moolenaar  *     will result in a failed regexp search. :(
1550071d4279SBram Moolenaar  *
1551d4db7719SBram Moolenaar  * Besides, even if this particular case didn't happen, the search pattern
1552071d4279SBram Moolenaar  * would still have to be modified to escape all the special regular expression
1553071d4279SBram Moolenaar  * characters to comply with ctags formatting.
1554071d4279SBram Moolenaar  */
1555071d4279SBram Moolenaar     static char *
cs_make_vim_style_matches(char * fname,char * slno,char * search,char * tagstr)155668c2f638SBram Moolenaar cs_make_vim_style_matches(
155768c2f638SBram Moolenaar     char *fname,
155868c2f638SBram Moolenaar     char *slno,
155968c2f638SBram Moolenaar     char *search,
156068c2f638SBram Moolenaar     char *tagstr)
1561071d4279SBram Moolenaar {
15622ab2e860SBram Moolenaar     // vim style is ctags:
15632ab2e860SBram Moolenaar     //
15642ab2e860SBram Moolenaar     //	    <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
15652ab2e860SBram Moolenaar     //
15662ab2e860SBram Moolenaar     // but as mentioned above, we'll always use the line number and
15672ab2e860SBram Moolenaar     // put the search pattern (if one exists) as "extra"
15682ab2e860SBram Moolenaar     //
15692ab2e860SBram Moolenaar     // buf is used as part of vim's method of handling tags, and
15702ab2e860SBram Moolenaar     // (i think) vim frees it when you pop your tags and get replaced
15712ab2e860SBram Moolenaar     // by new ones on the tag stack.
1572071d4279SBram Moolenaar     char *buf;
1573071d4279SBram Moolenaar     int amt;
1574071d4279SBram Moolenaar 
1575071d4279SBram Moolenaar     if (search != NULL)
1576071d4279SBram Moolenaar     {
1577a93fa7eeSBram Moolenaar 	amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6);
1578c799fe20SBram Moolenaar 	if ((buf = alloc(amt)) == NULL)
1579071d4279SBram Moolenaar 	    return NULL;
1580071d4279SBram Moolenaar 
1581071d4279SBram Moolenaar 	(void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
1582071d4279SBram Moolenaar     }
1583071d4279SBram Moolenaar     else
1584071d4279SBram Moolenaar     {
1585a93fa7eeSBram Moolenaar 	amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + 5);
1586c799fe20SBram Moolenaar 	if ((buf = alloc(amt)) == NULL)
1587071d4279SBram Moolenaar 	    return NULL;
1588071d4279SBram Moolenaar 
1589071d4279SBram Moolenaar 	(void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
1590071d4279SBram Moolenaar     }
1591071d4279SBram Moolenaar 
1592071d4279SBram Moolenaar     return buf;
15932ab2e860SBram Moolenaar }
1594071d4279SBram Moolenaar 
1595071d4279SBram Moolenaar 
1596071d4279SBram Moolenaar /*
1597d4db7719SBram Moolenaar  * This is kind of hokey, but i don't see an easy way round this.
1598071d4279SBram Moolenaar  *
1599071d4279SBram Moolenaar  * Store: keep a ptr to the (malloc'd) memory of matches originally
1600071d4279SBram Moolenaar  * generated from cs_find().  the matches are originally lines directly
1601071d4279SBram Moolenaar  * from cscope output, but transformed to look like something out of a
1602071d4279SBram Moolenaar  * ctags.  see cs_make_vim_style_matches for more details.
1603071d4279SBram Moolenaar  *
1604071d4279SBram Moolenaar  * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
1605071d4279SBram Moolenaar  * the next line from the cscope output.  it basically keeps track of which
1606071d4279SBram Moolenaar  * lines have been "used" and returns the next one.
1607071d4279SBram Moolenaar  *
1608071d4279SBram Moolenaar  * Free: frees up everything and resets
1609071d4279SBram Moolenaar  *
1610071d4279SBram Moolenaar  * Print: prints the tags
1611071d4279SBram Moolenaar  */
1612071d4279SBram Moolenaar     static char *
cs_manage_matches(char ** matches,char ** contexts,int totmatches,mcmd_e cmd)161368c2f638SBram Moolenaar cs_manage_matches(
161468c2f638SBram Moolenaar     char **matches,
161568c2f638SBram Moolenaar     char **contexts,
161668c2f638SBram Moolenaar     int totmatches,
161768c2f638SBram Moolenaar     mcmd_e cmd)
1618071d4279SBram Moolenaar {
1619071d4279SBram Moolenaar     static char **mp = NULL;
1620071d4279SBram Moolenaar     static char **cp = NULL;
1621071d4279SBram Moolenaar     static int cnt = -1;
1622071d4279SBram Moolenaar     static int next = -1;
1623071d4279SBram Moolenaar     char *p = NULL;
1624071d4279SBram Moolenaar 
1625071d4279SBram Moolenaar     switch (cmd)
1626071d4279SBram Moolenaar     {
1627071d4279SBram Moolenaar     case Store:
1628071d4279SBram Moolenaar 	assert(matches != NULL);
1629071d4279SBram Moolenaar 	assert(totmatches > 0);
1630071d4279SBram Moolenaar 	if (mp != NULL || cp != NULL)
1631071d4279SBram Moolenaar 	    (void)cs_manage_matches(NULL, NULL, -1, Free);
1632071d4279SBram Moolenaar 	mp = matches;
1633071d4279SBram Moolenaar 	cp = contexts;
1634071d4279SBram Moolenaar 	cnt = totmatches;
1635071d4279SBram Moolenaar 	next = 0;
1636071d4279SBram Moolenaar 	break;
1637071d4279SBram Moolenaar     case Get:
1638071d4279SBram Moolenaar 	if (next >= cnt)
1639071d4279SBram Moolenaar 	    return NULL;
1640071d4279SBram Moolenaar 
1641071d4279SBram Moolenaar 	p = mp[next];
1642071d4279SBram Moolenaar 	next++;
1643071d4279SBram Moolenaar 	break;
1644071d4279SBram Moolenaar     case Free:
1645071d4279SBram Moolenaar 	if (mp != NULL)
1646071d4279SBram Moolenaar 	{
1647071d4279SBram Moolenaar 	    if (cnt > 0)
1648071d4279SBram Moolenaar 		while (cnt--)
1649071d4279SBram Moolenaar 		{
1650071d4279SBram Moolenaar 		    vim_free(mp[cnt]);
1651071d4279SBram Moolenaar 		    if (cp != NULL)
1652071d4279SBram Moolenaar 			vim_free(cp[cnt]);
1653071d4279SBram Moolenaar 		}
1654071d4279SBram Moolenaar 	    vim_free(mp);
1655071d4279SBram Moolenaar 	    vim_free(cp);
1656071d4279SBram Moolenaar 	}
1657071d4279SBram Moolenaar 	mp = NULL;
1658071d4279SBram Moolenaar 	cp = NULL;
1659071d4279SBram Moolenaar 	cnt = 0;
1660071d4279SBram Moolenaar 	next = 0;
1661071d4279SBram Moolenaar 	break;
1662071d4279SBram Moolenaar     case Print:
1663071d4279SBram Moolenaar 	cs_print_tags_priv(mp, cp, cnt);
1664071d4279SBram Moolenaar 	break;
16652ab2e860SBram Moolenaar     default:	// should not reach here
1666f9e3e09fSBram Moolenaar 	iemsg(_("E570: fatal error in cs_manage_matches"));
1667071d4279SBram Moolenaar 	return NULL;
1668071d4279SBram Moolenaar     }
1669071d4279SBram Moolenaar 
1670071d4279SBram Moolenaar     return p;
16712ab2e860SBram Moolenaar }
1672071d4279SBram Moolenaar 
1673071d4279SBram Moolenaar 
1674071d4279SBram Moolenaar /*
1675d4db7719SBram Moolenaar  * Parse cscope output.
1676071d4279SBram Moolenaar  */
1677071d4279SBram Moolenaar     static char *
cs_parse_results(int cnumber,char * buf,int bufsize,char ** context,char ** linenumber,char ** search)167868c2f638SBram Moolenaar cs_parse_results(
167968c2f638SBram Moolenaar     int cnumber,
168068c2f638SBram Moolenaar     char *buf,
168168c2f638SBram Moolenaar     int bufsize,
168268c2f638SBram Moolenaar     char **context,
168368c2f638SBram Moolenaar     char **linenumber,
168468c2f638SBram Moolenaar     char **search)
1685071d4279SBram Moolenaar {
1686071d4279SBram Moolenaar     int ch;
1687071d4279SBram Moolenaar     char *p;
1688071d4279SBram Moolenaar     char *name;
1689071d4279SBram Moolenaar 
1690071d4279SBram Moolenaar     if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL)
1691071d4279SBram Moolenaar     {
1692071d4279SBram Moolenaar 	if (feof(csinfo[cnumber].fr_fp))
1693071d4279SBram Moolenaar 	    errno = EIO;
1694071d4279SBram Moolenaar 
1695071d4279SBram Moolenaar 	cs_reading_emsg(cnumber);
1696071d4279SBram Moolenaar 
1697071d4279SBram Moolenaar 	return NULL;
1698071d4279SBram Moolenaar     }
1699071d4279SBram Moolenaar 
17002ab2e860SBram Moolenaar     // If the line's too long for the buffer, discard it.
1701071d4279SBram Moolenaar     if ((p = strchr(buf, '\n')) == NULL)
1702071d4279SBram Moolenaar     {
1703071d4279SBram Moolenaar 	while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
1704071d4279SBram Moolenaar 	    ;
1705071d4279SBram Moolenaar 	return NULL;
1706071d4279SBram Moolenaar     }
1707071d4279SBram Moolenaar     *p = '\0';
1708071d4279SBram Moolenaar 
1709071d4279SBram Moolenaar     /*
1710071d4279SBram Moolenaar      * cscope output is in the following format:
1711071d4279SBram Moolenaar      *
1712071d4279SBram Moolenaar      *	<filename> <context> <line number> <pattern>
1713071d4279SBram Moolenaar      */
1714dfa5e464S=?UTF-8?q?Dundar=20G=C3=B6c?=     if ((name = strtok(buf, (const char *)" ")) == NULL)
1715071d4279SBram Moolenaar 	return NULL;
1716071d4279SBram Moolenaar     if ((*context = strtok(NULL, (const char *)" ")) == NULL)
1717071d4279SBram Moolenaar 	return NULL;
1718071d4279SBram Moolenaar     if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
1719071d4279SBram Moolenaar 	return NULL;
17202ab2e860SBram Moolenaar     *search = *linenumber + strlen(*linenumber) + 1;	// +1 to skip \0
1721071d4279SBram Moolenaar 
17222ab2e860SBram Moolenaar     // --- nvi ---
17232ab2e860SBram Moolenaar     // If the file is older than the cscope database, that is,
17242ab2e860SBram Moolenaar     // the database was built since the file was last modified,
17252ab2e860SBram Moolenaar     // or there wasn't a search string, use the line number.
1726071d4279SBram Moolenaar     if (strcmp(*search, "<unknown>") == 0)
1727071d4279SBram Moolenaar 	*search = NULL;
1728071d4279SBram Moolenaar 
1729071d4279SBram Moolenaar     name = cs_resolve_file(cnumber, name);
1730071d4279SBram Moolenaar     return name;
1731071d4279SBram Moolenaar }
1732071d4279SBram Moolenaar 
1733c716c306SBram Moolenaar #ifdef FEAT_QUICKFIX
1734071d4279SBram Moolenaar /*
1735d4db7719SBram Moolenaar  * Write cscope find results to file.
1736071d4279SBram Moolenaar  */
1737071d4279SBram Moolenaar     static void
cs_file_results(FILE * f,int * nummatches_a)173868c2f638SBram Moolenaar cs_file_results(FILE *f, int *nummatches_a)
1739071d4279SBram Moolenaar {
1740071d4279SBram Moolenaar     int i, j;
1741071d4279SBram Moolenaar     char *buf;
1742071d4279SBram Moolenaar     char *search, *slno;
1743071d4279SBram Moolenaar     char *fullname;
1744071d4279SBram Moolenaar     char *cntx;
1745071d4279SBram Moolenaar     char *context;
1746071d4279SBram Moolenaar 
1747c799fe20SBram Moolenaar     buf = alloc(CSREAD_BUFSIZE);
1748071d4279SBram Moolenaar     if (buf == NULL)
1749071d4279SBram Moolenaar 	return;
1750071d4279SBram Moolenaar 
17519fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
1752071d4279SBram Moolenaar     {
1753071d4279SBram Moolenaar 	if (nummatches_a[i] < 1)
1754071d4279SBram Moolenaar 	    continue;
1755071d4279SBram Moolenaar 
1756071d4279SBram Moolenaar 	for (j = 0; j < nummatches_a[i]; j++)
1757071d4279SBram Moolenaar 	{
1758071d4279SBram Moolenaar 	   if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1759071d4279SBram Moolenaar 			   &slno, &search)) == NULL)
1760071d4279SBram Moolenaar 	       continue;
1761071d4279SBram Moolenaar 
1762c799fe20SBram Moolenaar 	   context = alloc(strlen(cntx)+5);
1763071d4279SBram Moolenaar 	   if (context == NULL)
17644dba0425SBram Moolenaar 	   {
17654dba0425SBram Moolenaar 	       vim_free(fullname);
1766071d4279SBram Moolenaar 	       continue;
17674dba0425SBram Moolenaar 	   }
1768071d4279SBram Moolenaar 
1769071d4279SBram Moolenaar 	   if (strcmp(cntx, "<global>")==0)
1770071d4279SBram Moolenaar 	       strcpy(context, "<<global>>");
1771071d4279SBram Moolenaar 	   else
1772071d4279SBram Moolenaar 	       sprintf(context, "<<%s>>", cntx);
1773071d4279SBram Moolenaar 
1774071d4279SBram Moolenaar 	   if (search == NULL)
1775071d4279SBram Moolenaar 	       fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
1776071d4279SBram Moolenaar 	   else
1777071d4279SBram Moolenaar 	       fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
1778071d4279SBram Moolenaar 
1779071d4279SBram Moolenaar 	   vim_free(context);
1780071d4279SBram Moolenaar 	   vim_free(fullname);
17812ab2e860SBram Moolenaar 	} // for all matches
1782071d4279SBram Moolenaar 
1783071d4279SBram Moolenaar 	(void)cs_read_prompt(i);
1784071d4279SBram Moolenaar 
17852ab2e860SBram Moolenaar     } // for all cscope connections
1786071d4279SBram Moolenaar     vim_free(buf);
1787071d4279SBram Moolenaar }
1788c716c306SBram Moolenaar #endif
1789071d4279SBram Moolenaar 
1790071d4279SBram Moolenaar /*
1791d4db7719SBram Moolenaar  * Get parsed cscope output and calls cs_make_vim_style_matches to convert
1792d4db7719SBram Moolenaar  * into ctags format.
1793d6f676daSBram Moolenaar  * When there are no matches sets "*matches_p" to NULL.
1794071d4279SBram Moolenaar  */
1795071d4279SBram Moolenaar     static void
cs_fill_results(char * tagstr,int totmatches,int * nummatches_a,char *** matches_p,char *** cntxts_p,int * matched)179668c2f638SBram Moolenaar cs_fill_results(
179768c2f638SBram Moolenaar     char *tagstr,
179868c2f638SBram Moolenaar     int totmatches,
179968c2f638SBram Moolenaar     int *nummatches_a,
180068c2f638SBram Moolenaar     char ***matches_p,
180168c2f638SBram Moolenaar     char ***cntxts_p,
180268c2f638SBram Moolenaar     int *matched)
1803071d4279SBram Moolenaar {
1804071d4279SBram Moolenaar     int i, j;
1805071d4279SBram Moolenaar     char *buf;
1806071d4279SBram Moolenaar     char *search, *slno;
1807071d4279SBram Moolenaar     int totsofar = 0;
1808071d4279SBram Moolenaar     char **matches = NULL;
1809071d4279SBram Moolenaar     char **cntxts = NULL;
1810071d4279SBram Moolenaar     char *fullname;
1811071d4279SBram Moolenaar     char *cntx;
1812071d4279SBram Moolenaar 
1813071d4279SBram Moolenaar     assert(totmatches > 0);
1814071d4279SBram Moolenaar 
1815c799fe20SBram Moolenaar     buf = alloc(CSREAD_BUFSIZE);
1816071d4279SBram Moolenaar     if (buf == NULL)
1817071d4279SBram Moolenaar 	return;
1818071d4279SBram Moolenaar 
1819c799fe20SBram Moolenaar     if ((matches = ALLOC_MULT(char *, totmatches)) == NULL)
1820071d4279SBram Moolenaar 	goto parse_out;
1821c799fe20SBram Moolenaar     if ((cntxts = ALLOC_MULT(char *, totmatches)) == NULL)
1822071d4279SBram Moolenaar 	goto parse_out;
1823071d4279SBram Moolenaar 
18249fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
1825071d4279SBram Moolenaar     {
1826071d4279SBram Moolenaar 	if (nummatches_a[i] < 1)
1827071d4279SBram Moolenaar 	    continue;
1828071d4279SBram Moolenaar 
1829071d4279SBram Moolenaar 	for (j = 0; j < nummatches_a[i]; j++)
1830071d4279SBram Moolenaar 	{
1831071d4279SBram Moolenaar 	   if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
1832071d4279SBram Moolenaar 			   &slno, &search)) == NULL)
1833071d4279SBram Moolenaar 		continue;
1834071d4279SBram Moolenaar 
1835071d4279SBram Moolenaar 	    matches[totsofar] = cs_make_vim_style_matches(fullname, slno,
1836071d4279SBram Moolenaar 							  search, tagstr);
1837071d4279SBram Moolenaar 
1838071d4279SBram Moolenaar 	    vim_free(fullname);
1839071d4279SBram Moolenaar 
1840071d4279SBram Moolenaar 	    if (strcmp(cntx, "<global>") == 0)
1841071d4279SBram Moolenaar 		cntxts[totsofar] = NULL;
1842071d4279SBram Moolenaar 	    else
18432ab2e860SBram Moolenaar 		// note: if vim_strsave returns NULL, then the context
18442ab2e860SBram Moolenaar 		// will be "<global>", which is misleading.
1845071d4279SBram Moolenaar 		cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
1846071d4279SBram Moolenaar 
1847071d4279SBram Moolenaar 	    if (matches[totsofar] != NULL)
1848071d4279SBram Moolenaar 		totsofar++;
1849071d4279SBram Moolenaar 
18502ab2e860SBram Moolenaar 	} // for all matches
1851071d4279SBram Moolenaar 
1852071d4279SBram Moolenaar 	(void)cs_read_prompt(i);
1853071d4279SBram Moolenaar 
18542ab2e860SBram Moolenaar     } // for all cscope connections
1855071d4279SBram Moolenaar 
1856071d4279SBram Moolenaar parse_out:
1857d6f676daSBram Moolenaar     if (totsofar == 0)
1858d6f676daSBram Moolenaar     {
18592ab2e860SBram Moolenaar 	// No matches, free the arrays and return NULL in "*matches_p".
1860d23a8236SBram Moolenaar 	VIM_CLEAR(matches);
1861d23a8236SBram Moolenaar 	VIM_CLEAR(cntxts);
1862d6f676daSBram Moolenaar     }
1863071d4279SBram Moolenaar     *matched = totsofar;
1864071d4279SBram Moolenaar     *matches_p = matches;
1865071d4279SBram Moolenaar     *cntxts_p = cntxts;
1866d6f676daSBram Moolenaar 
1867071d4279SBram Moolenaar     vim_free(buf);
18682ab2e860SBram Moolenaar }
1869071d4279SBram Moolenaar 
1870071d4279SBram Moolenaar 
18712ab2e860SBram Moolenaar /*
18722ab2e860SBram Moolenaar  * get the requested path components
18732ab2e860SBram Moolenaar  */
1874071d4279SBram Moolenaar     static char *
cs_pathcomponents(char * path)187568c2f638SBram Moolenaar cs_pathcomponents(char *path)
1876071d4279SBram Moolenaar {
1877071d4279SBram Moolenaar     int		i;
1878071d4279SBram Moolenaar     char	*s;
1879071d4279SBram Moolenaar 
1880071d4279SBram Moolenaar     if (p_cspc == 0)
1881071d4279SBram Moolenaar 	return path;
1882071d4279SBram Moolenaar 
1883071d4279SBram Moolenaar     s = path + strlen(path) - 1;
1884071d4279SBram Moolenaar     for (i = 0; i < p_cspc; ++i)
1885071d4279SBram Moolenaar 	while (s > path && *--s != '/'
18864f97475dSBram Moolenaar #ifdef MSWIN
1887071d4279SBram Moolenaar 		&& *--s != '\\'
1888071d4279SBram Moolenaar #endif
1889071d4279SBram Moolenaar 		)
1890071d4279SBram Moolenaar 	    ;
1891071d4279SBram Moolenaar     if ((s > path && *s == '/')
18924f97475dSBram Moolenaar #ifdef MSWIN
1893071d4279SBram Moolenaar 	|| (s > path && *s == '\\')
1894071d4279SBram Moolenaar #endif
1895071d4279SBram Moolenaar 	    )
1896071d4279SBram Moolenaar 	++s;
1897071d4279SBram Moolenaar     return s;
1898071d4279SBram Moolenaar }
1899071d4279SBram Moolenaar 
1900071d4279SBram Moolenaar /*
1901d4db7719SBram Moolenaar  * Called from cs_manage_matches().
1902071d4279SBram Moolenaar  */
1903071d4279SBram Moolenaar     static void
cs_print_tags_priv(char ** matches,char ** cntxts,int num_matches)190468c2f638SBram Moolenaar cs_print_tags_priv(char **matches, char **cntxts, int num_matches)
1905071d4279SBram Moolenaar {
1906071d4279SBram Moolenaar     char	*buf = NULL;
19079abd5c65SBram Moolenaar     char	*t_buf;
19082ab2e860SBram Moolenaar     int		bufsize = 0; // Track available bufsize
1909071d4279SBram Moolenaar     int		newsize = 0;
1910071d4279SBram Moolenaar     char	*ptag;
1911071d4279SBram Moolenaar     char	*fname, *lno, *extra, *tbuf;
1912071d4279SBram Moolenaar     int		i, idx, num;
1913071d4279SBram Moolenaar     char	*globalcntx = "GLOBAL";
1914071d4279SBram Moolenaar     char	*cntxformat = " <<%s>>";
1915071d4279SBram Moolenaar     char	*context;
1916071d4279SBram Moolenaar     char	*cstag_msg = _("Cscope tag: %s");
1917071d4279SBram Moolenaar     char	*csfmt_str = "%4d %6s  ";
1918071d4279SBram Moolenaar 
1919071d4279SBram Moolenaar     assert(num_matches > 0);
1920071d4279SBram Moolenaar 
1921c799fe20SBram Moolenaar     if ((tbuf = alloc(strlen(matches[0]) + 1)) == NULL)
1922071d4279SBram Moolenaar 	return;
1923071d4279SBram Moolenaar 
1924071d4279SBram Moolenaar     strcpy(tbuf, matches[0]);
1925071d4279SBram Moolenaar     ptag = strtok(tbuf, "\t");
1926cde88547SBram Moolenaar     if (ptag == NULL)
192742dd7aeeSBram Moolenaar     {
192842dd7aeeSBram Moolenaar 	vim_free(tbuf);
1929cde88547SBram Moolenaar 	return;
193042dd7aeeSBram Moolenaar     }
1931071d4279SBram Moolenaar 
1932a93fa7eeSBram Moolenaar     newsize = (int)(strlen(cstag_msg) + strlen(ptag));
1933c799fe20SBram Moolenaar     buf = alloc(newsize);
1934071d4279SBram Moolenaar     if (buf != NULL)
1935071d4279SBram Moolenaar     {
1936071d4279SBram Moolenaar 	bufsize = newsize;
1937071d4279SBram Moolenaar 	(void)sprintf(buf, cstag_msg, ptag);
193832526b3cSBram Moolenaar 	msg_puts_attr(buf, HL_ATTR(HLF_T));
1939071d4279SBram Moolenaar     }
1940071d4279SBram Moolenaar 
1941071d4279SBram Moolenaar     vim_free(tbuf);
1942071d4279SBram Moolenaar 
19432ab2e860SBram Moolenaar     msg_puts_attr(_("\n   #   line"), HL_ATTR(HLF_T));    // strlen is 7
1944071d4279SBram Moolenaar     msg_advance(msg_col + 2);
194532526b3cSBram Moolenaar     msg_puts_attr(_("filename / context / line\n"), HL_ATTR(HLF_T));
1946071d4279SBram Moolenaar 
1947071d4279SBram Moolenaar     num = 1;
1948071d4279SBram Moolenaar     for (i = 0; i < num_matches; i++)
1949071d4279SBram Moolenaar     {
1950071d4279SBram Moolenaar 	idx = i;
1951071d4279SBram Moolenaar 
19522ab2e860SBram Moolenaar 	// if we really wanted to, we could avoid this malloc and strcpy
19532ab2e860SBram Moolenaar 	// by parsing matches[i] on the fly and placing stuff into buf
19542ab2e860SBram Moolenaar 	// directly, but that's too much of a hassle
1955c799fe20SBram Moolenaar 	if ((tbuf = alloc(strlen(matches[idx]) + 1)) == NULL)
1956071d4279SBram Moolenaar 	    continue;
1957071d4279SBram Moolenaar 	(void)strcpy(tbuf, matches[idx]);
1958071d4279SBram Moolenaar 
1959e16e5a9dSBram Moolenaar 	if (strtok(tbuf, (const char *)"\t") == NULL
1960e16e5a9dSBram Moolenaar 		|| (fname = strtok(NULL, (const char *)"\t")) == NULL
1961e16e5a9dSBram Moolenaar 		|| (lno = strtok(NULL, (const char *)"\t")) == NULL)
1962e16e5a9dSBram Moolenaar 	{
1963e16e5a9dSBram Moolenaar 	    vim_free(tbuf);
1964071d4279SBram Moolenaar 	    continue;
1965e16e5a9dSBram Moolenaar 	}
1966f2a4e33fSBram Moolenaar 	extra = strtok(NULL, (const char *)"\t");
1967071d4279SBram Moolenaar 
19682ab2e860SBram Moolenaar 	lno[strlen(lno)-2] = '\0';  // ignore ;" at the end
1969071d4279SBram Moolenaar 
19702ab2e860SBram Moolenaar 	// hopefully 'num' (num of matches) will be less than 10^16
1971a93fa7eeSBram Moolenaar 	newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno));
1972071d4279SBram Moolenaar 	if (bufsize < newsize)
1973071d4279SBram Moolenaar 	{
19749abd5c65SBram Moolenaar 	    t_buf = buf;
1975c799fe20SBram Moolenaar 	    buf = vim_realloc(buf, newsize);
1976071d4279SBram Moolenaar 	    if (buf == NULL)
19779abd5c65SBram Moolenaar 	    {
1978071d4279SBram Moolenaar 		bufsize = 0;
19799abd5c65SBram Moolenaar 		vim_free(t_buf);
19809abd5c65SBram Moolenaar 	    }
1981071d4279SBram Moolenaar 	    else
1982071d4279SBram Moolenaar 		bufsize = newsize;
1983071d4279SBram Moolenaar 	}
1984071d4279SBram Moolenaar 	if (buf != NULL)
1985071d4279SBram Moolenaar 	{
19862ab2e860SBram Moolenaar 	    // csfmt_str = "%4d %6s  ";
1987071d4279SBram Moolenaar 	    (void)sprintf(buf, csfmt_str, num, lno);
198832526b3cSBram Moolenaar 	    msg_puts_attr(buf, HL_ATTR(HLF_CM));
1989071d4279SBram Moolenaar 	}
199032526b3cSBram Moolenaar 	msg_outtrans_long_attr((char_u *)cs_pathcomponents(fname),
199132526b3cSBram Moolenaar 							      HL_ATTR(HLF_CM));
1992071d4279SBram Moolenaar 
19932ab2e860SBram Moolenaar 	// compute the required space for the context
1994071d4279SBram Moolenaar 	if (cntxts[idx] != NULL)
1995071d4279SBram Moolenaar 	    context = cntxts[idx];
1996071d4279SBram Moolenaar 	else
1997071d4279SBram Moolenaar 	    context = globalcntx;
1998a93fa7eeSBram Moolenaar 	newsize = (int)(strlen(context) + strlen(cntxformat));
1999071d4279SBram Moolenaar 
2000071d4279SBram Moolenaar 	if (bufsize < newsize)
2001071d4279SBram Moolenaar 	{
20029abd5c65SBram Moolenaar 	    t_buf = buf;
2003c799fe20SBram Moolenaar 	    buf = vim_realloc(buf, newsize);
2004071d4279SBram Moolenaar 	    if (buf == NULL)
20059abd5c65SBram Moolenaar 	    {
2006071d4279SBram Moolenaar 		bufsize = 0;
20079abd5c65SBram Moolenaar 		vim_free(t_buf);
20089abd5c65SBram Moolenaar 	    }
2009071d4279SBram Moolenaar 	    else
2010071d4279SBram Moolenaar 		bufsize = newsize;
2011071d4279SBram Moolenaar 	}
2012071d4279SBram Moolenaar 	if (buf != NULL)
2013071d4279SBram Moolenaar 	{
2014071d4279SBram Moolenaar 	    (void)sprintf(buf, cntxformat, context);
2015071d4279SBram Moolenaar 
20162ab2e860SBram Moolenaar 	    // print the context only if it fits on the same line
2017071d4279SBram Moolenaar 	    if (msg_col + (int)strlen(buf) >= (int)Columns)
2018071d4279SBram Moolenaar 		msg_putchar('\n');
2019071d4279SBram Moolenaar 	    msg_advance(12);
202032526b3cSBram Moolenaar 	    msg_outtrans_long_attr((char_u *)buf, 0);
2021071d4279SBram Moolenaar 	    msg_putchar('\n');
2022071d4279SBram Moolenaar 	}
2023071d4279SBram Moolenaar 	if (extra != NULL)
2024071d4279SBram Moolenaar 	{
2025071d4279SBram Moolenaar 	    msg_advance(13);
202632526b3cSBram Moolenaar 	    msg_outtrans_long_attr((char_u *)extra, 0);
2027071d4279SBram Moolenaar 	}
2028071d4279SBram Moolenaar 
20292ab2e860SBram Moolenaar 	vim_free(tbuf); // only after printing extra due to strtok use
2030071d4279SBram Moolenaar 
2031071d4279SBram Moolenaar 	if (msg_col)
2032071d4279SBram Moolenaar 	    msg_putchar('\n');
2033071d4279SBram Moolenaar 
2034071d4279SBram Moolenaar 	ui_breakcheck();
2035071d4279SBram Moolenaar 	if (got_int)
2036071d4279SBram Moolenaar 	{
20372ab2e860SBram Moolenaar 	    got_int = FALSE;	// don't print any more matches
2038071d4279SBram Moolenaar 	    break;
2039071d4279SBram Moolenaar 	}
2040071d4279SBram Moolenaar 
2041071d4279SBram Moolenaar 	num++;
20422ab2e860SBram Moolenaar     } // for all matches
2043071d4279SBram Moolenaar 
2044071d4279SBram Moolenaar     vim_free(buf);
20452ab2e860SBram Moolenaar }
2046071d4279SBram Moolenaar 
2047071d4279SBram Moolenaar 
2048071d4279SBram Moolenaar /*
2049d4db7719SBram Moolenaar  * Read a cscope prompt (basically, skip over the ">> ").
2050071d4279SBram Moolenaar  */
2051071d4279SBram Moolenaar     static int
cs_read_prompt(int i)205268c2f638SBram Moolenaar cs_read_prompt(int i)
2053071d4279SBram Moolenaar {
2054071d4279SBram Moolenaar     int		ch;
20552ab2e860SBram Moolenaar     char	*buf = NULL; // buffer for possible error message from cscope
2056071d4279SBram Moolenaar     int		bufpos = 0;
2057071d4279SBram Moolenaar     char	*cs_emsg;
2058071d4279SBram Moolenaar     int		maxlen;
2059071d4279SBram Moolenaar     static char *eprompt = "Press the RETURN key to continue:";
2060a93fa7eeSBram Moolenaar     int		epromptlen = (int)strlen(eprompt);
2061071d4279SBram Moolenaar     int		n;
2062071d4279SBram Moolenaar 
2063071d4279SBram Moolenaar     cs_emsg = _("E609: Cscope error: %s");
20642ab2e860SBram Moolenaar     // compute maximum allowed len for Cscope error message
2065071d4279SBram Moolenaar     maxlen = (int)(IOSIZE - strlen(cs_emsg));
2066071d4279SBram Moolenaar 
2067071d4279SBram Moolenaar     for (;;)
2068071d4279SBram Moolenaar     {
2069071d4279SBram Moolenaar 	while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
20702ab2e860SBram Moolenaar 	    // if there is room and char is printable
2071071d4279SBram Moolenaar 	    if (bufpos < maxlen - 1 && vim_isprintc(ch))
2072071d4279SBram Moolenaar 	    {
20732ab2e860SBram Moolenaar 		if (buf == NULL) // lazy buffer allocation
2074c799fe20SBram Moolenaar 		    buf = alloc(maxlen);
2075071d4279SBram Moolenaar 		if (buf != NULL)
2076071d4279SBram Moolenaar 		{
20772ab2e860SBram Moolenaar 		    // append character to the message
2078071d4279SBram Moolenaar 		    buf[bufpos++] = ch;
2079071d4279SBram Moolenaar 		    buf[bufpos] = NUL;
2080071d4279SBram Moolenaar 		    if (bufpos >= epromptlen
2081071d4279SBram Moolenaar 			    && strcmp(&buf[bufpos - epromptlen], eprompt) == 0)
2082071d4279SBram Moolenaar 		    {
20832ab2e860SBram Moolenaar 			// remove eprompt from buf
2084071d4279SBram Moolenaar 			buf[bufpos - epromptlen] = NUL;
2085071d4279SBram Moolenaar 
20862ab2e860SBram Moolenaar 			// print message to user
2087f9e3e09fSBram Moolenaar 			(void)semsg(cs_emsg, buf);
2088071d4279SBram Moolenaar 
20892ab2e860SBram Moolenaar 			// send RETURN to cscope
2090071d4279SBram Moolenaar 			(void)putc('\n', csinfo[i].to_fp);
2091071d4279SBram Moolenaar 			(void)fflush(csinfo[i].to_fp);
2092071d4279SBram Moolenaar 
20932ab2e860SBram Moolenaar 			// clear buf
2094071d4279SBram Moolenaar 			bufpos = 0;
2095071d4279SBram Moolenaar 			buf[bufpos] = NUL;
2096071d4279SBram Moolenaar 		    }
2097071d4279SBram Moolenaar 		}
2098071d4279SBram Moolenaar 	    }
2099071d4279SBram Moolenaar 
2100071d4279SBram Moolenaar 	for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n)
2101071d4279SBram Moolenaar 	{
2102071d4279SBram Moolenaar 	    if (n > 0)
2103071d4279SBram Moolenaar 		ch = getc(csinfo[i].fr_fp);
2104071d4279SBram Moolenaar 	    if (ch == EOF)
2105071d4279SBram Moolenaar 	    {
2106071d4279SBram Moolenaar 		if (buf != NULL && buf[0] != NUL)
2107f9e3e09fSBram Moolenaar 		    (void)semsg(cs_emsg, buf);
2108071d4279SBram Moolenaar 		else if (p_csverbose)
21092ab2e860SBram Moolenaar 		    cs_reading_emsg(i); // don't have additional information
2110071d4279SBram Moolenaar 		cs_release_csp(i, TRUE);
2111071d4279SBram Moolenaar 		vim_free(buf);
2112071d4279SBram Moolenaar 		return CSCOPE_FAILURE;
2113071d4279SBram Moolenaar 	    }
2114071d4279SBram Moolenaar 
2115071d4279SBram Moolenaar 	    if (ch != CSCOPE_PROMPT[n])
2116071d4279SBram Moolenaar 	    {
2117071d4279SBram Moolenaar 		ch = EOF;
2118071d4279SBram Moolenaar 		break;
2119071d4279SBram Moolenaar 	    }
2120071d4279SBram Moolenaar 	}
2121071d4279SBram Moolenaar 
2122071d4279SBram Moolenaar 	if (ch == EOF)
21232ab2e860SBram Moolenaar 	    continue;	    // didn't find the prompt
21242ab2e860SBram Moolenaar 	break;		    // did find the prompt
2125071d4279SBram Moolenaar     }
2126071d4279SBram Moolenaar 
2127071d4279SBram Moolenaar     vim_free(buf);
2128071d4279SBram Moolenaar     return CSCOPE_SUCCESS;
2129071d4279SBram Moolenaar }
2130071d4279SBram Moolenaar 
21317dc767c8SBram Moolenaar #if defined(UNIX) && defined(SIGALRM)
21327dc767c8SBram Moolenaar /*
21337dc767c8SBram Moolenaar  * Used to catch and ignore SIGALRM below.
21347dc767c8SBram Moolenaar  */
21357dc767c8SBram Moolenaar     static RETSIGTYPE
SIGDEFARG(sigarg)21367dc767c8SBram Moolenaar sig_handler SIGDEFARG(sigarg)
21377dc767c8SBram Moolenaar {
21382ab2e860SBram Moolenaar     // do nothing
21397dc767c8SBram Moolenaar     SIGRETURN;
21407dc767c8SBram Moolenaar }
21417dc767c8SBram Moolenaar #endif
2142071d4279SBram Moolenaar 
2143071d4279SBram Moolenaar /*
214402b06313SBram Moolenaar  * Does the actual free'ing for the cs ptr with an optional flag of whether
214502b06313SBram Moolenaar  * or not to free the filename.  Called by cs_kill and cs_reset.
2146071d4279SBram Moolenaar  */
2147071d4279SBram Moolenaar     static void
cs_release_csp(int i,int freefnpp)214868c2f638SBram Moolenaar cs_release_csp(int i, int freefnpp)
2149071d4279SBram Moolenaar {
2150071d4279SBram Moolenaar     /*
2151071d4279SBram Moolenaar      * Trying to exit normally (not sure whether it is fit to UNIX cscope
2152071d4279SBram Moolenaar      */
2153071d4279SBram Moolenaar     if (csinfo[i].to_fp != NULL)
2154071d4279SBram Moolenaar     {
2155071d4279SBram Moolenaar 	(void)fputs("q\n", csinfo[i].to_fp);
2156071d4279SBram Moolenaar 	(void)fflush(csinfo[i].to_fp);
2157071d4279SBram Moolenaar     }
21587dc767c8SBram Moolenaar #if defined(UNIX)
21597dc767c8SBram Moolenaar     {
2160e9b2884cSBram Moolenaar 	int waitpid_errno;
21617dc767c8SBram Moolenaar 	int pstat;
21627dc767c8SBram Moolenaar 	pid_t pid;
21637dc767c8SBram Moolenaar 
21647dc767c8SBram Moolenaar # if defined(HAVE_SIGACTION)
21657dc767c8SBram Moolenaar 	struct sigaction sa, old;
21667dc767c8SBram Moolenaar 
21672ab2e860SBram Moolenaar 	// Use sigaction() to limit the waiting time to two seconds.
21689701da01SBram Moolenaar 	sigemptyset(&sa.sa_mask);
21697dc767c8SBram Moolenaar 	sa.sa_handler = sig_handler;
217025153e12SBram Moolenaar #  ifdef SA_NODEFER
21717dc767c8SBram Moolenaar 	sa.sa_flags = SA_NODEFER;
217225153e12SBram Moolenaar #  else
217325153e12SBram Moolenaar 	sa.sa_flags = 0;
217425153e12SBram Moolenaar #  endif
21757dc767c8SBram Moolenaar 	sigaction(SIGALRM, &sa, &old);
21762ab2e860SBram Moolenaar 	alarm(2); // 2 sec timeout
21777dc767c8SBram Moolenaar 
21782ab2e860SBram Moolenaar 	// Block until cscope exits or until timer expires
21797dc767c8SBram Moolenaar 	pid = waitpid(csinfo[i].pid, &pstat, 0);
2180e9b2884cSBram Moolenaar 	waitpid_errno = errno;
21817dc767c8SBram Moolenaar 
21822ab2e860SBram Moolenaar 	// cancel pending alarm if still there and restore signal
21837dc767c8SBram Moolenaar 	alarm(0);
21847dc767c8SBram Moolenaar 	sigaction(SIGALRM, &old, NULL);
21857dc767c8SBram Moolenaar # else
21867dc767c8SBram Moolenaar 	int waited;
21877dc767c8SBram Moolenaar 
21882ab2e860SBram Moolenaar 	// Can't use sigaction(), loop for two seconds.  First yield the CPU
21892ab2e860SBram Moolenaar 	// to give cscope a chance to exit quickly.
21907dc767c8SBram Moolenaar 	sleep(0);
21917dc767c8SBram Moolenaar 	for (waited = 0; waited < 40; ++waited)
21927dc767c8SBram Moolenaar 	{
21937dc767c8SBram Moolenaar 	    pid = waitpid(csinfo[i].pid, &pstat, WNOHANG);
2194e9b2884cSBram Moolenaar 	    waitpid_errno = errno;
21957dc767c8SBram Moolenaar 	    if (pid != 0)
21962ab2e860SBram Moolenaar 		break;  // break unless the process is still running
21970981c872SBram Moolenaar 	    mch_delay(50L, 0); // sleep 50 ms
21987dc767c8SBram Moolenaar 	}
21997dc767c8SBram Moolenaar # endif
22007dc767c8SBram Moolenaar 	/*
22017dc767c8SBram Moolenaar 	 * If the cscope process is still running: kill it.
22027dc767c8SBram Moolenaar 	 * Safety check: If the PID would be zero here, the entire X session
22037dc767c8SBram Moolenaar 	 * would be killed.  -1 and 1 are dangerous as well.
22047dc767c8SBram Moolenaar 	 */
22057dc767c8SBram Moolenaar 	if (pid < 0 && csinfo[i].pid > 1)
22067dc767c8SBram Moolenaar 	{
2207e9b2884cSBram Moolenaar # ifdef ECHILD
2208e9b2884cSBram Moolenaar 	    int alive = TRUE;
2209e9b2884cSBram Moolenaar 
2210e9b2884cSBram Moolenaar 	    if (waitpid_errno == ECHILD)
2211e9b2884cSBram Moolenaar 	    {
2212e9b2884cSBram Moolenaar 		/*
2213e9b2884cSBram Moolenaar 		 * When using 'vim -g', vim is forked and cscope process is
2214e9b2884cSBram Moolenaar 		 * no longer a child process but a sibling.  So waitpid()
2215e9b2884cSBram Moolenaar 		 * fails with errno being ECHILD (No child processes).
2216e9b2884cSBram Moolenaar 		 * Don't send SIGKILL to cscope immediately but wait
2217e9b2884cSBram Moolenaar 		 * (polling) for it to exit normally as result of sending
2218e9b2884cSBram Moolenaar 		 * the "q" command, hence giving it a chance to clean up
2219e9b2884cSBram Moolenaar 		 * its temporary files.
2220e9b2884cSBram Moolenaar 		 */
2221e9b2884cSBram Moolenaar 		int waited;
2222e9b2884cSBram Moolenaar 
2223e9b2884cSBram Moolenaar 		sleep(0);
2224e9b2884cSBram Moolenaar 		for (waited = 0; waited < 40; ++waited)
2225e9b2884cSBram Moolenaar 		{
22262ab2e860SBram Moolenaar 		    // Check whether cscope process is still alive
2227e9b2884cSBram Moolenaar 		    if (kill(csinfo[i].pid, 0) != 0)
2228e9b2884cSBram Moolenaar 		    {
22292ab2e860SBram Moolenaar 			alive = FALSE; // cscope process no longer exists
2230e9b2884cSBram Moolenaar 			break;
2231e9b2884cSBram Moolenaar 		    }
22320981c872SBram Moolenaar 		    mch_delay(50L, 0); // sleep 50 ms
2233e9b2884cSBram Moolenaar 		}
2234e9b2884cSBram Moolenaar 	    }
2235e9b2884cSBram Moolenaar 	    if (alive)
2236e9b2884cSBram Moolenaar # endif
2237e9b2884cSBram Moolenaar 	    {
22389701da01SBram Moolenaar 		kill(csinfo[i].pid, SIGKILL);
22397dc767c8SBram Moolenaar 		(void)waitpid(csinfo[i].pid, &pstat, 0);
22407dc767c8SBram Moolenaar 	    }
22417dc767c8SBram Moolenaar 	}
2242e9b2884cSBram Moolenaar     }
22432ab2e860SBram Moolenaar #else  // !UNIX
224402b06313SBram Moolenaar     if (csinfo[i].hProc != NULL)
224502b06313SBram Moolenaar     {
22462ab2e860SBram Moolenaar 	// Give cscope a chance to exit normally
224702b06313SBram Moolenaar 	if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
2248071d4279SBram Moolenaar 	    TerminateProcess(csinfo[i].hProc, 0);
224902b06313SBram Moolenaar 	CloseHandle(csinfo[i].hProc);
225002b06313SBram Moolenaar     }
2251071d4279SBram Moolenaar #endif
2252071d4279SBram Moolenaar 
2253071d4279SBram Moolenaar     if (csinfo[i].fr_fp != NULL)
2254071d4279SBram Moolenaar 	(void)fclose(csinfo[i].fr_fp);
2255071d4279SBram Moolenaar     if (csinfo[i].to_fp != NULL)
2256071d4279SBram Moolenaar 	(void)fclose(csinfo[i].to_fp);
2257071d4279SBram Moolenaar 
2258071d4279SBram Moolenaar     if (freefnpp)
2259071d4279SBram Moolenaar     {
2260071d4279SBram Moolenaar 	vim_free(csinfo[i].fname);
2261071d4279SBram Moolenaar 	vim_free(csinfo[i].ppath);
2262071d4279SBram Moolenaar 	vim_free(csinfo[i].flags);
2263071d4279SBram Moolenaar     }
2264071d4279SBram Moolenaar 
2265071d4279SBram Moolenaar     clear_csinfo(i);
22662ab2e860SBram Moolenaar }
2267071d4279SBram Moolenaar 
2268071d4279SBram Moolenaar 
2269071d4279SBram Moolenaar /*
2270d4db7719SBram Moolenaar  * Calls cs_kill on all cscope connections then reinits.
2271071d4279SBram Moolenaar  */
2272071d4279SBram Moolenaar     static int
cs_reset(exarg_T * eap UNUSED)227368c2f638SBram Moolenaar cs_reset(exarg_T *eap UNUSED)
2274071d4279SBram Moolenaar {
2275071d4279SBram Moolenaar     char	**dblist = NULL, **pplist = NULL, **fllist = NULL;
2276071d4279SBram Moolenaar     int	i;
22772ab2e860SBram Moolenaar     char buf[20]; // for sprintf " (#%d)"
2278071d4279SBram Moolenaar 
22799fa49da7SBram Moolenaar     if (csinfo_size == 0)
22809fa49da7SBram Moolenaar 	return CSCOPE_SUCCESS;
22819fa49da7SBram Moolenaar 
22822ab2e860SBram Moolenaar     // malloc our db and ppath list
2283c799fe20SBram Moolenaar     dblist = ALLOC_MULT(char *, csinfo_size);
2284c799fe20SBram Moolenaar     pplist = ALLOC_MULT(char *, csinfo_size);
2285c799fe20SBram Moolenaar     fllist = ALLOC_MULT(char *, csinfo_size);
2286071d4279SBram Moolenaar     if (dblist == NULL || pplist == NULL || fllist == NULL)
2287071d4279SBram Moolenaar     {
2288071d4279SBram Moolenaar 	vim_free(dblist);
2289071d4279SBram Moolenaar 	vim_free(pplist);
2290071d4279SBram Moolenaar 	vim_free(fllist);
2291071d4279SBram Moolenaar 	return CSCOPE_FAILURE;
2292071d4279SBram Moolenaar     }
2293071d4279SBram Moolenaar 
22949fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
2295071d4279SBram Moolenaar     {
2296071d4279SBram Moolenaar 	dblist[i] = csinfo[i].fname;
2297071d4279SBram Moolenaar 	pplist[i] = csinfo[i].ppath;
2298071d4279SBram Moolenaar 	fllist[i] = csinfo[i].flags;
2299071d4279SBram Moolenaar 	if (csinfo[i].fname != NULL)
2300071d4279SBram Moolenaar 	    cs_release_csp(i, FALSE);
2301071d4279SBram Moolenaar     }
2302071d4279SBram Moolenaar 
23032ab2e860SBram Moolenaar     // rebuild the cscope connection list
23049fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
2305071d4279SBram Moolenaar     {
2306071d4279SBram Moolenaar 	if (dblist[i] != NULL)
2307071d4279SBram Moolenaar 	{
2308071d4279SBram Moolenaar 	    cs_add_common(dblist[i], pplist[i], fllist[i]);
2309071d4279SBram Moolenaar 	    if (p_csverbose)
2310071d4279SBram Moolenaar 	    {
23112ab2e860SBram Moolenaar 		// don't use smsg_attr() because we want to display the
23122ab2e860SBram Moolenaar 		// connection number in the same line as
23132ab2e860SBram Moolenaar 		// "Added cscope database..."
2314071d4279SBram Moolenaar 		sprintf(buf, " (#%d)", i);
231532526b3cSBram Moolenaar 		msg_puts_attr(buf, HL_ATTR(HLF_R));
2316071d4279SBram Moolenaar 	    }
2317071d4279SBram Moolenaar 	}
2318071d4279SBram Moolenaar 	vim_free(dblist[i]);
2319071d4279SBram Moolenaar 	vim_free(pplist[i]);
2320071d4279SBram Moolenaar 	vim_free(fllist[i]);
2321071d4279SBram Moolenaar     }
2322071d4279SBram Moolenaar     vim_free(dblist);
2323071d4279SBram Moolenaar     vim_free(pplist);
2324071d4279SBram Moolenaar     vim_free(fllist);
2325071d4279SBram Moolenaar 
2326071d4279SBram Moolenaar     if (p_csverbose)
232732526b3cSBram Moolenaar 	msg_attr(_("All cscope databases reset"), HL_ATTR(HLF_R) | MSG_HIST);
2328071d4279SBram Moolenaar     return CSCOPE_SUCCESS;
23292ab2e860SBram Moolenaar }
2330071d4279SBram Moolenaar 
2331071d4279SBram Moolenaar 
2332071d4279SBram Moolenaar /*
233328c21919SBram Moolenaar  * Construct the full pathname to a file found in the cscope database.
2334071d4279SBram Moolenaar  * (Prepends ppath, if there is one and if it's not already prepended,
2335071d4279SBram Moolenaar  * otherwise just uses the name found.)
2336071d4279SBram Moolenaar  *
233728c21919SBram Moolenaar  * We need to prepend the prefix because on some cscope's (e.g., the one that
2338071d4279SBram Moolenaar  * ships with Solaris 2.6), the output never has the prefix prepended.
233928c21919SBram Moolenaar  * Contrast this with my development system (Digital Unix), which does.
2340071d4279SBram Moolenaar  */
2341071d4279SBram Moolenaar     static char *
cs_resolve_file(int i,char * name)234268c2f638SBram Moolenaar cs_resolve_file(int i, char *name)
2343071d4279SBram Moolenaar {
2344071d4279SBram Moolenaar     char	*fullname;
2345071d4279SBram Moolenaar     int		len;
23462f982e4fSBram Moolenaar     char_u	*csdir = NULL;
2347071d4279SBram Moolenaar 
2348071d4279SBram Moolenaar     /*
23492f982e4fSBram Moolenaar      * Ppath is freed when we destroy the cscope connection.
23502f982e4fSBram Moolenaar      * Fullname is freed after cs_make_vim_style_matches, after it's been
23512f982e4fSBram Moolenaar      * copied into the tag buffer used by Vim.
2352071d4279SBram Moolenaar      */
2353a93fa7eeSBram Moolenaar     len = (int)(strlen(name) + 2);
2354071d4279SBram Moolenaar     if (csinfo[i].ppath != NULL)
2355a93fa7eeSBram Moolenaar 	len += (int)strlen(csinfo[i].ppath);
23562f982e4fSBram Moolenaar     else if (p_csre && csinfo[i].fname != NULL)
23572f982e4fSBram Moolenaar     {
23582ab2e860SBram Moolenaar 	// If 'cscoperelative' is set and ppath is not set, use cscope.out
23592ab2e860SBram Moolenaar 	// path in path resolution.
23602f982e4fSBram Moolenaar 	csdir = alloc(MAXPATHL);
23612f982e4fSBram Moolenaar 	if (csdir != NULL)
23622f982e4fSBram Moolenaar 	{
23632f982e4fSBram Moolenaar 	    vim_strncpy(csdir, (char_u *)csinfo[i].fname,
236428c21919SBram Moolenaar 					  gettail((char_u *)csinfo[i].fname)
236528c21919SBram Moolenaar 						 - (char_u *)csinfo[i].fname);
23662f982e4fSBram Moolenaar 	    len += (int)STRLEN(csdir);
23672f982e4fSBram Moolenaar 	}
23682f982e4fSBram Moolenaar     }
2369071d4279SBram Moolenaar 
23702ab2e860SBram Moolenaar     // Note/example: this won't work if the cscope output already starts
23712ab2e860SBram Moolenaar     // "../.." and the prefix path is also "../..".  if something like this
23722ab2e860SBram Moolenaar     // happens, you are screwed up and need to fix how you're using cscope.
23732f982e4fSBram Moolenaar     if (csinfo[i].ppath != NULL
23742f982e4fSBram Moolenaar 	    && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0)
23752f982e4fSBram Moolenaar 	    && (name[0] != '/')
23764f97475dSBram Moolenaar #ifdef MSWIN
2377071d4279SBram Moolenaar 	    && name[0] != '\\' && name[1] != ':'
2378071d4279SBram Moolenaar #endif
2379071d4279SBram Moolenaar        )
238028c21919SBram Moolenaar     {
2381c799fe20SBram Moolenaar 	if ((fullname = alloc(len)) != NULL)
2382071d4279SBram Moolenaar 	    (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
238328c21919SBram Moolenaar     }
238428c21919SBram Moolenaar     else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL)
23852f982e4fSBram Moolenaar     {
23862ab2e860SBram Moolenaar 	// Check for csdir to be non empty to avoid empty path concatenated to
23872ab2e860SBram Moolenaar 	// cscope output.
238803227eebSBram Moolenaar 	fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE);
23892f982e4fSBram Moolenaar     }
2390071d4279SBram Moolenaar     else
239128c21919SBram Moolenaar     {
239228c21919SBram Moolenaar 	fullname = (char *)vim_strsave((char_u *)name);
239328c21919SBram Moolenaar     }
2394071d4279SBram Moolenaar 
23952f982e4fSBram Moolenaar     vim_free(csdir);
2396071d4279SBram Moolenaar     return fullname;
23972f982e4fSBram Moolenaar }
2398071d4279SBram Moolenaar 
2399071d4279SBram Moolenaar 
2400071d4279SBram Moolenaar /*
2401d4db7719SBram Moolenaar  * Show all cscope connections.
2402071d4279SBram Moolenaar  */
2403071d4279SBram Moolenaar     static int
cs_show(exarg_T * eap UNUSED)240468c2f638SBram Moolenaar cs_show(exarg_T *eap UNUSED)
2405071d4279SBram Moolenaar {
2406071d4279SBram Moolenaar     short i;
2407071d4279SBram Moolenaar     if (cs_cnt_connections() == 0)
240832526b3cSBram Moolenaar 	msg_puts(_("no cscope connections\n"));
2409071d4279SBram Moolenaar     else
2410071d4279SBram Moolenaar     {
241132526b3cSBram Moolenaar 	msg_puts_attr(
2412071d4279SBram Moolenaar 	    _(" # pid    database name                       prepend path\n"),
24138820b486SBram Moolenaar 	    HL_ATTR(HLF_T));
24149fa49da7SBram Moolenaar 	for (i = 0; i < csinfo_size; i++)
2415071d4279SBram Moolenaar 	{
2416071d4279SBram Moolenaar 	    if (csinfo[i].fname == NULL)
2417071d4279SBram Moolenaar 		continue;
2418071d4279SBram Moolenaar 
2419071d4279SBram Moolenaar 	    if (csinfo[i].ppath != NULL)
2420f9e3e09fSBram Moolenaar 		(void)smsg("%2d %-5ld  %-34s  %-32s",
2421071d4279SBram Moolenaar 		    i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
2422071d4279SBram Moolenaar 	    else
2423f9e3e09fSBram Moolenaar 		(void)smsg("%2d %-5ld  %-34s  <none>",
2424071d4279SBram Moolenaar 			   i, (long)csinfo[i].pid, csinfo[i].fname);
2425071d4279SBram Moolenaar 	}
2426071d4279SBram Moolenaar     }
2427071d4279SBram Moolenaar 
2428071d4279SBram Moolenaar     wait_return(TRUE);
2429071d4279SBram Moolenaar     return CSCOPE_SUCCESS;
24302ab2e860SBram Moolenaar }
2431071d4279SBram Moolenaar 
243202b06313SBram Moolenaar 
243302b06313SBram Moolenaar /*
243402b06313SBram Moolenaar  * Only called when VIM exits to quit any cscope sessions.
243502b06313SBram Moolenaar  */
243602b06313SBram Moolenaar     void
cs_end(void)243768c2f638SBram Moolenaar cs_end(void)
243802b06313SBram Moolenaar {
243902b06313SBram Moolenaar     int i;
244002b06313SBram Moolenaar 
24419fa49da7SBram Moolenaar     for (i = 0; i < csinfo_size; i++)
244202b06313SBram Moolenaar 	cs_release_csp(i, TRUE);
24439fa49da7SBram Moolenaar     vim_free(csinfo);
24449fa49da7SBram Moolenaar     csinfo_size = 0;
244502b06313SBram Moolenaar }
244602b06313SBram Moolenaar 
24472ab2e860SBram Moolenaar #endif	// FEAT_CSCOPE
2448071d4279SBram Moolenaar 
24496f72e90dSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
24506f72e90dSBram Moolenaar 
24516f72e90dSBram Moolenaar /*
24526f72e90dSBram Moolenaar  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
24536f72e90dSBram Moolenaar  *
24546f72e90dSBram Moolenaar  * Checks the existence of a cscope connection.
24556f72e90dSBram Moolenaar  */
24566f72e90dSBram Moolenaar     void
f_cscope_connection(typval_T * argvars UNUSED,typval_T * rettv UNUSED)24576f72e90dSBram Moolenaar f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
24586f72e90dSBram Moolenaar {
24596f72e90dSBram Moolenaar # ifdef FEAT_CSCOPE
24606f72e90dSBram Moolenaar     int		num = 0;
24616f72e90dSBram Moolenaar     char_u	*dbpath = NULL;
24626f72e90dSBram Moolenaar     char_u	*prepend = NULL;
24636f72e90dSBram Moolenaar     char_u	buf[NUMBUFLEN];
24646f72e90dSBram Moolenaar 
24657973de35SYegappan Lakshmanan     if (in_vim9script()
24667973de35SYegappan Lakshmanan 	    && (check_for_opt_number_arg(argvars, 0) == FAIL
24677973de35SYegappan Lakshmanan 		|| (argvars[0].v_type != VAR_UNKNOWN
24687973de35SYegappan Lakshmanan 		    && (check_for_opt_string_arg(argvars, 1) == FAIL
24697973de35SYegappan Lakshmanan 			|| (argvars[1].v_type != VAR_UNKNOWN
24707973de35SYegappan Lakshmanan 			    && check_for_opt_string_arg(argvars, 2) == FAIL)))))
24717973de35SYegappan Lakshmanan 	return;
24727973de35SYegappan Lakshmanan 
24736f72e90dSBram Moolenaar     if (argvars[0].v_type != VAR_UNKNOWN
24746f72e90dSBram Moolenaar 	    && argvars[1].v_type != VAR_UNKNOWN)
24756f72e90dSBram Moolenaar     {
24766f72e90dSBram Moolenaar 	num = (int)tv_get_number(&argvars[0]);
24776f72e90dSBram Moolenaar 	dbpath = tv_get_string(&argvars[1]);
24786f72e90dSBram Moolenaar 	if (argvars[2].v_type != VAR_UNKNOWN)
24796f72e90dSBram Moolenaar 	    prepend = tv_get_string_buf(&argvars[2], buf);
24806f72e90dSBram Moolenaar     }
24816f72e90dSBram Moolenaar 
24826f72e90dSBram Moolenaar     rettv->vval.v_number = cs_connection(num, dbpath, prepend);
24836f72e90dSBram Moolenaar # endif
24846f72e90dSBram Moolenaar }
24856f72e90dSBram Moolenaar 
24866f72e90dSBram Moolenaar #endif // FEAT_EVAL
2487