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