10 |
|
#include "config.h" |
11 |
|
|
12 |
|
#ifndef lint |
13 |
< |
static const char sccsid[] = "@(#)ex_cscope.c 10.13 (Berkeley) 9/15/96"; |
13 |
> |
static 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/param.h> |
17 |
< |
#include <sys/types.h> /* XXX: param.h may not have included types.h */ |
16 |
> |
#include <sys/types.h> |
17 |
|
#include <sys/queue.h> |
18 |
|
#include <sys/stat.h> |
20 |
– |
#include <sys/time.h> |
19 |
|
#include <sys/wait.h> |
20 |
|
|
21 |
|
#include <bitstring.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> |
61 |
|
s: find all uses of name\n\ |
62 |
|
t: find assignments to name" |
63 |
|
|
64 |
< |
static int cscope_add __P((SCR *, EXCMD *, char *)); |
65 |
< |
static int cscope_find __P((SCR *, EXCMD*, char *)); |
66 |
< |
static int cscope_help __P((SCR *, EXCMD *, char *)); |
67 |
< |
static int cscope_kill __P((SCR *, EXCMD *, char *)); |
68 |
< |
static int cscope_reset __P((SCR *, EXCMD *, char *)); |
64 |
> |
static int cscope_add __P((SCR *, EXCMD *, CHAR_T *)); |
65 |
> |
static int cscope_find __P((SCR *, EXCMD*, CHAR_T *)); |
66 |
> |
static int cscope_help __P((SCR *, EXCMD *, CHAR_T *)); |
67 |
> |
static int cscope_kill __P((SCR *, EXCMD *, CHAR_T *)); |
68 |
> |
static int cscope_reset __P((SCR *, EXCMD *, CHAR_T *)); |
69 |
|
|
70 |
|
typedef struct _cc { |
71 |
|
char *name; |
72 |
< |
int (*function) __P((SCR *, EXCMD *, char *)); |
72 |
> |
int (*function) __P((SCR *, EXCMD *, CHAR_T *)); |
73 |
|
char *help_msg; |
74 |
|
char *usage_msg; |
75 |
|
} CC; |
107 |
|
* PUBLIC: int ex_cscope __P((SCR *, EXCMD *)); |
108 |
|
*/ |
109 |
|
int |
110 |
< |
ex_cscope(sp, cmdp) |
112 |
< |
SCR *sp; |
113 |
< |
EXCMD *cmdp; |
110 |
> |
ex_cscope(SCR *sp, EXCMD *cmdp) |
111 |
|
{ |
112 |
|
CC const *ccp; |
113 |
|
EX_PRIVATE *exp; |
114 |
|
int i; |
115 |
< |
char *cmd, *p; |
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); |
139 |
|
for (; *p && isspace(*p); ++p); |
140 |
|
} |
141 |
|
|
142 |
< |
if ((ccp = lookup_ccmd(cmd)) == NULL) { |
142 |
> |
INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen); |
143 |
> |
if ((ccp = lookup_ccmd(np)) == NULL) { |
144 |
|
usage: msgq(sp, M_ERR, "309|Use \"cscope help\" for help"); |
145 |
|
return (1); |
146 |
|
} |
154 |
|
* Initialize the cscope package. |
155 |
|
*/ |
156 |
|
static int |
157 |
< |
start_cscopes(sp, cmdp) |
157 |
< |
SCR *sp; |
158 |
< |
EXCMD *cmdp; |
157 |
> |
start_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: |
176 |
|
if ((cscopes = getenv("CSCOPE_DIRS")) == NULL) |
177 |
|
return (0); |
178 |
|
len = strlen(cscopes); |
179 |
< |
GET_SPACE_RET(sp, bp, blen, len); |
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 |
< |
(void)cscope_add(sp, cmdp, p); |
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); |
194 |
|
* The cscope add command. |
195 |
|
*/ |
196 |
|
static int |
197 |
< |
cscope_add(sp, cmdp, dname) |
195 |
< |
SCR *sp; |
196 |
< |
EXCMD *cmdp; |
197 |
< |
char *dname; |
197 |
> |
cscope_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[MAXPATHLEN]; |
204 |
> |
char *dbname, *path; |
205 |
> |
char *np = NULL; |
206 |
> |
size_t nlen; |
207 |
|
|
208 |
|
exp = EXP(sp); |
209 |
|
|
213 |
|
* >1 additional args: object, too many args. |
214 |
|
*/ |
215 |
|
cur_argc = cmdp->argc; |
216 |
< |
if (argv_exp2(sp, cmdp, dname, strlen(dname))) |
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); |
223 |
|
if (cmdp->argc == cur_argc + 1) |
224 |
|
dname = cmdp->argv[cur_argc]->bp; |
225 |
|
else { |
226 |
< |
ex_emsg(sp, dname, EXM_FILECOUNT); |
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 |
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(dname, &sb)) { |
240 |
< |
msgq(sp, M_SYSERR, dname); |
239 |
> |
if (stat(np, &sb)) { |
240 |
> |
msgq(sp, M_SYSERR, "%s", np); |
241 |
|
return (1); |
242 |
|
} |
243 |
|
if (S_ISDIR(sb.st_mode)) { |
244 |
< |
(void)snprintf(path, sizeof(path), |
245 |
< |
"%s/%s", dname, CSCOPE_DBFILE); |
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, path); |
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(dname, '/')) != NULL) |
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(dname); |
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, dname, len); |
268 |
< |
csc->mtime = sb.st_mtime; |
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)) |
280 |
|
* on error, we have to call terminate, which expects the csc to |
281 |
|
* be on the chain. |
282 |
|
*/ |
283 |
< |
LIST_INSERT_HEAD(&exp->cscq, csc, q); |
283 |
> |
SLIST_INSERT_HEAD(exp->cscq, csc, q); |
284 |
|
|
285 |
|
/* Read the initial prompt from the cscope to make sure it's okay. */ |
286 |
< |
if (read_prompt(sp, csc)) { |
274 |
< |
terminate(sp, csc, 0); |
275 |
< |
return (1); |
276 |
< |
} |
286 |
> |
return read_prompt(sp, csc); |
287 |
|
|
278 |
– |
return (0); |
279 |
– |
|
288 |
|
err: free(csc); |
289 |
|
return (1); |
290 |
|
} |
295 |
|
* cscope database. |
296 |
|
*/ |
297 |
|
static int |
298 |
< |
get_paths(sp, csc) |
291 |
< |
SCR *sp; |
292 |
< |
CSC *csc; |
298 |
> |
get_paths(SCR *sp, CSC *csc) |
299 |
|
{ |
300 |
|
struct stat sb; |
301 |
|
int fd, nentries; |
302 |
|
size_t len; |
303 |
< |
char *p, **pathp, buf[MAXPATHLEN * 2]; |
303 |
> |
char *p, **pathp, *buf; |
304 |
|
|
305 |
|
/* |
306 |
|
* EXTENSION #2: |
314 |
|
* directory. To fix this, rewrite the each path using the cscope |
315 |
|
* directory as a prefix. |
316 |
|
*/ |
317 |
< |
(void)snprintf(buf, sizeof(buf), "%s/%s", csc->dname, CSCOPE_PATHS); |
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; |
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. */ |
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 |
374 |
|
* Fork off the cscope process. |
375 |
|
*/ |
376 |
|
static int |
377 |
< |
run_cscope(sp, csc, dbname) |
366 |
< |
SCR *sp; |
367 |
< |
CSC *csc; |
368 |
< |
char *dbname; |
377 |
> |
run_cscope(SCR *sp, CSC *csc, char *dbname) |
378 |
|
{ |
379 |
|
int to_cs[2], from_cs[2]; |
380 |
< |
char cmd[MAXPATHLEN * 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[0] = -1; |
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"); |
395 |
|
err: if (to_cs[0] != -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 |
< |
(void)snprintf(cmd, sizeof(cmd), |
416 |
< |
CSCOPE_CMD_FMT, csc->dname, dbname); |
417 |
< |
(void)execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); |
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) { |
425 |
> |
nomem: 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. */ |
453 |
|
* The cscope find command. |
454 |
|
*/ |
455 |
|
static int |
456 |
< |
cscope_find(sp, cmdp, pattern) |
435 |
< |
SCR *sp; |
436 |
< |
EXCMD *cmdp; |
437 |
< |
char *pattern; |
456 |
> |
cscope_find(SCR *sp, EXCMD *cmdp, CHAR_T *pattern) |
457 |
|
{ |
458 |
|
CSC *csc, *csc_next; |
459 |
|
EX_PRIVATE *exp; |
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 (exp->cscq.lh_first == NULL) { |
472 |
> |
if (SLIST_EMPTY(exp->cscq)) { |
473 |
|
msgq(sp, M_ERR, "310|No cscope connections running"); |
474 |
|
return (1); |
475 |
|
} |
481 |
|
*/ |
482 |
|
rtp = NULL; |
483 |
|
rtqp = NULL; |
484 |
< |
if (exp->tq.cqh_first == (void *)&exp->tq) { |
484 |
> |
if (TAILQ_EMPTY(exp->tq)) { |
485 |
|
/* Initialize the `local context' tag queue structure. */ |
486 |
|
CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ)); |
487 |
< |
CIRCLEQ_INIT(&rtqp->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 |
< |
CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q); |
492 |
< |
rtqp->current = rtp; |
491 |
> |
TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q); |
492 |
> |
rtqp->current = rtp; |
493 |
|
} |
494 |
|
|
495 |
|
/* Create the cscope command. */ |
496 |
< |
if ((tqp = create_cs_cmd(sp, pattern, &search)) == NULL) |
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 |
511 |
|
|
512 |
|
/* Search all open connections for a match. */ |
513 |
|
matches = 0; |
514 |
< |
for (csc = exp->cscq.lh_first; csc != NULL; csc = csc_next) { |
515 |
< |
/* Copy csc->q.lh_next here in case csc is killed. */ |
491 |
< |
csc_next = csc->q.le_next; |
492 |
< |
|
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, "%d%s\n", search, tqp->tag + 2); |
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 |
< |
if (rtqp != NULL) |
505 |
< |
free(rtqp); |
506 |
< |
tagq_free(sp, tqp); |
507 |
< |
return (1); |
508 |
< |
} |
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"); |
532 |
< |
return (0); |
532 |
> |
nomatch: if (rtp != NULL) |
533 |
> |
free(rtp); |
534 |
> |
if (rtqp != NULL) |
535 |
> |
free(rtqp); |
536 |
> |
tagq_free(sp, tqp); |
537 |
> |
return (1); |
538 |
|
} |
539 |
|
|
516 |
– |
tqp->current = tqp->tagq.cqh_first; |
517 |
– |
|
540 |
|
/* Try to switch to the first tag. */ |
541 |
|
force = FL_ISSET(cmdp->iflags, E_C_FORCE); |
542 |
|
if (F_ISSET(cmdp, E_NEWSCREEN)) { |
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 (exp->tq.cqh_first == (void *)&exp->tq) { |
559 |
< |
CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q); |
558 |
> |
if (TAILQ_EMPTY(exp->tq)) { |
559 |
> |
TAILQ_INSERT_HEAD(exp->tq, rtqp, q); |
560 |
|
} else |
561 |
< |
rtqp = exp->tq.cqh_first; |
561 |
> |
rtqp = TAILQ_FIRST(exp->tq); |
562 |
|
|
563 |
|
/* Link the current TAGQ structure into place. */ |
564 |
< |
CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q); |
564 |
> |
TAILQ_INSERT_HEAD(exp->tq, tqp, q); |
565 |
|
|
566 |
|
(void)cscope_search(sp, tqp, tqp->current); |
567 |
|
|
592 |
|
free(rtqp); |
593 |
|
if (rtp != NULL) |
594 |
|
free(rtp); |
595 |
+ |
if (np != NULL) |
596 |
+ |
free(np); |
597 |
|
return (1); |
598 |
|
} |
599 |
|
|
602 |
|
* Build a cscope command, creating and initializing the base TAGQ. |
603 |
|
*/ |
604 |
|
static TAGQ * |
605 |
< |
create_cs_cmd(sp, pattern, searchp) |
582 |
< |
SCR *sp; |
583 |
< |
char *pattern; |
584 |
< |
size_t *searchp; |
605 |
> |
create_cs_cmd(SCR *sp, char *pattern, size_t *searchp) |
606 |
|
{ |
607 |
|
CB *cbp; |
608 |
|
TAGQ *tqp; |
622 |
|
goto usage; |
623 |
|
|
624 |
|
/* Skip leading blanks, check for command character. */ |
625 |
< |
for (; isblank(pattern[0]); ++pattern); |
626 |
< |
if (pattern[0] == '\0' || !isblank(pattern[1])) |
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); |
635 |
|
} |
636 |
|
|
637 |
|
/* Skip <blank> characters to the pattern. */ |
638 |
< |
for (p = pattern + 1; *p != '\0' && isblank(*p); ++p); |
638 |
> |
for (p = pattern + 1; *p != '\0' && cmdskip(*p); ++p); |
639 |
|
if (*p == '\0') { |
640 |
|
usage: (void)csc_help(sp, "find"); |
641 |
|
return (NULL); |
646 |
|
if (p[0] == '"' && p[1] != '\0' && p[2] == '\0') |
647 |
|
CBNAME(sp, cbp, p[1]); |
648 |
|
if (cbp != NULL) { |
649 |
< |
p = cbp->textq.cqh_first->lb; |
650 |
< |
tlen = cbp->textq.cqh_first->len; |
649 |
> |
INT2CHAR(sp, TAILQ_FIRST(cbp->textq)->lb, |
650 |
> |
TAILQ_FIRST(cbp->textq)->len, p, tlen); |
651 |
|
} else |
652 |
|
tlen = strlen(p); |
653 |
|
|
655 |
|
CALLOC(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + tlen + 3); |
656 |
|
if (tqp == NULL) |
657 |
|
return (NULL); |
658 |
< |
CIRCLEQ_INIT(&tqp->tagq); |
658 |
> |
TAILQ_INIT(tqp->tagq); |
659 |
|
tqp->tag = tqp->buf; |
660 |
|
tqp->tag[0] = pattern[0]; |
661 |
|
tqp->tag[1] = ' '; |
672 |
|
* Parse the cscope output. |
673 |
|
*/ |
674 |
|
static int |
675 |
< |
parse(sp, csc, tqp, matchesp) |
655 |
< |
SCR *sp; |
656 |
< |
CSC *csc; |
657 |
< |
TAGQ *tqp; |
658 |
< |
int *matchesp; |
675 |
> |
parse(SCR *sp, CSC *csc, TAGQ *tqp, int *matchesp) |
676 |
|
{ |
677 |
|
TAG *tp; |
678 |
< |
recno_t slno; |
679 |
< |
size_t dlen, nlen, slen; |
680 |
< |
int ch, i, isolder, nlines; |
681 |
< |
char *dname, *name, *search, *p, *t, dummy[2], buf[2048]; |
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)) |
757 |
|
* length cscope information that follows it. |
758 |
|
*/ |
759 |
|
CALLOC_RET(sp, tp, |
760 |
< |
TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1); |
761 |
< |
tp->fname = tp->buf; |
762 |
< |
if (dlen != 0) { |
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; |
770 |
|
memcpy(tp->fname + dlen, name, nlen + 1); |
771 |
|
tp->fnlen = dlen + nlen; |
772 |
|
tp->slno = slno; |
773 |
< |
if (slen != 0) { |
774 |
< |
tp->search = tp->fname + tp->fnlen + 1; |
775 |
< |
memcpy(tp->search, search, (tp->slen = slen) + 1); |
776 |
< |
} |
755 |
< |
CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q); |
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 |
< |
(void)read_prompt(sp, csc); |
787 |
< |
return (0); |
786 |
> |
if (tqp->current == NULL) |
787 |
> |
tqp->current = TAILQ_FIRST(tqp->tagq); |
788 |
|
|
789 |
+ |
return read_prompt(sp, csc); |
790 |
+ |
|
791 |
|
io_err: if (feof(csc->from_fp)) |
792 |
|
errno = EIO; |
793 |
|
msgq_str(sp, M_SYSERR, "%s", csc->dname); |
800 |
|
* Search for the right path to this file. |
801 |
|
*/ |
802 |
|
static void |
803 |
< |
csc_file(sp, csc, name, dirp, dlenp, isolderp) |
776 |
< |
SCR *sp; |
777 |
< |
CSC *csc; |
778 |
< |
char *name, **dirp; |
779 |
< |
size_t *dlenp; |
780 |
< |
int *isolderp; |
803 |
> |
csc_file(SCR *sp, CSC *csc, char *name, char **dirp, size_t *dlenp, int *isolderp) |
804 |
|
{ |
805 |
|
struct stat sb; |
806 |
< |
char **pp, buf[MAXPATHLEN]; |
806 |
> |
char **pp, *buf; |
807 |
|
|
808 |
|
/* |
809 |
|
* Check for the file in all of the listed paths. If we don't |
813 |
|
* lives. |
814 |
|
*/ |
815 |
|
for (pp = csc->paths; *pp != NULL; ++pp) { |
816 |
< |
(void)snprintf(buf, sizeof(buf), "%s/%s", *pp, name); |
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 = sb.st_mtime < csc->mtime; |
825 |
> |
*isolderp = timespeccmp( |
826 |
> |
&sb.st_mtimespec, &csc->mtim, <); |
827 |
|
return; |
828 |
|
} |
829 |
+ |
free(buf); |
830 |
|
} |
831 |
|
*dlenp = 0; |
832 |
|
} |
836 |
|
* The cscope help command. |
837 |
|
*/ |
838 |
|
static int |
839 |
< |
cscope_help(sp, cmdp, subcmd) |
810 |
< |
SCR *sp; |
811 |
< |
EXCMD *cmdp; |
812 |
< |
char *subcmd; |
839 |
> |
cscope_help(SCR *sp, EXCMD *cmdp, CHAR_T *subcmd) |
840 |
|
{ |
841 |
< |
return (csc_help(sp, subcmd)); |
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 |
|
/* |
850 |
|
* Display help/usage messages. |
851 |
|
*/ |
852 |
|
static int |
853 |
< |
csc_help(sp, cmd) |
823 |
< |
SCR *sp; |
824 |
< |
char *cmd; |
853 |
> |
csc_help(SCR *sp, char *cmd) |
854 |
|
{ |
855 |
|
CC const *ccp; |
856 |
|
|
877 |
|
* The cscope kill command. |
878 |
|
*/ |
879 |
|
static int |
880 |
< |
cscope_kill(sp, cmdp, cn) |
852 |
< |
SCR *sp; |
853 |
< |
EXCMD *cmdp; |
854 |
< |
char *cn; |
880 |
> |
cscope_kill(SCR *sp, EXCMD *cmdp, CHAR_T *cn) |
881 |
|
{ |
882 |
< |
return (terminate(sp, NULL, atoi(cn))); |
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 |
|
/* |
895 |
|
* Detach from a cscope process. |
896 |
|
*/ |
897 |
|
static int |
898 |
< |
terminate(sp, csc, n) |
865 |
< |
SCR *sp; |
866 |
< |
CSC *csc; |
867 |
< |
int n; |
898 |
> |
terminate(SCR *sp, CSC *csc, int n) |
899 |
|
{ |
900 |
|
EX_PRIVATE *exp; |
901 |
< |
int i, pstat; |
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. If not provided a |
908 |
< |
* csc structure, find the right one. |
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) { |
911 |
< |
if (n < 1) |
912 |
< |
goto badno; |
913 |
< |
for (i = 1, csc = exp->cscq.lh_first; |
914 |
< |
csc != NULL; csc = csc->q.le_next, i++) |
915 |
< |
if (i == n) |
916 |
< |
break; |
885 |
< |
if (csc == NULL) { |
886 |
< |
badno: msgq(sp, M_ERR, "312|%d: no such cscope session", n); |
887 |
< |
return (1); |
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) { |
926 |
+ |
badno: 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. The original vi cscope integration sent the cscope |
935 |
< |
* connection a SIGTERM signal, so I'm not sure if closing the file |
897 |
< |
* descriptors is sufficient. |
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. */ |
906 |
– |
LIST_REMOVE(csc, q); |
946 |
|
if (csc->pbuf != NULL) |
947 |
|
free(csc->pbuf); |
948 |
|
if (csc->paths != NULL) |
956 |
|
* The cscope reset command. |
957 |
|
*/ |
958 |
|
static int |
959 |
< |
cscope_reset(sp, cmdp, notusedp) |
921 |
< |
SCR *sp; |
922 |
< |
EXCMD *cmdp; |
923 |
< |
char *notusedp; |
959 |
> |
cscope_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 |
+ |
*/ |
970 |
+ |
int |
971 |
+ |
cscope_end(SCR *sp) |
972 |
+ |
{ |
973 |
|
EX_PRIVATE *exp; |
974 |
|
|
975 |
< |
for (exp = EXP(sp); exp->cscq.lh_first != NULL;) |
976 |
< |
if (cscope_kill(sp, cmdp, "1")) |
975 |
> |
for (exp = EXP(sp); !SLIST_EMPTY(exp->cscq);) |
976 |
> |
if (terminate(sp, NULL, 1)) |
977 |
|
return (1); |
978 |
|
return (0); |
979 |
|
} |
985 |
|
* PUBLIC: int cscope_display __P((SCR *)); |
986 |
|
*/ |
987 |
|
int |
988 |
< |
cscope_display(sp) |
941 |
< |
SCR *sp; |
988 |
> |
cscope_display(SCR *sp) |
989 |
|
{ |
990 |
|
EX_PRIVATE *exp; |
991 |
|
CSC *csc; |
992 |
< |
int i; |
992 |
> |
int i = 0; |
993 |
|
|
994 |
|
exp = EXP(sp); |
995 |
< |
if (exp->cscq.lh_first == NULL) { |
995 |
> |
if (SLIST_EMPTY(exp->cscq)) { |
996 |
|
ex_printf(sp, "No cscope connections.\n"); |
997 |
|
return (0); |
998 |
|
} |
999 |
< |
for (i = 1, |
1000 |
< |
csc = exp->cscq.lh_first; csc != NULL; ++i, csc = csc->q.le_next) |
1001 |
< |
ex_printf(sp, |
955 |
< |
"%2d %s (process %lu)\n", i, csc->dname, (u_long)csc->pid); |
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 |
|
|
1009 |
|
* PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *)); |
1010 |
|
*/ |
1011 |
|
int |
1012 |
< |
cscope_search(sp, tqp, tp) |
967 |
< |
SCR *sp; |
968 |
< |
TAGQ *tqp; |
969 |
< |
TAG *tp; |
1012 |
> |
cscope_search(SCR *sp, TAGQ *tqp, TAG *tp) |
1013 |
|
{ |
1014 |
|
MARK m; |
1015 |
|
|
1058 |
|
* Return a pointer to the command structure. |
1059 |
|
*/ |
1060 |
|
static CC const * |
1061 |
< |
lookup_ccmd(name) |
1019 |
< |
char *name; |
1061 |
> |
lookup_ccmd(char *name) |
1062 |
|
{ |
1063 |
|
CC const *ccp; |
1064 |
|
size_t len; |
1075 |
|
* Read a prompt from cscope. |
1076 |
|
*/ |
1077 |
|
static int |
1078 |
< |
read_prompt(sp, csc) |
1037 |
< |
SCR *sp; |
1038 |
< |
CSC *csc; |
1078 |
> |
read_prompt(SCR *sp, CSC *csc) |
1079 |
|
{ |
1080 |
|
int ch; |
1081 |
|
|