1/*-
2 * Copyright (c) 1994, 1996
3 *	Rob Mayoff.  All rights reserved.
4 * Copyright (c) 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "$Id: ex_cscope.c,v 10.25 2012/10/04 09:23:03 zy Exp $";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/stat.h>
19#include <sys/wait.h>
20
21#include <bitstring.h>
22#include <ctype.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <limits.h>
26#include <signal.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <termios.h>
32#include <unistd.h>
33
34#include "../common/common.h"
35#include "pathnames.h"
36#include "tag.h"
37
38#define	CSCOPE_DBFILE		"cscope.out"
39#define	CSCOPE_PATHS		"cscope.tpath"
40
41/*
42 * 0name	find all uses of name
43 * 1name	find definition of name
44 * 2name	find all function calls made from name
45 * 3name	find callers of name
46 * 4string	find text string (cscope 12.9)
47 * 4name	find assignments to name (cscope 13.3)
48 * 5pattern	change pattern -- NOT USED
49 * 6pattern	find pattern
50 * 7name	find files with name as substring
51 * 8name	find files #including name
52 */
53#define	FINDHELP "\
54find c|d|e|f|g|i|s|t buffer|pattern\n\
55      c: find callers of name\n\
56      d: find all function calls made from name\n\
57      e: find pattern\n\
58      f: find files with name as substring\n\
59      g: find definition of name\n\
60      i: find files #including name\n\
61      s: find all uses of name\n\
62      t: find assignments to name"
63
64static int cscope_add __P((SCR *, EXCMD *, CHAR_T *));
65static int cscope_find __P((SCR *, EXCMD*, CHAR_T *));
66static int cscope_help __P((SCR *, EXCMD *, CHAR_T *));
67static int cscope_kill __P((SCR *, EXCMD *, CHAR_T *));
68static int cscope_reset __P((SCR *, EXCMD *, CHAR_T *));
69
70typedef struct _cc {
71	char	 *name;
72	int	(*function) __P((SCR *, EXCMD *, CHAR_T *));
73	char	 *help_msg;
74	char	 *usage_msg;
75} CC;
76
77static CC const cscope_cmds[] = {
78	{ "add",   cscope_add,
79	  "Add a new cscope database", "add file | directory" },
80	{ "find",  cscope_find,
81	  "Query the databases for a pattern", FINDHELP },
82	{ "help",  cscope_help,
83	  "Show help for cscope commands", "help [command]" },
84	{ "kill",  cscope_kill,
85	  "Kill a cscope connection", "kill number" },
86	{ "reset", cscope_reset,
87	  "Discard all current cscope connections", "reset" },
88	{ NULL }
89};
90
91static TAGQ	*create_cs_cmd __P((SCR *, char *, size_t *));
92static int	 csc_help __P((SCR *, char *));
93static void	 csc_file __P((SCR *,
94		    CSC *, char *, char **, size_t *, int *));
95static int	 get_paths __P((SCR *, CSC *));
96static CC const	*lookup_ccmd __P((char *));
97static int	 parse __P((SCR *, CSC *, TAGQ *, int *));
98static int	 read_prompt __P((SCR *, CSC *));
99static int	 run_cscope __P((SCR *, CSC *, char *));
100static int	 start_cscopes __P((SCR *, EXCMD *));
101static int	 terminate __P((SCR *, CSC *, int));
102
103/*
104 * ex_cscope --
105 *	Perform an ex cscope.
106 *
107 * PUBLIC: int ex_cscope __P((SCR *, EXCMD *));
108 */
109int
110ex_cscope(SCR *sp, EXCMD *cmdp)
111{
112	CC const *ccp;
113	EX_PRIVATE *exp;
114	int i;
115	CHAR_T *cmd;
116	CHAR_T *p;
117	char *np;
118	size_t nlen;
119
120	/* Initialize the default cscope directories. */
121	exp = EXP(sp);
122	if (!F_ISSET(exp, EXP_CSCINIT) && start_cscopes(sp, cmdp))
123		return (1);
124	F_SET(exp, EXP_CSCINIT);
125
126	/* Skip leading whitespace. */
127	for (p = cmdp->argv[0]->bp, i = cmdp->argv[0]->len; i > 0; --i, ++p)
128		if (!isspace(*p))
129			break;
130	if (i == 0)
131		goto usage;
132
133	/* Skip the command to any arguments. */
134	for (cmd = p; i > 0; --i, ++p)
135		if (isspace(*p))
136			break;
137	if (*p != '\0') {
138		*p++ = '\0';
139		for (; *p && isspace(*p); ++p);
140	}
141
142	INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen);
143	if ((ccp = lookup_ccmd(np)) == NULL) {
144usage:		msgq(sp, M_ERR, "309|Use \"cscope help\" for help");
145		return (1);
146	}
147
148	/* Call the underlying function. */
149	return (ccp->function(sp, cmdp, p));
150}
151
152/*
153 * start_cscopes --
154 *	Initialize the cscope package.
155 */
156static int
157start_cscopes(SCR *sp, EXCMD *cmdp)
158{
159	size_t blen, len;
160	char *bp, *cscopes, *p, *t;
161	CHAR_T *wp;
162	size_t wlen;
163
164	/*
165	 * EXTENSION #1:
166	 *
167	 * If the CSCOPE_DIRS environment variable is set, we treat it as a
168	 * list of cscope directories that we're using, similar to the tags
169	 * edit option.
170	 *
171	 * XXX
172	 * This should probably be an edit option, although that implies that
173	 * we start/stop cscope processes periodically, instead of once when
174	 * the editor starts.
175	 */
176	if ((cscopes = getenv("CSCOPE_DIRS")) == NULL)
177		return (0);
178	len = strlen(cscopes);
179	GET_SPACE_RETC(sp, bp, blen, len);
180	memcpy(bp, cscopes, len + 1);
181
182	for (cscopes = t = bp; (p = strsep(&t, "\t :")) != NULL;)
183		if (*p != '\0') {
184			CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
185			(void)cscope_add(sp, cmdp, wp);
186		}
187
188	FREE_SPACE(sp, bp, blen);
189	return (0);
190}
191
192/*
193 * cscope_add --
194 *	The cscope add command.
195 */
196static int
197cscope_add(SCR *sp, EXCMD *cmdp, CHAR_T *dname)
198{
199	struct stat sb;
200	EX_PRIVATE *exp;
201	CSC *csc;
202	size_t len;
203	int cur_argc;
204	char *dbname, *path;
205	char *np = NULL;
206	size_t nlen;
207
208	exp = EXP(sp);
209
210	/*
211	 *  0 additional args: usage.
212	 *  1 additional args: matched a file.
213	 * >1 additional args: object, too many args.
214	 */
215	cur_argc = cmdp->argc;
216	if (argv_exp2(sp, cmdp, dname, STRLEN(dname))) {
217		return (1);
218	}
219	if (cmdp->argc == cur_argc) {
220		(void)csc_help(sp, "add");
221		return (1);
222	}
223	if (cmdp->argc == cur_argc + 1)
224		dname = cmdp->argv[cur_argc]->bp;
225	else {
226		ex_emsg(sp, np, EXM_FILECOUNT);
227		return (1);
228	}
229
230	INT2CHAR(sp, dname, STRLEN(dname)+1, np, nlen);
231
232	/*
233	 * The user can specify a specific file (so they can have multiple
234	 * Cscope databases in a single directory) or a directory.  If the
235	 * file doesn't exist, we're done.  If it's a directory, append the
236	 * standard database file name and try again.  Store the directory
237	 * name regardless so that we can use it as a base for searches.
238	 */
239	if (stat(np, &sb)) {
240		msgq(sp, M_SYSERR, "%s", np);
241		return (1);
242	}
243	if (S_ISDIR(sb.st_mode)) {
244		if ((path = join(np, CSCOPE_DBFILE)) == NULL) {
245			msgq(sp, M_SYSERR, NULL);
246			return (1);
247		}
248		if (stat(path, &sb)) {
249			msgq(sp, M_SYSERR, "%s", path);
250			free(path);
251			return (1);
252		}
253		free(path);
254		dbname = CSCOPE_DBFILE;
255	} else if ((dbname = strrchr(np, '/')) != NULL)
256		*dbname++ = '\0';
257	else {
258		dbname = np;
259		np = ".";
260	}
261
262	/* Allocate a cscope connection structure and initialize its fields. */
263	len = strlen(np);
264	CALLOC_RET(sp, csc, CSC *, 1, sizeof(CSC) + len);
265	csc->dname = csc->buf;
266	csc->dlen = len;
267	memcpy(csc->dname, np, len);
268	csc->mtim = sb.st_mtimespec;
269
270	/* Get the search paths for the cscope. */
271	if (get_paths(sp, csc))
272		goto err;
273
274	/* Start the cscope process. */
275	if (run_cscope(sp, csc, dbname))
276		goto err;
277
278	/*
279	 * Add the cscope connection to the screen's list.  From now on,
280	 * on error, we have to call terminate, which expects the csc to
281	 * be on the chain.
282	 */
283	SLIST_INSERT_HEAD(exp->cscq, csc, q);
284
285	/* Read the initial prompt from the cscope to make sure it's okay. */
286	return read_prompt(sp, csc);
287
288err:	free(csc);
289	return (1);
290}
291
292/*
293 * get_paths --
294 *	Get the directories to search for the files associated with this
295 *	cscope database.
296 */
297static int
298get_paths(SCR *sp, CSC *csc)
299{
300	struct stat sb;
301	int fd, nentries;
302	size_t len;
303	char *p, **pathp, *buf;
304
305	/*
306	 * EXTENSION #2:
307	 *
308	 * If there's a cscope directory with a file named CSCOPE_PATHS, it
309	 * contains a colon-separated list of paths in which to search for
310	 * files returned by cscope.
311	 *
312	 * XXX
313	 * These paths are absolute paths, and not relative to the cscope
314	 * directory.  To fix this, rewrite the each path using the cscope
315	 * directory as a prefix.
316	 */
317	if ((buf = join(csc->dname, CSCOPE_PATHS)) == NULL) {
318		msgq(sp, M_SYSERR, NULL);
319		return (1);
320	}
321	if (stat(buf, &sb) == 0) {
322		/* Read in the CSCOPE_PATHS file. */
323		len = sb.st_size;
324		MALLOC_RET(sp, csc->pbuf, char *, len + 1);
325		if ((fd = open(buf, O_RDONLY, 0)) < 0 ||
326		    read(fd, csc->pbuf, len) != len) {
327			 msgq_str(sp, M_SYSERR, buf, "%s");
328			 if (fd >= 0)
329				(void)close(fd);
330			 free(buf);
331			 return (1);
332		}
333		(void)close(fd);
334		free(buf);
335		csc->pbuf[len] = '\0';
336
337		/* Count up the entries. */
338		for (nentries = 0, p = csc->pbuf; *p != '\0'; ++p)
339			if (p[0] == ':' && p[1] != '\0')
340				++nentries;
341
342		/* Build an array of pointers to the paths. */
343		CALLOC_GOTO(sp,
344		    csc->paths, char **, nentries + 1, sizeof(char **));
345		for (pathp = csc->paths, p = strtok(csc->pbuf, ":");
346		    p != NULL; p = strtok(NULL, ":"))
347			*pathp++ = p;
348		return (0);
349	}
350	free(buf);
351
352	/*
353	 * If the CSCOPE_PATHS file doesn't exist, we look for files
354	 * relative to the cscope directory.
355	 */
356	if ((csc->pbuf = strdup(csc->dname)) == NULL) {
357		msgq(sp, M_SYSERR, NULL);
358		return (1);
359	}
360	CALLOC_GOTO(sp, csc->paths, char **, 2, sizeof(char *));
361	csc->paths[0] = csc->pbuf;
362	return (0);
363
364alloc_err:
365	if (csc->pbuf != NULL) {
366		free(csc->pbuf);
367		csc->pbuf = NULL;
368	}
369	return (1);
370}
371
372/*
373 * run_cscope --
374 *	Fork off the cscope process.
375 */
376static int
377run_cscope(SCR *sp, CSC *csc, char *dbname)
378{
379	int to_cs[2], from_cs[2];
380	char *cmd;
381
382	/*
383	 * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
384	 * from_cs[0] and writes to to_cs[1].
385	 */
386	to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
387	if (pipe(to_cs) < 0 || pipe(from_cs) < 0) {
388		msgq(sp, M_SYSERR, "pipe");
389		goto err;
390	}
391	switch (csc->pid = vfork()) {
392		char *dn, *dbn;
393	case -1:
394		msgq(sp, M_SYSERR, "vfork");
395err:		if (to_cs[0] != -1)
396			(void)close(to_cs[0]);
397		if (to_cs[1] != -1)
398			(void)close(to_cs[1]);
399		if (from_cs[0] != -1)
400			(void)close(from_cs[0]);
401		if (from_cs[1] != -1)
402			(void)close(from_cs[1]);
403		return (1);
404	case 0:				/* child: run cscope. */
405		(void)dup2(to_cs[0], STDIN_FILENO);
406		(void)dup2(from_cs[1], STDOUT_FILENO);
407		(void)dup2(from_cs[1], STDERR_FILENO);
408
409		/* Close unused file descriptors. */
410		(void)close(to_cs[1]);
411		(void)close(from_cs[0]);
412
413		/* Run the cscope command. */
414#define	CSCOPE_CMD_FMT		"cd %s && exec cscope -dl -f %s"
415		if ((dn = quote(csc->dname)) == NULL)
416			goto nomem;
417		if ((dbn = quote(dbname)) == NULL) {
418			free(dn);
419			goto nomem;
420		}
421		(void)asprintf(&cmd, CSCOPE_CMD_FMT, dn, dbn);
422		free(dbn);
423		free(dn);
424		if (cmd == NULL) {
425nomem:			msgq(sp, M_SYSERR, NULL);
426			_exit (1);
427		}
428		(void)execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
429		msgq_str(sp, M_SYSERR, cmd, "execl: %s");
430		free(cmd);
431		_exit (127);
432		/* NOTREACHED */
433	default:			/* parent. */
434		/* Close unused file descriptors. */
435		(void)close(to_cs[0]);
436		(void)close(from_cs[1]);
437
438		/*
439		 * Save the file descriptors for later duplication, and
440		 * reopen as streams.
441		 */
442		csc->to_fd = to_cs[1];
443		csc->to_fp = fdopen(to_cs[1], "w");
444		csc->from_fd = from_cs[0];
445		csc->from_fp = fdopen(from_cs[0], "r");
446		break;
447	}
448	return (0);
449}
450
451/*
452 * cscope_find --
453 *	The cscope find command.
454 */
455static int
456cscope_find(SCR *sp, EXCMD *cmdp, CHAR_T *pattern)
457{
458	CSC *csc, *csc_next;
459	EX_PRIVATE *exp;
460	FREF *frp;
461	TAGQ *rtqp, *tqp;
462	TAG *rtp;
463	recno_t lno;
464	size_t cno, search;
465	int force, istmp, matches;
466	char *np = NULL;
467	size_t nlen;
468
469	exp = EXP(sp);
470
471	/* Check for connections. */
472	if (SLIST_EMPTY(exp->cscq)) {
473		msgq(sp, M_ERR, "310|No cscope connections running");
474		return (1);
475	}
476
477	/*
478	 * Allocate all necessary memory before doing anything hard.  If the
479	 * tags stack is empty, we'll need the `local context' TAGQ structure
480	 * later.
481	 */
482	rtp = NULL;
483	rtqp = NULL;
484	if (TAILQ_EMPTY(exp->tq)) {
485		/* Initialize the `local context' tag queue structure. */
486		CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ));
487		TAILQ_INIT(rtqp->tagq);
488
489		/* Initialize and link in its tag structure. */
490		CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG));
491		TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q);
492		rtqp->current = rtp;
493	}
494
495	/* Create the cscope command. */
496	INT2CHAR(sp, pattern, STRLEN(pattern) + 1, np, nlen);
497	np = strdup(np);
498	if ((tqp = create_cs_cmd(sp, np, &search)) == NULL)
499		goto err;
500	if (np != NULL)
501		free(np);
502
503	/*
504	 * Stick the current context in a convenient place, we'll lose it
505	 * when we switch files.
506	 */
507	frp = sp->frp;
508	lno = sp->lno;
509	cno = sp->cno;
510	istmp = F_ISSET(sp->frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN);
511
512	/* Search all open connections for a match. */
513	matches = 0;
514	/* Copy next connect here in case csc is killed. */
515	SLIST_FOREACH_SAFE(csc, exp->cscq, q, csc_next) {
516		/*
517		 * Send the command to the cscope program.  (We skip the
518		 * first two bytes of the command, because we stored the
519		 * search cscope command character and a leading space
520		 * there.)
521		 */
522		(void)fprintf(csc->to_fp, "%lu%s\n", search, tqp->tag + 2);
523		(void)fflush(csc->to_fp);
524
525		/* Read the output. */
526		if (parse(sp, csc, tqp, &matches))
527			goto nomatch;
528	}
529
530	if (matches == 0) {
531		msgq(sp, M_INFO, "278|No matches for query");
532nomatch:	if (rtp != NULL)
533			free(rtp);
534		if (rtqp != NULL)
535			free(rtqp);
536		tagq_free(sp, tqp);
537		return (1);
538	}
539
540	/* Try to switch to the first tag. */
541	force = FL_ISSET(cmdp->iflags, E_C_FORCE);
542	if (F_ISSET(cmdp, E_NEWSCREEN)) {
543		if (ex_tag_Nswitch(sp, tqp->current, force))
544			goto err;
545
546		/* Everything else gets done in the new screen. */
547		sp = sp->nextdisp;
548		exp = EXP(sp);
549	} else
550		if (ex_tag_nswitch(sp, tqp->current, force))
551			goto err;
552
553	/*
554	 * If this is the first tag, put a `current location' queue entry
555	 * in place, so we can pop all the way back to the current mark.
556	 * Note, it doesn't point to much of anything, it's a placeholder.
557	 */
558	if (TAILQ_EMPTY(exp->tq)) {
559		TAILQ_INSERT_HEAD(exp->tq, rtqp, q);
560	} else
561		rtqp = TAILQ_FIRST(exp->tq);
562
563	/* Link the current TAGQ structure into place. */
564	TAILQ_INSERT_HEAD(exp->tq, tqp, q);
565
566	(void)cscope_search(sp, tqp, tqp->current);
567
568	/*
569	 * Move the current context from the temporary save area into the
570	 * right structure.
571	 *
572	 * If we were in a temporary file, we don't have a context to which
573	 * we can return, so just make it be the same as what we're moving
574	 * to.  It will be a little odd that ^T doesn't change anything, but
575	 * I don't think it's a big deal.
576	 */
577	if (istmp) {
578		rtqp->current->frp = sp->frp;
579		rtqp->current->lno = sp->lno;
580		rtqp->current->cno = sp->cno;
581	} else {
582		rtqp->current->frp = frp;
583		rtqp->current->lno = lno;
584		rtqp->current->cno = cno;
585	}
586
587	return (0);
588
589err:
590alloc_err:
591	if (rtqp != NULL)
592		free(rtqp);
593	if (rtp != NULL)
594		free(rtp);
595	if (np != NULL)
596		free(np);
597	return (1);
598}
599
600/*
601 * create_cs_cmd --
602 *	Build a cscope command, creating and initializing the base TAGQ.
603 */
604static TAGQ *
605create_cs_cmd(SCR *sp, char *pattern, size_t *searchp)
606{
607	CB *cbp;
608	TAGQ *tqp;
609	size_t tlen;
610	char *p;
611
612	/*
613	 * Cscope supports a "change pattern" command which we never use,
614	 * cscope command 5.  Set CSCOPE_QUERIES[5] to " " since the user
615	 * can't pass " " as the first character of pattern.  That way the
616	 * user can't ask for pattern 5 so we don't need any special-case
617	 * code.
618	 */
619#define	CSCOPE_QUERIES		"sgdct efi"
620
621	if (pattern == NULL)
622		goto usage;
623
624	/* Skip leading blanks, check for command character. */
625	for (; cmdskip(pattern[0]); ++pattern);
626	if (pattern[0] == '\0' || !cmdskip(pattern[1]))
627		goto usage;
628	for (*searchp = 0, p = CSCOPE_QUERIES;
629	    *p != '\0' && *p != pattern[0]; ++*searchp, ++p);
630	if (*p == '\0') {
631		msgq(sp, M_ERR,
632		    "311|%s: unknown search type: use one of %s",
633		    KEY_NAME(sp, pattern[0]), CSCOPE_QUERIES);
634		return (NULL);
635	}
636
637	/* Skip <blank> characters to the pattern. */
638	for (p = pattern + 1; *p != '\0' && cmdskip(*p); ++p);
639	if (*p == '\0') {
640usage:		(void)csc_help(sp, "find");
641		return (NULL);
642	}
643
644	/* The user can specify the contents of a buffer as the pattern. */
645	cbp = NULL;
646	if (p[0] == '"' && p[1] != '\0' && p[2] == '\0')
647		CBNAME(sp, cbp, p[1]);
648	if (cbp != NULL) {
649		INT2CHAR(sp, TAILQ_FIRST(cbp->textq)->lb,
650			TAILQ_FIRST(cbp->textq)->len, p, tlen);
651	} else
652		tlen = strlen(p);
653
654	/* Allocate and initialize the TAGQ structure. */
655	CALLOC(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + tlen + 3);
656	if (tqp == NULL)
657		return (NULL);
658	TAILQ_INIT(tqp->tagq);
659	tqp->tag = tqp->buf;
660	tqp->tag[0] = pattern[0];
661	tqp->tag[1] = ' ';
662	tqp->tlen = tlen + 2;
663	memcpy(tqp->tag + 2, p, tlen);
664	tqp->tag[tlen + 2] = '\0';
665	F_SET(tqp, TAG_CSCOPE);
666
667	return (tqp);
668}
669
670/*
671 * parse --
672 *	Parse the cscope output.
673 */
674static int
675parse(SCR *sp, CSC *csc, TAGQ *tqp, int *matchesp)
676{
677	TAG *tp;
678	recno_t slno = 0;
679	size_t dlen, nlen = 0, slen = 0;
680	int ch, i, isolder = 0, nlines;
681	char *dname = NULL, *name = NULL, *search, *p, *t, dummy[2], buf[2048];
682	CHAR_T *wp;
683	size_t wlen;
684
685	for (;;) {
686		if (!fgets(buf, sizeof(buf), csc->from_fp))
687			goto io_err;
688
689		/*
690		 * If the database is out of date, or there's some other
691		 * problem, cscope will output error messages before the
692		 * number-of-lines output.  Display/discard any output
693		 * that doesn't match what we want.
694		 */
695#define	CSCOPE_NLINES_FMT	"cscope: %d lines%1[\n]"
696		if (sscanf(buf, CSCOPE_NLINES_FMT, &nlines, dummy) == 2)
697			break;
698		if ((p = strchr(buf, '\n')) != NULL)
699			*p = '\0';
700		msgq(sp, M_ERR, "%s: \"%s\"", csc->dname, buf);
701	}
702
703	while (nlines--) {
704		if (fgets(buf, sizeof(buf), csc->from_fp) == NULL)
705			goto io_err;
706
707		/* If the line's too long for the buffer, discard it. */
708		if ((p = strchr(buf, '\n')) == NULL) {
709			while ((ch = getc(csc->from_fp)) != EOF && ch != '\n');
710			continue;
711		}
712		*p = '\0';
713
714		/*
715		 * The cscope output is in the following format:
716		 *
717		 *	<filename> <context> <line number> <pattern>
718		 *
719		 * Figure out how long everything is so we can allocate in one
720		 * swell foop, but discard anything that looks wrong.
721		 */
722		for (p = buf, i = 0;
723		    i < 3 && (t = strsep(&p, "\t ")) != NULL; ++i)
724			switch (i) {
725			case 0:			/* Filename. */
726				name = t;
727				nlen = strlen(name);
728				break;
729			case 1:			/* Context. */
730				break;
731			case 2:			/* Line number. */
732				slno = (recno_t)atol(t);
733				break;
734			}
735		if (i != 3 || p == NULL || t == NULL)
736			continue;
737
738		/* The rest of the string is the search pattern. */
739		search = p;
740		slen = strlen(p);
741
742		/* Resolve the file name. */
743		csc_file(sp, csc, name, &dname, &dlen, &isolder);
744
745		/*
746		 * If the file is older than the cscope database, that is,
747		 * the database was built since the file was last modified,
748		 * or there wasn't a search string, use the line number.
749		 */
750		if (isolder || strcmp(search, "<unknown>") == 0) {
751			search = NULL;
752			slen = 0;
753		}
754
755		/*
756		 * Allocate and initialize a tag structure plus the variable
757		 * length cscope information that follows it.
758		 */
759		CALLOC_RET(sp, tp,
760		    TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 +
761		    (slen + 1) * sizeof(CHAR_T));
762		tp->fname = (char *)tp->buf;
763		if (dlen == 1 && *dname == '.')
764			--dlen;
765		else if (dlen != 0) {
766			memcpy(tp->fname, dname, dlen);
767			tp->fname[dlen] = '/';
768			++dlen;
769		}
770		memcpy(tp->fname + dlen, name, nlen + 1);
771		tp->fnlen = dlen + nlen;
772		tp->slno = slno;
773		tp->search = (CHAR_T*)(tp->fname + tp->fnlen + 1);
774		CHAR2INT(sp, search, slen + 1, wp, wlen);
775		MEMCPY(tp->search, wp, (tp->slen = slen) + 1);
776		TAILQ_INSERT_TAIL(tqp->tagq, tp, q);
777
778		/* Try to preset the tag within the current file. */
779		if (sp->frp != NULL && sp->frp->name != NULL &&
780		    tqp->current == NULL && !strcmp(tp->fname, sp->frp->name))
781			tqp->current = tp;
782
783		++*matchesp;
784	}
785
786	if (tqp->current == NULL)
787		tqp->current = TAILQ_FIRST(tqp->tagq);
788
789	return read_prompt(sp, csc);
790
791io_err:	if (feof(csc->from_fp))
792		errno = EIO;
793	msgq_str(sp, M_SYSERR, "%s", csc->dname);
794	terminate(sp, csc, 0);
795	return (1);
796}
797
798/*
799 * csc_file --
800 *	Search for the right path to this file.
801 */
802static void
803csc_file(SCR *sp, CSC *csc, char *name, char **dirp, size_t *dlenp, int *isolderp)
804{
805	struct stat sb;
806	char **pp, *buf;
807
808	/*
809	 * Check for the file in all of the listed paths.  If we don't
810	 * find it, we simply return it unchanged.  We have to do this
811	 * now, even though it's expensive, because if the user changes
812	 * directories, we can't change our minds as to where the file
813	 * lives.
814	 */
815	for (pp = csc->paths; *pp != NULL; ++pp) {
816		if ((buf = join(*pp, name)) == NULL) {
817			msgq(sp, M_SYSERR, NULL);
818			*dlenp = 0;
819			return;
820		}
821		if (stat(buf, &sb) == 0) {
822			free(buf);
823			*dirp = *pp;
824			*dlenp = strlen(*pp);
825			*isolderp = timespeccmp(
826			    &sb.st_mtimespec, &csc->mtim, <);
827			return;
828		}
829		free(buf);
830	}
831	*dlenp = 0;
832}
833
834/*
835 * cscope_help --
836 *	The cscope help command.
837 */
838static int
839cscope_help(SCR *sp, EXCMD *cmdp, CHAR_T *subcmd)
840{
841	char *np;
842	size_t nlen;
843
844	INT2CHAR(sp, subcmd, STRLEN(subcmd) + 1, np, nlen);
845	return (csc_help(sp, np));
846}
847
848/*
849 * csc_help --
850 *	Display help/usage messages.
851 */
852static int
853csc_help(SCR *sp, char *cmd)
854{
855	CC const *ccp;
856
857	if (cmd != NULL && *cmd != '\0')
858		if ((ccp = lookup_ccmd(cmd)) == NULL) {
859			ex_printf(sp,
860			    "%s doesn't match any cscope command\n", cmd);
861			return (1);
862		} else {
863			ex_printf(sp,
864		          "Command: %s (%s)\n", ccp->name, ccp->help_msg);
865			ex_printf(sp, "  Usage: %s\n", ccp->usage_msg);
866			return (0);
867		}
868
869	ex_printf(sp, "cscope commands:\n");
870	for (ccp = cscope_cmds; ccp->name != NULL; ++ccp)
871		ex_printf(sp, "  %*s: %s\n", 5, ccp->name, ccp->help_msg);
872	return (0);
873}
874
875/*
876 * cscope_kill --
877 *	The cscope kill command.
878 */
879static int
880cscope_kill(SCR *sp, EXCMD *cmdp, CHAR_T *cn)
881{
882	char *np;
883	size_t nlen;
884	int n = 1;
885
886	if (*cn) {
887		INT2CHAR(sp, cn, STRLEN(cn) + 1, np, nlen);
888		n = atoi(np);
889	}
890	return (terminate(sp, NULL, n));
891}
892
893/*
894 * terminate --
895 *	Detach from a cscope process.
896 */
897static int
898terminate(SCR *sp, CSC *csc, int n)
899{
900	EX_PRIVATE *exp;
901	int i = 0, pstat;
902	CSC *cp, *pre_cp = NULL;
903
904	exp = EXP(sp);
905
906	/*
907	 * We either get a csc structure or a number.  Locate and remove
908	 * the candidate which matches the structure or the number.
909	 */
910	if (csc == NULL && n < 1)
911		goto badno;
912	SLIST_FOREACH(cp, exp->cscq, q) {
913		++i;
914		if (csc == NULL ? i != n : cp != csc) {
915			pre_cp = cp;
916			continue;
917		}
918		if (cp == SLIST_FIRST(exp->cscq))
919			SLIST_REMOVE_HEAD(exp->cscq, q);
920		else
921			SLIST_REMOVE_AFTER(pre_cp, q);
922		csc = cp;
923		break;
924	}
925	if (csc == NULL) {
926badno:		msgq(sp, M_ERR, "312|%d: no such cscope session", n);
927		return (1);
928	}
929
930	/*
931	 * XXX
932	 * Theoretically, we have the only file descriptors to the process,
933	 * so closing them should let it exit gracefully, deleting temporary
934	 * files, etc.  However, the earlier created cscope processes seems
935	 * to refuse to quit unless we send a SIGTERM signal.
936	 */
937	if (csc->from_fp != NULL)
938		(void)fclose(csc->from_fp);
939	if (csc->to_fp != NULL)
940		(void)fclose(csc->to_fp);
941	if (i > 1)
942		(void)kill(csc->pid, SIGTERM);
943	(void)waitpid(csc->pid, &pstat, 0);
944
945	/* Discard cscope connection information. */
946	if (csc->pbuf != NULL)
947		free(csc->pbuf);
948	if (csc->paths != NULL)
949		free(csc->paths);
950	free(csc);
951	return (0);
952}
953
954/*
955 * cscope_reset --
956 *	The cscope reset command.
957 */
958static int
959cscope_reset(SCR *sp, EXCMD *cmdp, CHAR_T *notusedp)
960{
961	return cscope_end(sp);
962}
963
964/*
965 * cscope_end --
966 *	End all cscope connections.
967 *
968 * PUBLIC: int cscope_end __P((SCR *));
969 */
970int
971cscope_end(SCR *sp)
972{
973	EX_PRIVATE *exp;
974
975	for (exp = EXP(sp); !SLIST_EMPTY(exp->cscq);)
976		if (terminate(sp, NULL, 1))
977			return (1);
978	return (0);
979}
980
981/*
982 * cscope_display --
983 *	Display current connections.
984 *
985 * PUBLIC: int cscope_display __P((SCR *));
986 */
987int
988cscope_display(SCR *sp)
989{
990	EX_PRIVATE *exp;
991	CSC *csc;
992	int i = 0;
993
994	exp = EXP(sp);
995	if (SLIST_EMPTY(exp->cscq)) {
996		ex_printf(sp, "No cscope connections.\n");
997		return (0);
998	}
999	SLIST_FOREACH(csc, exp->cscq, q)
1000		ex_printf(sp, "%2d %s (process %lu)\n",
1001		    ++i, csc->dname, (u_long)csc->pid);
1002	return (0);
1003}
1004
1005/*
1006 * cscope_search --
1007 *	Search a file for a cscope entry.
1008 *
1009 * PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *));
1010 */
1011int
1012cscope_search(SCR *sp, TAGQ *tqp, TAG *tp)
1013{
1014	MARK m;
1015
1016	/* If we don't have a search pattern, use the line number. */
1017	if (tp->search == NULL) {
1018		if (!db_exist(sp, tp->slno)) {
1019			tag_msg(sp, TAG_BADLNO, tqp->tag);
1020			return (1);
1021		}
1022		m.lno = tp->slno;
1023	} else {
1024		/*
1025		 * Search for the tag; cheap fallback for C functions
1026		 * if the name is the same but the arguments have changed.
1027		 */
1028		m.lno = 1;
1029		m.cno = 0;
1030		if (f_search(sp, &m, &m,
1031		    tp->search, tp->slen, NULL, SEARCH_CSCOPE | SEARCH_FILE)) {
1032			tag_msg(sp, TAG_SEARCH, tqp->tag);
1033			return (1);
1034		}
1035
1036		/*
1037		 * !!!
1038		 * Historically, tags set the search direction if it wasn't
1039		 * already set.
1040		 */
1041		if (sp->searchdir == NOTSET)
1042			sp->searchdir = FORWARD;
1043	}
1044
1045	/*
1046	 * !!!
1047	 * Tags move to the first non-blank, NOT the search pattern start.
1048	 */
1049	sp->lno = m.lno;
1050	sp->cno = 0;
1051	(void)nonblank(sp, sp->lno, &sp->cno);
1052	return (0);
1053}
1054
1055
1056/*
1057 * lookup_ccmd --
1058 *	Return a pointer to the command structure.
1059 */
1060static CC const *
1061lookup_ccmd(char *name)
1062{
1063	CC const *ccp;
1064	size_t len;
1065
1066	len = strlen(name);
1067	for (ccp = cscope_cmds; ccp->name != NULL; ++ccp)
1068		if (strncmp(name, ccp->name, len) == 0)
1069			return (ccp);
1070	return (NULL);
1071}
1072
1073/*
1074 * read_prompt --
1075 *	Read a prompt from cscope.
1076 */
1077static int
1078read_prompt(SCR *sp, CSC *csc)
1079{
1080	int ch;
1081
1082#define	CSCOPE_PROMPT		">> "
1083	for (;;) {
1084		while ((ch =
1085		    getc(csc->from_fp)) != EOF && ch != CSCOPE_PROMPT[0]);
1086		if (ch == EOF) {
1087			terminate(sp, csc, 0);
1088			return (1);
1089		}
1090		if (getc(csc->from_fp) != CSCOPE_PROMPT[1])
1091			continue;
1092		if (getc(csc->from_fp) != CSCOPE_PROMPT[2])
1093			continue;
1094		break;
1095	}
1096	return (0);
1097}
1098