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 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/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 "\ 54 find 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 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_T *)); 73 char *help_msg; 74 char *usage_msg; 75 } CC; 76 77 static 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 91 static TAGQ *create_cs_cmd __P((SCR *, char *, size_t *)); 92 static int csc_help __P((SCR *, char *)); 93 static void csc_file __P((SCR *, 94 CSC *, char *, char **, size_t *, int *)); 95 static int get_paths __P((SCR *, CSC *)); 96 static CC const *lookup_ccmd __P((char *)); 97 static int parse __P((SCR *, CSC *, TAGQ *, int *)); 98 static int read_prompt __P((SCR *, CSC *)); 99 static int run_cscope __P((SCR *, CSC *, char *)); 100 static int start_cscopes __P((SCR *, EXCMD *)); 101 static 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 */ 109 int 110 ex_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) { 144 usage: 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 */ 156 static int 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: 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 */ 196 static int 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; 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 288 err: 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 */ 297 static int 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; 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 364 alloc_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 */ 376 static int 377 run_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"); 395 err: 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) { 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. */ 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 */ 455 static int 456 cscope_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"); 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 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 589 err: 590 alloc_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 */ 604 static TAGQ * 605 create_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') { 640 usage: (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 */ 674 static int 675 parse(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 791 io_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 */ 802 static void 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; 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 */ 838 static int 839 cscope_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 */ 852 static int 853 csc_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 */ 879 static int 880 cscope_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 */ 897 static int 898 terminate(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) { 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. 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 */ 958 static int 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); !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 */ 987 int 988 cscope_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 */ 1011 int 1012 cscope_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 */ 1060 static CC const * 1061 lookup_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 */ 1077 static int 1078 read_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