1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * CSCOPE support for Vim added by Andy Kahn <[email protected]> 4 * Ported to Win32 by Sergey Khorev <[email protected]> 5 * 6 * The basic idea/structure of cscope for Vim was borrowed from Nvi. There 7 * might be a few lines of code that look similar to what Nvi has. 8 * 9 * See README.txt for an overview of the Vim source code. 10 */ 11 12 #include "vim.h" 13 14 #if defined(FEAT_CSCOPE) || defined(PROTO) 15 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #if defined(UNIX) 19 # include <sys/wait.h> 20 #endif 21 #include "if_cscope.h" 22 23 static int cs_add(exarg_T *eap); 24 static int cs_add_common(char *, char *, char *); 25 static int cs_check_for_connections(void); 26 static int cs_check_for_tags(void); 27 static int cs_cnt_connections(void); 28 static int cs_create_connection(int i); 29 #ifdef FEAT_QUICKFIX 30 static void cs_file_results(FILE *, int *); 31 #endif 32 static void cs_fill_results(char *, int , int *, char ***, 33 char ***, int *); 34 static int cs_find(exarg_T *eap); 35 static int cs_find_common(char *opt, char *pat, int, int, int, char_u *cmdline); 36 static int cs_help(exarg_T *eap); 37 static int cs_insert_filelist(char *, char *, char *, 38 stat_T *); 39 static int cs_kill(exarg_T *eap); 40 static void cs_kill_execute(int, char *); 41 static cscmd_T * cs_lookup_cmd(exarg_T *eap); 42 static char * cs_make_vim_style_matches(char *, char *, 43 char *, char *); 44 static char * cs_manage_matches(char **, char **, int, mcmd_e); 45 static void cs_print_tags_priv(char **, char **, int); 46 static int cs_read_prompt(int); 47 static void cs_release_csp(int, int freefnpp); 48 static int cs_reset(exarg_T *eap); 49 static char * cs_resolve_file(int, char *); 50 static int cs_show(exarg_T *eap); 51 52 53 static csinfo_T * csinfo = NULL; 54 static int csinfo_size = 0; /* number of items allocated in 55 csinfo[] */ 56 57 static int eap_arg_len; /* length of eap->arg, set in 58 cs_lookup_cmd() */ 59 static cscmd_T cs_cmds[] = 60 { 61 { "add", cs_add, 62 N_("Add a new database"), "add file|dir [pre-path] [flags]", 0 }, 63 { "find", cs_find, 64 N_("Query for a pattern"), "find a|c|d|e|f|g|i|s|t name", 1 }, 65 { "help", cs_help, 66 N_("Show this message"), "help", 0 }, 67 { "kill", cs_kill, 68 N_("Kill a connection"), "kill #", 0 }, 69 { "reset", cs_reset, 70 N_("Reinit all connections"), "reset", 0 }, 71 { "show", cs_show, 72 N_("Show connections"), "show", 0 }, 73 { NULL, NULL, NULL, NULL, 0 } 74 }; 75 76 static void 77 cs_usage_msg(csid_e x) 78 { 79 (void)semsg(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage); 80 } 81 82 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 83 84 static enum 85 { 86 EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */ 87 EXP_SCSCOPE_SUBCMD, /* expand ":scscope" sub-commands */ 88 EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */ 89 EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */ 90 } expand_what; 91 92 /* 93 * Function given to ExpandGeneric() to obtain the cscope command 94 * expansion. 95 */ 96 char_u * 97 get_cscope_name(expand_T *xp UNUSED, int idx) 98 { 99 int current_idx; 100 int i; 101 102 switch (expand_what) 103 { 104 case EXP_CSCOPE_SUBCMD: 105 /* Complete with sub-commands of ":cscope": 106 * add, find, help, kill, reset, show */ 107 return (char_u *)cs_cmds[idx].name; 108 case EXP_SCSCOPE_SUBCMD: 109 /* Complete with sub-commands of ":scscope": same sub-commands as 110 * ":cscope" but skip commands which don't support split windows */ 111 for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++) 112 if (cs_cmds[i].cansplit) 113 if (current_idx++ == idx) 114 break; 115 return (char_u *)cs_cmds[i].name; 116 case EXP_CSCOPE_FIND: 117 { 118 const char *query_type[] = 119 { 120 "a", "c", "d", "e", "f", "g", "i", "s", "t", NULL 121 }; 122 123 /* Complete with query type of ":cscope find {query_type}". 124 * {query_type} can be letters (c, d, ... a) or numbers (0, 1, 125 * ..., 9) but only complete with letters, since numbers are 126 * redundant. */ 127 return (char_u *)query_type[idx]; 128 } 129 case EXP_CSCOPE_KILL: 130 { 131 static char connection[5]; 132 133 /* ":cscope kill" accepts connection numbers or partial names of 134 * the pathname of the cscope database as argument. Only complete 135 * with connection numbers. -1 can also be used to kill all 136 * connections. */ 137 for (i = 0, current_idx = 0; i < csinfo_size; i++) 138 { 139 if (csinfo[i].fname == NULL) 140 continue; 141 if (current_idx++ == idx) 142 { 143 vim_snprintf(connection, sizeof(connection), "%d", i); 144 return (char_u *)connection; 145 } 146 } 147 return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL; 148 } 149 default: 150 return NULL; 151 } 152 } 153 154 /* 155 * Handle command line completion for :cscope command. 156 */ 157 void 158 set_context_in_cscope_cmd( 159 expand_T *xp, 160 char_u *arg, 161 cmdidx_T cmdidx) 162 { 163 char_u *p; 164 165 /* Default: expand subcommands */ 166 xp->xp_context = EXPAND_CSCOPE; 167 xp->xp_pattern = arg; 168 expand_what = (cmdidx == CMD_scscope) 169 ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD; 170 171 /* (part of) subcommand already typed */ 172 if (*arg != NUL) 173 { 174 p = skiptowhite(arg); 175 if (*p != NUL) /* past first word */ 176 { 177 xp->xp_pattern = skipwhite(p); 178 if (*skiptowhite(xp->xp_pattern) != NUL) 179 xp->xp_context = EXPAND_NOTHING; 180 else if (STRNICMP(arg, "add", p - arg) == 0) 181 xp->xp_context = EXPAND_FILES; 182 else if (STRNICMP(arg, "kill", p - arg) == 0) 183 expand_what = EXP_CSCOPE_KILL; 184 else if (STRNICMP(arg, "find", p - arg) == 0) 185 expand_what = EXP_CSCOPE_FIND; 186 else 187 xp->xp_context = EXPAND_NOTHING; 188 } 189 } 190 } 191 192 #endif /* FEAT_CMDL_COMPL */ 193 194 /* 195 * Find the command, print help if invalid, and then call the corresponding 196 * command function. 197 */ 198 static void 199 do_cscope_general( 200 exarg_T *eap, 201 int make_split UNUSED) /* whether to split window */ 202 { 203 cscmd_T *cmdp; 204 205 if ((cmdp = cs_lookup_cmd(eap)) == NULL) 206 { 207 cs_help(eap); 208 return; 209 } 210 211 if (make_split) 212 { 213 if (!cmdp->cansplit) 214 { 215 (void)msg_puts(_("This cscope command does not support splitting the window.\n")); 216 return; 217 } 218 postponed_split = -1; 219 postponed_split_flags = cmdmod.split; 220 postponed_split_tab = cmdmod.tab; 221 } 222 223 cmdp->func(eap); 224 225 postponed_split_flags = 0; 226 postponed_split_tab = 0; 227 } 228 229 /* 230 * Implementation of ":cscope" and ":lcscope" 231 */ 232 void 233 ex_cscope(exarg_T *eap) 234 { 235 do_cscope_general(eap, FALSE); 236 } 237 238 /* 239 * Implementation of ":scscope". Same as ex_cscope(), but splits window, too. 240 */ 241 void 242 ex_scscope(exarg_T *eap) 243 { 244 do_cscope_general(eap, TRUE); 245 } 246 247 /* 248 * Implementation of ":cstag" 249 */ 250 void 251 ex_cstag(exarg_T *eap) 252 { 253 int ret = FALSE; 254 255 if (*eap->arg == NUL) 256 { 257 (void)emsg(_("E562: Usage: cstag <ident>")); 258 return; 259 } 260 261 switch (p_csto) 262 { 263 case 0 : 264 if (cs_check_for_connections()) 265 { 266 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE, 267 FALSE, *eap->cmdlinep); 268 if (ret == FALSE) 269 { 270 cs_free_tags(); 271 if (msg_col) 272 msg_putchar('\n'); 273 274 if (cs_check_for_tags()) 275 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); 276 } 277 } 278 else if (cs_check_for_tags()) 279 { 280 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); 281 } 282 break; 283 case 1 : 284 if (cs_check_for_tags()) 285 { 286 ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); 287 if (ret == FALSE) 288 { 289 if (msg_col) 290 msg_putchar('\n'); 291 292 if (cs_check_for_connections()) 293 { 294 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, 295 FALSE, FALSE, *eap->cmdlinep); 296 if (ret == FALSE) 297 cs_free_tags(); 298 } 299 } 300 } 301 else if (cs_check_for_connections()) 302 { 303 ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE, 304 FALSE, *eap->cmdlinep); 305 if (ret == FALSE) 306 cs_free_tags(); 307 } 308 break; 309 default : 310 break; 311 } 312 313 if (!ret) 314 { 315 (void)emsg(_("E257: cstag: tag not found")); 316 #if defined(FEAT_QUICKFIX) 317 g_do_tagpreview = 0; 318 #endif 319 } 320 321 } 322 323 324 /* 325 * This simulates a vim_fgets(), but for cscope, returns the next line 326 * from the cscope output. should only be called from find_tags() 327 * 328 * returns TRUE if eof, FALSE otherwise 329 */ 330 int 331 cs_fgets(char_u *buf, int size) 332 { 333 char *p; 334 335 if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL) 336 return TRUE; 337 vim_strncpy(buf, (char_u *)p, size - 1); 338 339 return FALSE; 340 } /* cs_fgets */ 341 342 343 /* 344 * Called only from do_tag(), when popping the tag stack. 345 */ 346 void 347 cs_free_tags(void) 348 { 349 cs_manage_matches(NULL, NULL, -1, Free); 350 } 351 352 353 /* 354 * Called from do_tag(). 355 */ 356 void 357 cs_print_tags(void) 358 { 359 cs_manage_matches(NULL, NULL, -1, Print); 360 } 361 362 363 /* 364 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function 365 * 366 * Checks for the existence of a |cscope| connection. If no 367 * parameters are specified, then the function returns: 368 * 369 * 0, if cscope was not available (not compiled in), or if there 370 * are no cscope connections; or 371 * 1, if there is at least one cscope connection. 372 * 373 * If parameters are specified, then the value of {num} 374 * determines how existence of a cscope connection is checked: 375 * 376 * {num} Description of existence check 377 * ----- ------------------------------ 378 * 0 Same as no parameters (e.g., "cscope_connection()"). 379 * 1 Ignore {prepend}, and use partial string matches for 380 * {dbpath}. 381 * 2 Ignore {prepend}, and use exact string matches for 382 * {dbpath}. 383 * 3 Use {prepend}, use partial string matches for both 384 * {dbpath} and {prepend}. 385 * 4 Use {prepend}, use exact string matches for both 386 * {dbpath} and {prepend}. 387 * 388 * Note: All string comparisons are case sensitive! 389 */ 390 #if defined(FEAT_EVAL) || defined(PROTO) 391 int 392 cs_connection(int num, char_u *dbpath, char_u *ppath) 393 { 394 int i; 395 396 if (num < 0 || num > 4 || (num > 0 && !dbpath)) 397 return FALSE; 398 399 for (i = 0; i < csinfo_size; i++) 400 { 401 if (!csinfo[i].fname) 402 continue; 403 404 if (num == 0) 405 return TRUE; 406 407 switch (num) 408 { 409 case 1: 410 if (strstr(csinfo[i].fname, (char *)dbpath)) 411 return TRUE; 412 break; 413 case 2: 414 if (strcmp(csinfo[i].fname, (char *)dbpath) == 0) 415 return TRUE; 416 break; 417 case 3: 418 if (strstr(csinfo[i].fname, (char *)dbpath) 419 && ((!ppath && !csinfo[i].ppath) 420 || (ppath 421 && csinfo[i].ppath 422 && strstr(csinfo[i].ppath, (char *)ppath)))) 423 return TRUE; 424 break; 425 case 4: 426 if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0) 427 && ((!ppath && !csinfo[i].ppath) 428 || (ppath 429 && csinfo[i].ppath 430 && (strcmp(csinfo[i].ppath, (char *)ppath) == 0)))) 431 return TRUE; 432 break; 433 } 434 } 435 436 return FALSE; 437 } /* cs_connection */ 438 #endif 439 440 441 /* 442 * PRIVATE functions 443 ****************************************************************************/ 444 445 /* 446 * Add cscope database or a directory name (to look for cscope.out) 447 * to the cscope connection list. 448 */ 449 static int 450 cs_add(exarg_T *eap UNUSED) 451 { 452 char *fname, *ppath, *flags = NULL; 453 454 if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL) 455 { 456 cs_usage_msg(Add); 457 return CSCOPE_FAILURE; 458 } 459 if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL) 460 flags = strtok((char *)NULL, (const char *)" "); 461 462 return cs_add_common(fname, ppath, flags); 463 } 464 465 static void 466 cs_stat_emsg(char *fname) 467 { 468 char *stat_emsg = _("E563: stat(%s) error: %d"); 469 char *buf = alloc(strlen(stat_emsg) + MAXPATHL + 10); 470 471 if (buf != NULL) 472 { 473 (void)sprintf(buf, stat_emsg, fname, errno); 474 (void)emsg(buf); 475 vim_free(buf); 476 } 477 else 478 (void)emsg(_("E563: stat error")); 479 } 480 481 482 /* 483 * The common routine to add a new cscope connection. Called by 484 * cs_add() and cs_reset(). I really don't like to do this, but this 485 * routine uses a number of goto statements. 486 */ 487 static int 488 cs_add_common( 489 char *arg1, /* filename - may contain environment variables */ 490 char *arg2, /* prepend path - may contain environment variables */ 491 char *flags) 492 { 493 stat_T statbuf; 494 int ret; 495 char *fname = NULL; 496 char *fname2 = NULL; 497 char *ppath = NULL; 498 int i; 499 #ifdef FEAT_MODIFY_FNAME 500 int len; 501 int usedlen = 0; 502 char_u *fbuf = NULL; 503 #endif 504 505 /* get the filename (arg1), expand it, and try to stat it */ 506 if ((fname = alloc(MAXPATHL + 1)) == NULL) 507 goto add_err; 508 509 expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL); 510 #ifdef FEAT_MODIFY_FNAME 511 len = (int)STRLEN(fname); 512 fbuf = (char_u *)fname; 513 (void)modify_fname((char_u *)":p", FALSE, &usedlen, 514 (char_u **)&fname, &fbuf, &len); 515 if (fname == NULL) 516 goto add_err; 517 fname = (char *)vim_strnsave((char_u *)fname, len); 518 vim_free(fbuf); 519 #endif 520 ret = mch_stat(fname, &statbuf); 521 if (ret < 0) 522 { 523 staterr: 524 if (p_csverbose) 525 cs_stat_emsg(fname); 526 goto add_err; 527 } 528 529 /* get the prepend path (arg2), expand it, and try to stat it */ 530 if (arg2 != NULL) 531 { 532 stat_T statbuf2; 533 534 if ((ppath = alloc(MAXPATHL + 1)) == NULL) 535 goto add_err; 536 537 expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL); 538 ret = mch_stat(ppath, &statbuf2); 539 if (ret < 0) 540 goto staterr; 541 } 542 543 /* if filename is a directory, append the cscope database name to it */ 544 if (S_ISDIR(statbuf.st_mode)) 545 { 546 fname2 = alloc(strlen(CSCOPE_DBFILE) + strlen(fname) + 2); 547 if (fname2 == NULL) 548 goto add_err; 549 550 while (fname[strlen(fname)-1] == '/' 551 #ifdef MSWIN 552 || fname[strlen(fname)-1] == '\\' 553 #endif 554 ) 555 { 556 fname[strlen(fname)-1] = '\0'; 557 if (fname[0] == '\0') 558 break; 559 } 560 if (fname[0] == '\0') 561 (void)sprintf(fname2, "/%s", CSCOPE_DBFILE); 562 else 563 (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE); 564 565 ret = mch_stat(fname2, &statbuf); 566 if (ret < 0) 567 { 568 if (p_csverbose) 569 cs_stat_emsg(fname2); 570 goto add_err; 571 } 572 573 i = cs_insert_filelist(fname2, ppath, flags, &statbuf); 574 } 575 else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) 576 { 577 i = cs_insert_filelist(fname, ppath, flags, &statbuf); 578 } 579 else 580 { 581 if (p_csverbose) 582 (void)semsg( 583 _("E564: %s is not a directory or a valid cscope database"), 584 fname); 585 goto add_err; 586 } 587 588 if (i != -1) 589 { 590 if (cs_create_connection(i) == CSCOPE_FAILURE 591 || cs_read_prompt(i) == CSCOPE_FAILURE) 592 { 593 cs_release_csp(i, TRUE); 594 goto add_err; 595 } 596 597 if (p_csverbose) 598 { 599 msg_clr_eos(); 600 (void)smsg_attr(HL_ATTR(HLF_R), 601 _("Added cscope database %s"), 602 csinfo[i].fname); 603 } 604 } 605 606 vim_free(fname); 607 vim_free(fname2); 608 vim_free(ppath); 609 return CSCOPE_SUCCESS; 610 611 add_err: 612 vim_free(fname2); 613 vim_free(fname); 614 vim_free(ppath); 615 return CSCOPE_FAILURE; 616 } /* cs_add_common */ 617 618 619 static int 620 cs_check_for_connections(void) 621 { 622 return (cs_cnt_connections() > 0); 623 } /* cs_check_for_connections */ 624 625 626 static int 627 cs_check_for_tags(void) 628 { 629 return (p_tags[0] != NUL && curbuf->b_p_tags != NULL); 630 } /* cs_check_for_tags */ 631 632 633 /* 634 * Count the number of cscope connections. 635 */ 636 static int 637 cs_cnt_connections(void) 638 { 639 short i; 640 short cnt = 0; 641 642 for (i = 0; i < csinfo_size; i++) 643 { 644 if (csinfo[i].fname != NULL) 645 cnt++; 646 } 647 return cnt; 648 } /* cs_cnt_connections */ 649 650 static void 651 cs_reading_emsg( 652 int idx) /* connection index */ 653 { 654 semsg(_("E262: error reading cscope connection %d"), idx); 655 } 656 657 #define CSREAD_BUFSIZE 2048 658 /* 659 * Count the number of matches for a given cscope connection. 660 */ 661 static int 662 cs_cnt_matches(int idx) 663 { 664 char *stok; 665 char *buf; 666 int nlines = 0; 667 668 buf = alloc(CSREAD_BUFSIZE); 669 if (buf == NULL) 670 return 0; 671 for (;;) 672 { 673 if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) 674 { 675 if (feof(csinfo[idx].fr_fp)) 676 errno = EIO; 677 678 cs_reading_emsg(idx); 679 680 vim_free(buf); 681 return -1; 682 } 683 684 /* 685 * If the database is out of date, or there's some other problem, 686 * cscope will output error messages before the number-of-lines output. 687 * Display/discard any output that doesn't match what we want. 688 * Accept "\S*cscope: X lines", also matches "mlcscope". 689 * Bail out for the "Unable to search" error. 690 */ 691 if (strstr((const char *)buf, "Unable to search database") != NULL) 692 break; 693 if ((stok = strtok(buf, (const char *)" ")) == NULL) 694 continue; 695 if (strstr((const char *)stok, "cscope:") == NULL) 696 continue; 697 698 if ((stok = strtok(NULL, (const char *)" ")) == NULL) 699 continue; 700 nlines = atoi(stok); 701 if (nlines < 0) 702 { 703 nlines = 0; 704 break; 705 } 706 707 if ((stok = strtok(NULL, (const char *)" ")) == NULL) 708 continue; 709 if (strncmp((const char *)stok, "lines", 5)) 710 continue; 711 712 break; 713 } 714 715 vim_free(buf); 716 return nlines; 717 } /* cs_cnt_matches */ 718 719 720 /* 721 * Creates the actual cscope command query from what the user entered. 722 */ 723 static char * 724 cs_create_cmd(char *csoption, char *pattern) 725 { 726 char *cmd; 727 short search; 728 char *pat; 729 730 switch (csoption[0]) 731 { 732 case '0' : case 's' : 733 search = 0; 734 break; 735 case '1' : case 'g' : 736 search = 1; 737 break; 738 case '2' : case 'd' : 739 search = 2; 740 break; 741 case '3' : case 'c' : 742 search = 3; 743 break; 744 case '4' : case 't' : 745 search = 4; 746 break; 747 case '6' : case 'e' : 748 search = 6; 749 break; 750 case '7' : case 'f' : 751 search = 7; 752 break; 753 case '8' : case 'i' : 754 search = 8; 755 break; 756 case '9' : case 'a' : 757 search = 9; 758 break; 759 default : 760 (void)emsg(_("E561: unknown cscope search type")); 761 cs_usage_msg(Find); 762 return NULL; 763 } 764 765 /* Skip white space before the patter, except for text and pattern search, 766 * they may want to use the leading white space. */ 767 pat = pattern; 768 if (search != 4 && search != 6) 769 while VIM_ISWHITE(*pat) 770 ++pat; 771 772 if ((cmd = alloc(strlen(pat) + 2)) == NULL) 773 return NULL; 774 775 (void)sprintf(cmd, "%d%s", search, pat); 776 777 return cmd; 778 } /* cs_create_cmd */ 779 780 781 /* 782 * This piece of code was taken/adapted from nvi. do we need to add 783 * the BSD license notice? 784 */ 785 static int 786 cs_create_connection(int i) 787 { 788 #ifdef UNIX 789 int to_cs[2], from_cs[2]; 790 #endif 791 int len; 792 char *prog, *cmd, *ppath = NULL; 793 #ifdef MSWIN 794 int fd; 795 SECURITY_ATTRIBUTES sa; 796 PROCESS_INFORMATION pi; 797 STARTUPINFO si; 798 BOOL pipe_stdin = FALSE, pipe_stdout = FALSE; 799 HANDLE stdin_rd, stdout_rd; 800 HANDLE stdout_wr, stdin_wr; 801 BOOL created; 802 # if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__) 803 # define OPEN_OH_ARGTYPE intptr_t 804 # else 805 # define OPEN_OH_ARGTYPE long 806 # endif 807 #endif 808 809 #if defined(UNIX) 810 /* 811 * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from 812 * from_cs[0] and writes to to_cs[1]. 813 */ 814 to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1; 815 if (pipe(to_cs) < 0 || pipe(from_cs) < 0) 816 { 817 (void)emsg(_("E566: Could not create cscope pipes")); 818 err_closing: 819 if (to_cs[0] != -1) 820 (void)close(to_cs[0]); 821 if (to_cs[1] != -1) 822 (void)close(to_cs[1]); 823 if (from_cs[0] != -1) 824 (void)close(from_cs[0]); 825 if (from_cs[1] != -1) 826 (void)close(from_cs[1]); 827 return CSCOPE_FAILURE; 828 } 829 830 switch (csinfo[i].pid = fork()) 831 { 832 case -1: 833 (void)emsg(_("E622: Could not fork for cscope")); 834 goto err_closing; 835 case 0: /* child: run cscope. */ 836 if (dup2(to_cs[0], STDIN_FILENO) == -1) 837 PERROR("cs_create_connection 1"); 838 if (dup2(from_cs[1], STDOUT_FILENO) == -1) 839 PERROR("cs_create_connection 2"); 840 if (dup2(from_cs[1], STDERR_FILENO) == -1) 841 PERROR("cs_create_connection 3"); 842 843 /* close unused */ 844 (void)close(to_cs[1]); 845 (void)close(from_cs[0]); 846 #else 847 /* MSWIN */ 848 /* Create pipes to communicate with cscope */ 849 sa.nLength = sizeof(SECURITY_ATTRIBUTES); 850 sa.bInheritHandle = TRUE; 851 sa.lpSecurityDescriptor = NULL; 852 853 if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0)) 854 || !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0))) 855 { 856 (void)emsg(_("E566: Could not create cscope pipes")); 857 err_closing: 858 if (pipe_stdin) 859 { 860 CloseHandle(stdin_rd); 861 CloseHandle(stdin_wr); 862 } 863 if (pipe_stdout) 864 { 865 CloseHandle(stdout_rd); 866 CloseHandle(stdout_wr); 867 } 868 return CSCOPE_FAILURE; 869 } 870 #endif 871 /* expand the cscope exec for env var's */ 872 if ((prog = alloc(MAXPATHL + 1)) == NULL) 873 { 874 #ifdef UNIX 875 return CSCOPE_FAILURE; 876 #else 877 /* MSWIN */ 878 goto err_closing; 879 #endif 880 } 881 expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL); 882 883 /* alloc space to hold the cscope command */ 884 len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32); 885 if (csinfo[i].ppath) 886 { 887 /* expand the prepend path for env var's */ 888 if ((ppath = alloc(MAXPATHL + 1)) == NULL) 889 { 890 vim_free(prog); 891 #ifdef UNIX 892 return CSCOPE_FAILURE; 893 #else 894 /* MSWIN */ 895 goto err_closing; 896 #endif 897 } 898 expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL); 899 900 len += (int)strlen(ppath); 901 } 902 903 if (csinfo[i].flags) 904 len += (int)strlen(csinfo[i].flags); 905 906 if ((cmd = alloc(len)) == NULL) 907 { 908 vim_free(prog); 909 vim_free(ppath); 910 #ifdef UNIX 911 return CSCOPE_FAILURE; 912 #else 913 /* MSWIN */ 914 goto err_closing; 915 #endif 916 } 917 918 /* run the cscope command; is there execl for non-unix systems? */ 919 #if defined(UNIX) 920 (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname); 921 #else 922 /* MSWIN */ 923 (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname); 924 #endif 925 if (csinfo[i].ppath != NULL) 926 { 927 (void)strcat(cmd, " -P"); 928 (void)strcat(cmd, csinfo[i].ppath); 929 } 930 if (csinfo[i].flags != NULL) 931 { 932 (void)strcat(cmd, " "); 933 (void)strcat(cmd, csinfo[i].flags); 934 } 935 # ifdef UNIX 936 /* on Win32 we still need prog */ 937 vim_free(prog); 938 # endif 939 vim_free(ppath); 940 941 #if defined(UNIX) 942 # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) 943 /* Change our process group to avoid cscope receiving SIGWINCH. */ 944 # if defined(HAVE_SETSID) 945 (void)setsid(); 946 # else 947 if (setpgid(0, 0) == -1) 948 PERROR(_("cs_create_connection setpgid failed")); 949 # endif 950 # endif 951 if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1) 952 PERROR(_("cs_create_connection exec failed")); 953 954 exit(127); 955 /* NOTREACHED */ 956 default: /* parent. */ 957 /* 958 * Save the file descriptors for later duplication, and 959 * reopen as streams. 960 */ 961 if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL) 962 PERROR(_("cs_create_connection: fdopen for to_fp failed")); 963 if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL) 964 PERROR(_("cs_create_connection: fdopen for fr_fp failed")); 965 966 /* close unused */ 967 (void)close(to_cs[0]); 968 (void)close(from_cs[1]); 969 970 break; 971 } 972 973 #else 974 /* MSWIN */ 975 /* Create a new process to run cscope and use pipes to talk with it */ 976 GetStartupInfo(&si); 977 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 978 si.wShowWindow = SW_HIDE; /* Hide child application window */ 979 si.hStdOutput = stdout_wr; 980 si.hStdError = stdout_wr; 981 si.hStdInput = stdin_rd; 982 created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, 983 NULL, NULL, &si, &pi); 984 vim_free(prog); 985 vim_free(cmd); 986 987 if (!created) 988 { 989 PERROR(_("cs_create_connection exec failed")); 990 (void)emsg(_("E623: Could not spawn cscope process")); 991 goto err_closing; 992 } 993 /* else */ 994 csinfo[i].pid = pi.dwProcessId; 995 csinfo[i].hProc = pi.hProcess; 996 CloseHandle(pi.hThread); 997 998 /* TODO - tidy up after failure to create files on pipe handles. */ 999 if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr, 1000 _O_TEXT|_O_APPEND)) < 0) 1001 || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL)) 1002 PERROR(_("cs_create_connection: fdopen for to_fp failed")); 1003 if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd, 1004 _O_TEXT|_O_RDONLY)) < 0) 1005 || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL)) 1006 PERROR(_("cs_create_connection: fdopen for fr_fp failed")); 1007 1008 /* Close handles for file descriptors inherited by the cscope process */ 1009 CloseHandle(stdin_rd); 1010 CloseHandle(stdout_wr); 1011 1012 #endif /* !UNIX */ 1013 1014 return CSCOPE_SUCCESS; 1015 } /* cs_create_connection */ 1016 1017 1018 /* 1019 * Query cscope using command line interface. Parse the output and use tselect 1020 * to allow choices. Like Nvi, creates a pipe to send to/from query/cscope. 1021 * 1022 * returns TRUE if we jump to a tag or abort, FALSE if not. 1023 */ 1024 static int 1025 cs_find(exarg_T *eap) 1026 { 1027 char *opt, *pat; 1028 int i; 1029 1030 if (cs_check_for_connections() == FALSE) 1031 { 1032 (void)emsg(_("E567: no cscope connections")); 1033 return FALSE; 1034 } 1035 1036 if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL) 1037 { 1038 cs_usage_msg(Find); 1039 return FALSE; 1040 } 1041 1042 pat = opt + strlen(opt) + 1; 1043 if (pat >= (char *)eap->arg + eap_arg_len) 1044 { 1045 cs_usage_msg(Find); 1046 return FALSE; 1047 } 1048 1049 /* 1050 * Let's replace the NULs written by strtok() with spaces - we need the 1051 * spaces to correctly display the quickfix/location list window's title. 1052 */ 1053 for (i = 0; i < eap_arg_len; ++i) 1054 if (NUL == eap->arg[i]) 1055 eap->arg[i] = ' '; 1056 1057 return cs_find_common(opt, pat, eap->forceit, TRUE, 1058 eap->cmdidx == CMD_lcscope, *eap->cmdlinep); 1059 } /* cs_find */ 1060 1061 1062 /* 1063 * Common code for cscope find, shared by cs_find() and ex_cstag(). 1064 */ 1065 static int 1066 cs_find_common( 1067 char *opt, 1068 char *pat, 1069 int forceit, 1070 int verbose, 1071 int use_ll UNUSED, 1072 char_u *cmdline UNUSED) 1073 { 1074 int i; 1075 char *cmd; 1076 int *nummatches; 1077 int totmatches; 1078 #ifdef FEAT_QUICKFIX 1079 char cmdletter; 1080 char *qfpos; 1081 1082 /* get cmd letter */ 1083 switch (opt[0]) 1084 { 1085 case '0' : 1086 cmdletter = 's'; 1087 break; 1088 case '1' : 1089 cmdletter = 'g'; 1090 break; 1091 case '2' : 1092 cmdletter = 'd'; 1093 break; 1094 case '3' : 1095 cmdletter = 'c'; 1096 break; 1097 case '4' : 1098 cmdletter = 't'; 1099 break; 1100 case '6' : 1101 cmdletter = 'e'; 1102 break; 1103 case '7' : 1104 cmdletter = 'f'; 1105 break; 1106 case '8' : 1107 cmdletter = 'i'; 1108 break; 1109 case '9' : 1110 cmdletter = 'a'; 1111 break; 1112 default : 1113 cmdletter = opt[0]; 1114 } 1115 1116 qfpos = (char *)vim_strchr(p_csqf, cmdletter); 1117 if (qfpos != NULL) 1118 { 1119 qfpos++; 1120 /* next symbol must be + or - */ 1121 if (strchr(CSQF_FLAGS, *qfpos) == NULL) 1122 { 1123 char *nf = _("E469: invalid cscopequickfix flag %c for %c"); 1124 char *buf = alloc(strlen(nf)); 1125 1126 /* strlen will be enough because we use chars */ 1127 if (buf != NULL) 1128 { 1129 sprintf(buf, nf, *qfpos, *(qfpos-1)); 1130 (void)emsg(buf); 1131 vim_free(buf); 1132 } 1133 return FALSE; 1134 } 1135 1136 if (*qfpos != '0' 1137 && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)"cscope", 1138 curbuf->b_fname, TRUE, curbuf)) 1139 { 1140 # ifdef FEAT_EVAL 1141 if (aborting()) 1142 return FALSE; 1143 # endif 1144 } 1145 } 1146 #endif 1147 1148 /* create the actual command to send to cscope */ 1149 cmd = cs_create_cmd(opt, pat); 1150 if (cmd == NULL) 1151 return FALSE; 1152 1153 nummatches = ALLOC_MULT(int, csinfo_size); 1154 if (nummatches == NULL) 1155 { 1156 vim_free(cmd); 1157 return FALSE; 1158 } 1159 1160 /* Send query to all open connections, then count the total number 1161 * of matches so we can alloc all in one swell foop. */ 1162 for (i = 0; i < csinfo_size; i++) 1163 nummatches[i] = 0; 1164 totmatches = 0; 1165 for (i = 0; i < csinfo_size; i++) 1166 { 1167 if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL) 1168 continue; 1169 1170 /* send cmd to cscope */ 1171 (void)fprintf(csinfo[i].to_fp, "%s\n", cmd); 1172 (void)fflush(csinfo[i].to_fp); 1173 1174 nummatches[i] = cs_cnt_matches(i); 1175 1176 if (nummatches[i] > -1) 1177 totmatches += nummatches[i]; 1178 1179 if (nummatches[i] == 0) 1180 (void)cs_read_prompt(i); 1181 } 1182 vim_free(cmd); 1183 1184 if (totmatches == 0) 1185 { 1186 char *nf = _("E259: no matches found for cscope query %s of %s"); 1187 char *buf; 1188 1189 if (!verbose) 1190 { 1191 vim_free(nummatches); 1192 return FALSE; 1193 } 1194 1195 buf = alloc(strlen(opt) + strlen(pat) + strlen(nf)); 1196 if (buf == NULL) 1197 (void)emsg(nf); 1198 else 1199 { 1200 sprintf(buf, nf, opt, pat); 1201 (void)emsg(buf); 1202 vim_free(buf); 1203 } 1204 vim_free(nummatches); 1205 return FALSE; 1206 } 1207 1208 #ifdef FEAT_QUICKFIX 1209 if (qfpos != NULL && *qfpos != '0' && totmatches > 0) 1210 { 1211 /* fill error list */ 1212 FILE *f; 1213 char_u *tmp = vim_tempname('c', TRUE); 1214 qf_info_T *qi = NULL; 1215 win_T *wp = NULL; 1216 1217 f = mch_fopen((char *)tmp, "w"); 1218 if (f == NULL) 1219 semsg(_(e_notopen), tmp); 1220 else 1221 { 1222 cs_file_results(f, nummatches); 1223 fclose(f); 1224 if (use_ll) /* Use location list */ 1225 wp = curwin; 1226 /* '-' starts a new error list */ 1227 if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m", 1228 *qfpos == '-', cmdline, NULL) > 0) 1229 { 1230 if (postponed_split != 0) 1231 { 1232 (void)win_split(postponed_split > 0 ? postponed_split : 0, 1233 postponed_split_flags); 1234 RESET_BINDING(curwin); 1235 postponed_split = 0; 1236 } 1237 1238 apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope", 1239 curbuf->b_fname, TRUE, curbuf); 1240 if (use_ll) 1241 /* 1242 * In the location list window, use the displayed location 1243 * list. Otherwise, use the location list for the window. 1244 */ 1245 qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) 1246 ? wp->w_llist_ref : wp->w_llist; 1247 qf_jump(qi, 0, 0, forceit); 1248 } 1249 } 1250 mch_remove(tmp); 1251 vim_free(tmp); 1252 vim_free(nummatches); 1253 return TRUE; 1254 } 1255 else 1256 #endif /* FEAT_QUICKFIX */ 1257 { 1258 char **matches = NULL, **contexts = NULL; 1259 int matched = 0; 1260 1261 /* read output */ 1262 cs_fill_results((char *)pat, totmatches, nummatches, &matches, 1263 &contexts, &matched); 1264 vim_free(nummatches); 1265 if (matches == NULL) 1266 return FALSE; 1267 1268 (void)cs_manage_matches(matches, contexts, matched, Store); 1269 1270 return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose); 1271 } 1272 1273 } /* cs_find_common */ 1274 1275 /* 1276 * Print help. 1277 */ 1278 static int 1279 cs_help(exarg_T *eap UNUSED) 1280 { 1281 cscmd_T *cmdp = cs_cmds; 1282 1283 (void)msg_puts(_("cscope commands:\n")); 1284 while (cmdp->name != NULL) 1285 { 1286 char *help = _(cmdp->help); 1287 int space_cnt = 30 - vim_strsize((char_u *)help); 1288 1289 /* Use %*s rather than %30s to ensure proper alignment in utf-8 */ 1290 if (space_cnt < 0) 1291 space_cnt = 0; 1292 (void)smsg(_("%-5s: %s%*s (Usage: %s)"), 1293 cmdp->name, 1294 help, space_cnt, " ", 1295 cmdp->usage); 1296 if (strcmp(cmdp->name, "find") == 0) 1297 msg_puts(_("\n" 1298 " a: Find assignments to this symbol\n" 1299 " c: Find functions calling this function\n" 1300 " d: Find functions called by this function\n" 1301 " e: Find this egrep pattern\n" 1302 " f: Find this file\n" 1303 " g: Find this definition\n" 1304 " i: Find files #including this file\n" 1305 " s: Find this C symbol\n" 1306 " t: Find this text string\n")); 1307 1308 cmdp++; 1309 } 1310 1311 wait_return(TRUE); 1312 return 0; 1313 } /* cs_help */ 1314 1315 1316 static void 1317 clear_csinfo(int i) 1318 { 1319 csinfo[i].fname = NULL; 1320 csinfo[i].ppath = NULL; 1321 csinfo[i].flags = NULL; 1322 #if defined(UNIX) 1323 csinfo[i].st_dev = (dev_t)0; 1324 csinfo[i].st_ino = (ino_t)0; 1325 #else 1326 csinfo[i].nVolume = 0; 1327 csinfo[i].nIndexHigh = 0; 1328 csinfo[i].nIndexLow = 0; 1329 #endif 1330 csinfo[i].pid = 0; 1331 csinfo[i].fr_fp = NULL; 1332 csinfo[i].to_fp = NULL; 1333 #if defined(MSWIN) 1334 csinfo[i].hProc = NULL; 1335 #endif 1336 } 1337 1338 #ifndef UNIX 1339 static char * 1340 GetWin32Error(void) 1341 { 1342 char *msg = NULL; 1343 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 1344 NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL); 1345 if (msg != NULL) 1346 { 1347 /* remove trailing \r\n */ 1348 char *pcrlf = strstr(msg, "\r\n"); 1349 if (pcrlf != NULL) 1350 *pcrlf = '\0'; 1351 } 1352 return msg; 1353 } 1354 #endif 1355 1356 /* 1357 * Insert a new cscope database filename into the filelist. 1358 */ 1359 static int 1360 cs_insert_filelist( 1361 char *fname, 1362 char *ppath, 1363 char *flags, 1364 stat_T *sb UNUSED) 1365 { 1366 short i, j; 1367 #ifndef UNIX 1368 BY_HANDLE_FILE_INFORMATION bhfi; 1369 1370 switch (win32_fileinfo((char_u *)fname, &bhfi)) 1371 { 1372 case FILEINFO_ENC_FAIL: /* enc_to_utf16() failed */ 1373 case FILEINFO_READ_FAIL: /* CreateFile() failed */ 1374 if (p_csverbose) 1375 { 1376 char *cant_msg = _("E625: cannot open cscope database: %s"); 1377 char *winmsg = GetWin32Error(); 1378 1379 if (winmsg != NULL) 1380 { 1381 (void)semsg(cant_msg, winmsg); 1382 LocalFree(winmsg); 1383 } 1384 else 1385 /* subst filename if can't get error text */ 1386 (void)semsg(cant_msg, fname); 1387 } 1388 return -1; 1389 1390 case FILEINFO_INFO_FAIL: /* GetFileInformationByHandle() failed */ 1391 if (p_csverbose) 1392 (void)emsg(_("E626: cannot get cscope database information")); 1393 return -1; 1394 } 1395 #endif 1396 1397 i = -1; /* can be set to the index of an empty item in csinfo */ 1398 for (j = 0; j < csinfo_size; j++) 1399 { 1400 if (csinfo[j].fname != NULL 1401 #if defined(UNIX) 1402 && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino 1403 #else 1404 // compare pathnames first 1405 && ((fullpathcmp((char_u *)csinfo[j].fname, 1406 (char_u *)fname, FALSE, TRUE) & FPC_SAME) 1407 // test index file attributes too 1408 || (csinfo[j].nVolume == bhfi.dwVolumeSerialNumber 1409 && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh 1410 && csinfo[j].nIndexLow == bhfi.nFileIndexLow)) 1411 #endif 1412 ) 1413 { 1414 if (p_csverbose) 1415 (void)emsg(_("E568: duplicate cscope database not added")); 1416 return -1; 1417 } 1418 1419 if (csinfo[j].fname == NULL && i == -1) 1420 i = j; /* remember first empty entry */ 1421 } 1422 1423 if (i == -1) 1424 { 1425 i = csinfo_size; 1426 if (csinfo_size == 0) 1427 { 1428 /* First time allocation: allocate only 1 connection. It should 1429 * be enough for most users. If more is needed, csinfo will be 1430 * reallocated. */ 1431 csinfo_size = 1; 1432 csinfo = ALLOC_CLEAR_ONE(csinfo_T); 1433 } 1434 else 1435 { 1436 csinfo_T *t_csinfo = csinfo; 1437 1438 /* Reallocate space for more connections. */ 1439 csinfo_size *= 2; 1440 csinfo = vim_realloc(csinfo, sizeof(csinfo_T)*csinfo_size); 1441 if (csinfo == NULL) 1442 { 1443 vim_free(t_csinfo); 1444 csinfo_size = 0; 1445 } 1446 } 1447 if (csinfo == NULL) 1448 return -1; 1449 for (j = csinfo_size/2; j < csinfo_size; j++) 1450 clear_csinfo(j); 1451 } 1452 1453 if ((csinfo[i].fname = alloc(strlen(fname)+1)) == NULL) 1454 return -1; 1455 1456 (void)strcpy(csinfo[i].fname, (const char *)fname); 1457 1458 if (ppath != NULL) 1459 { 1460 if ((csinfo[i].ppath = alloc(strlen(ppath) + 1)) == NULL) 1461 { 1462 VIM_CLEAR(csinfo[i].fname); 1463 return -1; 1464 } 1465 (void)strcpy(csinfo[i].ppath, (const char *)ppath); 1466 } else 1467 csinfo[i].ppath = NULL; 1468 1469 if (flags != NULL) 1470 { 1471 if ((csinfo[i].flags = alloc(strlen(flags) + 1)) == NULL) 1472 { 1473 VIM_CLEAR(csinfo[i].fname); 1474 VIM_CLEAR(csinfo[i].ppath); 1475 return -1; 1476 } 1477 (void)strcpy(csinfo[i].flags, (const char *)flags); 1478 } else 1479 csinfo[i].flags = NULL; 1480 1481 #if defined(UNIX) 1482 csinfo[i].st_dev = sb->st_dev; 1483 csinfo[i].st_ino = sb->st_ino; 1484 1485 #else 1486 csinfo[i].nVolume = bhfi.dwVolumeSerialNumber; 1487 csinfo[i].nIndexLow = bhfi.nFileIndexLow; 1488 csinfo[i].nIndexHigh = bhfi.nFileIndexHigh; 1489 #endif 1490 return i; 1491 } /* cs_insert_filelist */ 1492 1493 1494 /* 1495 * Find cscope command in command table. 1496 */ 1497 static cscmd_T * 1498 cs_lookup_cmd(exarg_T *eap) 1499 { 1500 cscmd_T *cmdp; 1501 char *stok; 1502 size_t len; 1503 1504 if (eap->arg == NULL) 1505 return NULL; 1506 1507 /* Store length of eap->arg before it gets modified by strtok(). */ 1508 eap_arg_len = (int)STRLEN(eap->arg); 1509 1510 if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) 1511 return NULL; 1512 1513 len = strlen(stok); 1514 for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp) 1515 { 1516 if (strncmp((const char *)(stok), cmdp->name, len) == 0) 1517 return (cmdp); 1518 } 1519 return NULL; 1520 } /* cs_lookup_cmd */ 1521 1522 1523 /* 1524 * Nuke em. 1525 */ 1526 static int 1527 cs_kill(exarg_T *eap UNUSED) 1528 { 1529 char *stok; 1530 short i; 1531 1532 if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL) 1533 { 1534 cs_usage_msg(Kill); 1535 return CSCOPE_FAILURE; 1536 } 1537 1538 /* only single digit positive and negative integers are allowed */ 1539 if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0]))) 1540 || (strlen(stok) < 3 && stok[0] == '-' 1541 && VIM_ISDIGIT((int)(stok[1])))) 1542 i = atoi(stok); 1543 else 1544 { 1545 /* It must be part of a name. We will try to find a match 1546 * within all the names in the csinfo data structure 1547 */ 1548 for (i = 0; i < csinfo_size; i++) 1549 { 1550 if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok)) 1551 break; 1552 } 1553 } 1554 1555 if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL)) 1556 { 1557 if (p_csverbose) 1558 (void)semsg(_("E261: cscope connection %s not found"), stok); 1559 } 1560 else 1561 { 1562 if (i == -1) 1563 { 1564 for (i = 0; i < csinfo_size; i++) 1565 { 1566 if (csinfo[i].fname) 1567 cs_kill_execute(i, csinfo[i].fname); 1568 } 1569 } 1570 else 1571 cs_kill_execute(i, stok); 1572 } 1573 1574 return 0; 1575 } /* cs_kill */ 1576 1577 1578 /* 1579 * Actually kills a specific cscope connection. 1580 */ 1581 static void 1582 cs_kill_execute( 1583 int i, /* cscope table index */ 1584 char *cname) /* cscope database name */ 1585 { 1586 if (p_csverbose) 1587 { 1588 msg_clr_eos(); 1589 (void)smsg_attr(HL_ATTR(HLF_R) | MSG_HIST, 1590 _("cscope connection %s closed"), cname); 1591 } 1592 cs_release_csp(i, TRUE); 1593 } 1594 1595 1596 /* 1597 * Convert the cscope output into a ctags style entry (as might be found 1598 * in a ctags tags file). there's one catch though: cscope doesn't tell you 1599 * the type of the tag you are looking for. for example, in Darren Hiebert's 1600 * ctags (the one that comes with vim), #define's use a line number to find the 1601 * tag in a file while function definitions use a regexp search pattern. 1602 * 1603 * I'm going to always use the line number because cscope does something 1604 * quirky (and probably other things i don't know about): 1605 * 1606 * if you have "# define" in your source file, which is 1607 * perfectly legal, cscope thinks you have "#define". this 1608 * will result in a failed regexp search. :( 1609 * 1610 * Besides, even if this particular case didn't happen, the search pattern 1611 * would still have to be modified to escape all the special regular expression 1612 * characters to comply with ctags formatting. 1613 */ 1614 static char * 1615 cs_make_vim_style_matches( 1616 char *fname, 1617 char *slno, 1618 char *search, 1619 char *tagstr) 1620 { 1621 /* vim style is ctags: 1622 * 1623 * <tagstr>\t<filename>\t<linenum_or_search>"\t<extra> 1624 * 1625 * but as mentioned above, we'll always use the line number and 1626 * put the search pattern (if one exists) as "extra" 1627 * 1628 * buf is used as part of vim's method of handling tags, and 1629 * (i think) vim frees it when you pop your tags and get replaced 1630 * by new ones on the tag stack. 1631 */ 1632 char *buf; 1633 int amt; 1634 1635 if (search != NULL) 1636 { 1637 amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6); 1638 if ((buf = alloc(amt)) == NULL) 1639 return NULL; 1640 1641 (void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search); 1642 } 1643 else 1644 { 1645 amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + 5); 1646 if ((buf = alloc(amt)) == NULL) 1647 return NULL; 1648 1649 (void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno); 1650 } 1651 1652 return buf; 1653 } /* cs_make_vim_style_matches */ 1654 1655 1656 /* 1657 * This is kind of hokey, but i don't see an easy way round this. 1658 * 1659 * Store: keep a ptr to the (malloc'd) memory of matches originally 1660 * generated from cs_find(). the matches are originally lines directly 1661 * from cscope output, but transformed to look like something out of a 1662 * ctags. see cs_make_vim_style_matches for more details. 1663 * 1664 * Get: used only from cs_fgets(), this simulates a vim_fgets() to return 1665 * the next line from the cscope output. it basically keeps track of which 1666 * lines have been "used" and returns the next one. 1667 * 1668 * Free: frees up everything and resets 1669 * 1670 * Print: prints the tags 1671 */ 1672 static char * 1673 cs_manage_matches( 1674 char **matches, 1675 char **contexts, 1676 int totmatches, 1677 mcmd_e cmd) 1678 { 1679 static char **mp = NULL; 1680 static char **cp = NULL; 1681 static int cnt = -1; 1682 static int next = -1; 1683 char *p = NULL; 1684 1685 switch (cmd) 1686 { 1687 case Store: 1688 assert(matches != NULL); 1689 assert(totmatches > 0); 1690 if (mp != NULL || cp != NULL) 1691 (void)cs_manage_matches(NULL, NULL, -1, Free); 1692 mp = matches; 1693 cp = contexts; 1694 cnt = totmatches; 1695 next = 0; 1696 break; 1697 case Get: 1698 if (next >= cnt) 1699 return NULL; 1700 1701 p = mp[next]; 1702 next++; 1703 break; 1704 case Free: 1705 if (mp != NULL) 1706 { 1707 if (cnt > 0) 1708 while (cnt--) 1709 { 1710 vim_free(mp[cnt]); 1711 if (cp != NULL) 1712 vim_free(cp[cnt]); 1713 } 1714 vim_free(mp); 1715 vim_free(cp); 1716 } 1717 mp = NULL; 1718 cp = NULL; 1719 cnt = 0; 1720 next = 0; 1721 break; 1722 case Print: 1723 cs_print_tags_priv(mp, cp, cnt); 1724 break; 1725 default: /* should not reach here */ 1726 iemsg(_("E570: fatal error in cs_manage_matches")); 1727 return NULL; 1728 } 1729 1730 return p; 1731 } /* cs_manage_matches */ 1732 1733 1734 /* 1735 * Parse cscope output. 1736 */ 1737 static char * 1738 cs_parse_results( 1739 int cnumber, 1740 char *buf, 1741 int bufsize, 1742 char **context, 1743 char **linenumber, 1744 char **search) 1745 { 1746 int ch; 1747 char *p; 1748 char *name; 1749 1750 if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL) 1751 { 1752 if (feof(csinfo[cnumber].fr_fp)) 1753 errno = EIO; 1754 1755 cs_reading_emsg(cnumber); 1756 1757 return NULL; 1758 } 1759 1760 /* If the line's too long for the buffer, discard it. */ 1761 if ((p = strchr(buf, '\n')) == NULL) 1762 { 1763 while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n') 1764 ; 1765 return NULL; 1766 } 1767 *p = '\0'; 1768 1769 /* 1770 * cscope output is in the following format: 1771 * 1772 * <filename> <context> <line number> <pattern> 1773 */ 1774 if ((name = strtok((char *)buf, (const char *)" ")) == NULL) 1775 return NULL; 1776 if ((*context = strtok(NULL, (const char *)" ")) == NULL) 1777 return NULL; 1778 if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL) 1779 return NULL; 1780 *search = *linenumber + strlen(*linenumber) + 1; /* +1 to skip \0 */ 1781 1782 /* --- nvi --- 1783 * If the file is older than the cscope database, that is, 1784 * the database was built since the file was last modified, 1785 * or there wasn't a search string, use the line number. 1786 */ 1787 if (strcmp(*search, "<unknown>") == 0) 1788 *search = NULL; 1789 1790 name = cs_resolve_file(cnumber, name); 1791 return name; 1792 } 1793 1794 #ifdef FEAT_QUICKFIX 1795 /* 1796 * Write cscope find results to file. 1797 */ 1798 static void 1799 cs_file_results(FILE *f, int *nummatches_a) 1800 { 1801 int i, j; 1802 char *buf; 1803 char *search, *slno; 1804 char *fullname; 1805 char *cntx; 1806 char *context; 1807 1808 buf = alloc(CSREAD_BUFSIZE); 1809 if (buf == NULL) 1810 return; 1811 1812 for (i = 0; i < csinfo_size; i++) 1813 { 1814 if (nummatches_a[i] < 1) 1815 continue; 1816 1817 for (j = 0; j < nummatches_a[i]; j++) 1818 { 1819 if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx, 1820 &slno, &search)) == NULL) 1821 continue; 1822 1823 context = alloc(strlen(cntx)+5); 1824 if (context == NULL) 1825 continue; 1826 1827 if (strcmp(cntx, "<global>")==0) 1828 strcpy(context, "<<global>>"); 1829 else 1830 sprintf(context, "<<%s>>", cntx); 1831 1832 if (search == NULL) 1833 fprintf(f, "%s\t%s\t%s\n", fullname, slno, context); 1834 else 1835 fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search); 1836 1837 vim_free(context); 1838 vim_free(fullname); 1839 } /* for all matches */ 1840 1841 (void)cs_read_prompt(i); 1842 1843 } /* for all cscope connections */ 1844 vim_free(buf); 1845 } 1846 #endif 1847 1848 /* 1849 * Get parsed cscope output and calls cs_make_vim_style_matches to convert 1850 * into ctags format. 1851 * When there are no matches sets "*matches_p" to NULL. 1852 */ 1853 static void 1854 cs_fill_results( 1855 char *tagstr, 1856 int totmatches, 1857 int *nummatches_a, 1858 char ***matches_p, 1859 char ***cntxts_p, 1860 int *matched) 1861 { 1862 int i, j; 1863 char *buf; 1864 char *search, *slno; 1865 int totsofar = 0; 1866 char **matches = NULL; 1867 char **cntxts = NULL; 1868 char *fullname; 1869 char *cntx; 1870 1871 assert(totmatches > 0); 1872 1873 buf = alloc(CSREAD_BUFSIZE); 1874 if (buf == NULL) 1875 return; 1876 1877 if ((matches = ALLOC_MULT(char *, totmatches)) == NULL) 1878 goto parse_out; 1879 if ((cntxts = ALLOC_MULT(char *, totmatches)) == NULL) 1880 goto parse_out; 1881 1882 for (i = 0; i < csinfo_size; i++) 1883 { 1884 if (nummatches_a[i] < 1) 1885 continue; 1886 1887 for (j = 0; j < nummatches_a[i]; j++) 1888 { 1889 if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx, 1890 &slno, &search)) == NULL) 1891 continue; 1892 1893 matches[totsofar] = cs_make_vim_style_matches(fullname, slno, 1894 search, tagstr); 1895 1896 vim_free(fullname); 1897 1898 if (strcmp(cntx, "<global>") == 0) 1899 cntxts[totsofar] = NULL; 1900 else 1901 /* note: if vim_strsave returns NULL, then the context 1902 * will be "<global>", which is misleading. 1903 */ 1904 cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx); 1905 1906 if (matches[totsofar] != NULL) 1907 totsofar++; 1908 1909 } /* for all matches */ 1910 1911 (void)cs_read_prompt(i); 1912 1913 } /* for all cscope connections */ 1914 1915 parse_out: 1916 if (totsofar == 0) 1917 { 1918 /* No matches, free the arrays and return NULL in "*matches_p". */ 1919 VIM_CLEAR(matches); 1920 VIM_CLEAR(cntxts); 1921 } 1922 *matched = totsofar; 1923 *matches_p = matches; 1924 *cntxts_p = cntxts; 1925 1926 vim_free(buf); 1927 } /* cs_fill_results */ 1928 1929 1930 /* get the requested path components */ 1931 static char * 1932 cs_pathcomponents(char *path) 1933 { 1934 int i; 1935 char *s; 1936 1937 if (p_cspc == 0) 1938 return path; 1939 1940 s = path + strlen(path) - 1; 1941 for (i = 0; i < p_cspc; ++i) 1942 while (s > path && *--s != '/' 1943 #ifdef MSWIN 1944 && *--s != '\\' 1945 #endif 1946 ) 1947 ; 1948 if ((s > path && *s == '/') 1949 #ifdef MSWIN 1950 || (s > path && *s == '\\') 1951 #endif 1952 ) 1953 ++s; 1954 return s; 1955 } 1956 1957 /* 1958 * Called from cs_manage_matches(). 1959 */ 1960 static void 1961 cs_print_tags_priv(char **matches, char **cntxts, int num_matches) 1962 { 1963 char *buf = NULL; 1964 char *t_buf; 1965 int bufsize = 0; /* Track available bufsize */ 1966 int newsize = 0; 1967 char *ptag; 1968 char *fname, *lno, *extra, *tbuf; 1969 int i, idx, num; 1970 char *globalcntx = "GLOBAL"; 1971 char *cntxformat = " <<%s>>"; 1972 char *context; 1973 char *cstag_msg = _("Cscope tag: %s"); 1974 char *csfmt_str = "%4d %6s "; 1975 1976 assert(num_matches > 0); 1977 1978 if ((tbuf = alloc(strlen(matches[0]) + 1)) == NULL) 1979 return; 1980 1981 strcpy(tbuf, matches[0]); 1982 ptag = strtok(tbuf, "\t"); 1983 if (ptag == NULL) 1984 { 1985 vim_free(tbuf); 1986 return; 1987 } 1988 1989 newsize = (int)(strlen(cstag_msg) + strlen(ptag)); 1990 buf = alloc(newsize); 1991 if (buf != NULL) 1992 { 1993 bufsize = newsize; 1994 (void)sprintf(buf, cstag_msg, ptag); 1995 msg_puts_attr(buf, HL_ATTR(HLF_T)); 1996 } 1997 1998 vim_free(tbuf); 1999 2000 msg_puts_attr(_("\n # line"), HL_ATTR(HLF_T)); /* strlen is 7 */ 2001 msg_advance(msg_col + 2); 2002 msg_puts_attr(_("filename / context / line\n"), HL_ATTR(HLF_T)); 2003 2004 num = 1; 2005 for (i = 0; i < num_matches; i++) 2006 { 2007 idx = i; 2008 2009 /* if we really wanted to, we could avoid this malloc and strcpy 2010 * by parsing matches[i] on the fly and placing stuff into buf 2011 * directly, but that's too much of a hassle 2012 */ 2013 if ((tbuf = alloc(strlen(matches[idx]) + 1)) == NULL) 2014 continue; 2015 (void)strcpy(tbuf, matches[idx]); 2016 2017 if (strtok(tbuf, (const char *)"\t") == NULL 2018 || (fname = strtok(NULL, (const char *)"\t")) == NULL 2019 || (lno = strtok(NULL, (const char *)"\t")) == NULL) 2020 { 2021 vim_free(tbuf); 2022 continue; 2023 } 2024 extra = strtok(NULL, (const char *)"\t"); 2025 2026 lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */ 2027 2028 /* hopefully 'num' (num of matches) will be less than 10^16 */ 2029 newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno)); 2030 if (bufsize < newsize) 2031 { 2032 t_buf = buf; 2033 buf = vim_realloc(buf, newsize); 2034 if (buf == NULL) 2035 { 2036 bufsize = 0; 2037 vim_free(t_buf); 2038 } 2039 else 2040 bufsize = newsize; 2041 } 2042 if (buf != NULL) 2043 { 2044 /* csfmt_str = "%4d %6s "; */ 2045 (void)sprintf(buf, csfmt_str, num, lno); 2046 msg_puts_attr(buf, HL_ATTR(HLF_CM)); 2047 } 2048 msg_outtrans_long_attr((char_u *)cs_pathcomponents(fname), 2049 HL_ATTR(HLF_CM)); 2050 2051 /* compute the required space for the context */ 2052 if (cntxts[idx] != NULL) 2053 context = cntxts[idx]; 2054 else 2055 context = globalcntx; 2056 newsize = (int)(strlen(context) + strlen(cntxformat)); 2057 2058 if (bufsize < newsize) 2059 { 2060 t_buf = buf; 2061 buf = vim_realloc(buf, newsize); 2062 if (buf == NULL) 2063 { 2064 bufsize = 0; 2065 vim_free(t_buf); 2066 } 2067 else 2068 bufsize = newsize; 2069 } 2070 if (buf != NULL) 2071 { 2072 (void)sprintf(buf, cntxformat, context); 2073 2074 /* print the context only if it fits on the same line */ 2075 if (msg_col + (int)strlen(buf) >= (int)Columns) 2076 msg_putchar('\n'); 2077 msg_advance(12); 2078 msg_outtrans_long_attr((char_u *)buf, 0); 2079 msg_putchar('\n'); 2080 } 2081 if (extra != NULL) 2082 { 2083 msg_advance(13); 2084 msg_outtrans_long_attr((char_u *)extra, 0); 2085 } 2086 2087 vim_free(tbuf); /* only after printing extra due to strtok use */ 2088 2089 if (msg_col) 2090 msg_putchar('\n'); 2091 2092 ui_breakcheck(); 2093 if (got_int) 2094 { 2095 got_int = FALSE; /* don't print any more matches */ 2096 break; 2097 } 2098 2099 num++; 2100 } /* for all matches */ 2101 2102 vim_free(buf); 2103 } /* cs_print_tags_priv */ 2104 2105 2106 /* 2107 * Read a cscope prompt (basically, skip over the ">> "). 2108 */ 2109 static int 2110 cs_read_prompt(int i) 2111 { 2112 int ch; 2113 char *buf = NULL; /* buffer for possible error message from cscope */ 2114 int bufpos = 0; 2115 char *cs_emsg; 2116 int maxlen; 2117 static char *eprompt = "Press the RETURN key to continue:"; 2118 int epromptlen = (int)strlen(eprompt); 2119 int n; 2120 2121 cs_emsg = _("E609: Cscope error: %s"); 2122 /* compute maximum allowed len for Cscope error message */ 2123 maxlen = (int)(IOSIZE - strlen(cs_emsg)); 2124 2125 for (;;) 2126 { 2127 while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0]) 2128 /* if there is room and char is printable */ 2129 if (bufpos < maxlen - 1 && vim_isprintc(ch)) 2130 { 2131 if (buf == NULL) /* lazy buffer allocation */ 2132 buf = alloc(maxlen); 2133 if (buf != NULL) 2134 { 2135 /* append character to the message */ 2136 buf[bufpos++] = ch; 2137 buf[bufpos] = NUL; 2138 if (bufpos >= epromptlen 2139 && strcmp(&buf[bufpos - epromptlen], eprompt) == 0) 2140 { 2141 /* remove eprompt from buf */ 2142 buf[bufpos - epromptlen] = NUL; 2143 2144 /* print message to user */ 2145 (void)semsg(cs_emsg, buf); 2146 2147 /* send RETURN to cscope */ 2148 (void)putc('\n', csinfo[i].to_fp); 2149 (void)fflush(csinfo[i].to_fp); 2150 2151 /* clear buf */ 2152 bufpos = 0; 2153 buf[bufpos] = NUL; 2154 } 2155 } 2156 } 2157 2158 for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n) 2159 { 2160 if (n > 0) 2161 ch = getc(csinfo[i].fr_fp); 2162 if (ch == EOF) 2163 { 2164 PERROR("cs_read_prompt EOF"); 2165 if (buf != NULL && buf[0] != NUL) 2166 (void)semsg(cs_emsg, buf); 2167 else if (p_csverbose) 2168 cs_reading_emsg(i); /* don't have additional information */ 2169 cs_release_csp(i, TRUE); 2170 vim_free(buf); 2171 return CSCOPE_FAILURE; 2172 } 2173 2174 if (ch != CSCOPE_PROMPT[n]) 2175 { 2176 ch = EOF; 2177 break; 2178 } 2179 } 2180 2181 if (ch == EOF) 2182 continue; /* didn't find the prompt */ 2183 break; /* did find the prompt */ 2184 } 2185 2186 vim_free(buf); 2187 return CSCOPE_SUCCESS; 2188 } 2189 2190 #if defined(UNIX) && defined(SIGALRM) 2191 /* 2192 * Used to catch and ignore SIGALRM below. 2193 */ 2194 static RETSIGTYPE 2195 sig_handler SIGDEFARG(sigarg) 2196 { 2197 /* do nothing */ 2198 SIGRETURN; 2199 } 2200 #endif 2201 2202 /* 2203 * Does the actual free'ing for the cs ptr with an optional flag of whether 2204 * or not to free the filename. Called by cs_kill and cs_reset. 2205 */ 2206 static void 2207 cs_release_csp(int i, int freefnpp) 2208 { 2209 /* 2210 * Trying to exit normally (not sure whether it is fit to UNIX cscope 2211 */ 2212 if (csinfo[i].to_fp != NULL) 2213 { 2214 (void)fputs("q\n", csinfo[i].to_fp); 2215 (void)fflush(csinfo[i].to_fp); 2216 } 2217 #if defined(UNIX) 2218 { 2219 int waitpid_errno; 2220 int pstat; 2221 pid_t pid; 2222 2223 # if defined(HAVE_SIGACTION) 2224 struct sigaction sa, old; 2225 2226 /* Use sigaction() to limit the waiting time to two seconds. */ 2227 sigemptyset(&sa.sa_mask); 2228 sa.sa_handler = sig_handler; 2229 # ifdef SA_NODEFER 2230 sa.sa_flags = SA_NODEFER; 2231 # else 2232 sa.sa_flags = 0; 2233 # endif 2234 sigaction(SIGALRM, &sa, &old); 2235 alarm(2); /* 2 sec timeout */ 2236 2237 /* Block until cscope exits or until timer expires */ 2238 pid = waitpid(csinfo[i].pid, &pstat, 0); 2239 waitpid_errno = errno; 2240 2241 /* cancel pending alarm if still there and restore signal */ 2242 alarm(0); 2243 sigaction(SIGALRM, &old, NULL); 2244 # else 2245 int waited; 2246 2247 /* Can't use sigaction(), loop for two seconds. First yield the CPU 2248 * to give cscope a chance to exit quickly. */ 2249 sleep(0); 2250 for (waited = 0; waited < 40; ++waited) 2251 { 2252 pid = waitpid(csinfo[i].pid, &pstat, WNOHANG); 2253 waitpid_errno = errno; 2254 if (pid != 0) 2255 break; /* break unless the process is still running */ 2256 mch_delay(50L, FALSE); /* sleep 50 ms */ 2257 } 2258 # endif 2259 /* 2260 * If the cscope process is still running: kill it. 2261 * Safety check: If the PID would be zero here, the entire X session 2262 * would be killed. -1 and 1 are dangerous as well. 2263 */ 2264 if (pid < 0 && csinfo[i].pid > 1) 2265 { 2266 # ifdef ECHILD 2267 int alive = TRUE; 2268 2269 if (waitpid_errno == ECHILD) 2270 { 2271 /* 2272 * When using 'vim -g', vim is forked and cscope process is 2273 * no longer a child process but a sibling. So waitpid() 2274 * fails with errno being ECHILD (No child processes). 2275 * Don't send SIGKILL to cscope immediately but wait 2276 * (polling) for it to exit normally as result of sending 2277 * the "q" command, hence giving it a chance to clean up 2278 * its temporary files. 2279 */ 2280 int waited; 2281 2282 sleep(0); 2283 for (waited = 0; waited < 40; ++waited) 2284 { 2285 /* Check whether cscope process is still alive */ 2286 if (kill(csinfo[i].pid, 0) != 0) 2287 { 2288 alive = FALSE; /* cscope process no longer exists */ 2289 break; 2290 } 2291 mch_delay(50L, FALSE); /* sleep 50ms */ 2292 } 2293 } 2294 if (alive) 2295 # endif 2296 { 2297 kill(csinfo[i].pid, SIGKILL); 2298 (void)waitpid(csinfo[i].pid, &pstat, 0); 2299 } 2300 } 2301 } 2302 #else /* !UNIX */ 2303 if (csinfo[i].hProc != NULL) 2304 { 2305 /* Give cscope a chance to exit normally */ 2306 if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT) 2307 TerminateProcess(csinfo[i].hProc, 0); 2308 CloseHandle(csinfo[i].hProc); 2309 } 2310 #endif 2311 2312 if (csinfo[i].fr_fp != NULL) 2313 (void)fclose(csinfo[i].fr_fp); 2314 if (csinfo[i].to_fp != NULL) 2315 (void)fclose(csinfo[i].to_fp); 2316 2317 if (freefnpp) 2318 { 2319 vim_free(csinfo[i].fname); 2320 vim_free(csinfo[i].ppath); 2321 vim_free(csinfo[i].flags); 2322 } 2323 2324 clear_csinfo(i); 2325 } /* cs_release_csp */ 2326 2327 2328 /* 2329 * Calls cs_kill on all cscope connections then reinits. 2330 */ 2331 static int 2332 cs_reset(exarg_T *eap UNUSED) 2333 { 2334 char **dblist = NULL, **pplist = NULL, **fllist = NULL; 2335 int i; 2336 char buf[20]; /* for sprintf " (#%d)" */ 2337 2338 if (csinfo_size == 0) 2339 return CSCOPE_SUCCESS; 2340 2341 /* malloc our db and ppath list */ 2342 dblist = ALLOC_MULT(char *, csinfo_size); 2343 pplist = ALLOC_MULT(char *, csinfo_size); 2344 fllist = ALLOC_MULT(char *, csinfo_size); 2345 if (dblist == NULL || pplist == NULL || fllist == NULL) 2346 { 2347 vim_free(dblist); 2348 vim_free(pplist); 2349 vim_free(fllist); 2350 return CSCOPE_FAILURE; 2351 } 2352 2353 for (i = 0; i < csinfo_size; i++) 2354 { 2355 dblist[i] = csinfo[i].fname; 2356 pplist[i] = csinfo[i].ppath; 2357 fllist[i] = csinfo[i].flags; 2358 if (csinfo[i].fname != NULL) 2359 cs_release_csp(i, FALSE); 2360 } 2361 2362 /* rebuild the cscope connection list */ 2363 for (i = 0; i < csinfo_size; i++) 2364 { 2365 if (dblist[i] != NULL) 2366 { 2367 cs_add_common(dblist[i], pplist[i], fllist[i]); 2368 if (p_csverbose) 2369 { 2370 /* don't use smsg_attr() because we want to display the 2371 * connection number in the same line as 2372 * "Added cscope database..." 2373 */ 2374 sprintf(buf, " (#%d)", i); 2375 msg_puts_attr(buf, HL_ATTR(HLF_R)); 2376 } 2377 } 2378 vim_free(dblist[i]); 2379 vim_free(pplist[i]); 2380 vim_free(fllist[i]); 2381 } 2382 vim_free(dblist); 2383 vim_free(pplist); 2384 vim_free(fllist); 2385 2386 if (p_csverbose) 2387 msg_attr(_("All cscope databases reset"), HL_ATTR(HLF_R) | MSG_HIST); 2388 return CSCOPE_SUCCESS; 2389 } /* cs_reset */ 2390 2391 2392 /* 2393 * Construct the full pathname to a file found in the cscope database. 2394 * (Prepends ppath, if there is one and if it's not already prepended, 2395 * otherwise just uses the name found.) 2396 * 2397 * We need to prepend the prefix because on some cscope's (e.g., the one that 2398 * ships with Solaris 2.6), the output never has the prefix prepended. 2399 * Contrast this with my development system (Digital Unix), which does. 2400 */ 2401 static char * 2402 cs_resolve_file(int i, char *name) 2403 { 2404 char *fullname; 2405 int len; 2406 char_u *csdir = NULL; 2407 2408 /* 2409 * Ppath is freed when we destroy the cscope connection. 2410 * Fullname is freed after cs_make_vim_style_matches, after it's been 2411 * copied into the tag buffer used by Vim. 2412 */ 2413 len = (int)(strlen(name) + 2); 2414 if (csinfo[i].ppath != NULL) 2415 len += (int)strlen(csinfo[i].ppath); 2416 else if (p_csre && csinfo[i].fname != NULL) 2417 { 2418 /* If 'cscoperelative' is set and ppath is not set, use cscope.out 2419 * path in path resolution. */ 2420 csdir = alloc(MAXPATHL); 2421 if (csdir != NULL) 2422 { 2423 vim_strncpy(csdir, (char_u *)csinfo[i].fname, 2424 gettail((char_u *)csinfo[i].fname) 2425 - (char_u *)csinfo[i].fname); 2426 len += (int)STRLEN(csdir); 2427 } 2428 } 2429 2430 /* Note/example: this won't work if the cscope output already starts 2431 * "../.." and the prefix path is also "../..". if something like this 2432 * happens, you are screwed up and need to fix how you're using cscope. */ 2433 if (csinfo[i].ppath != NULL 2434 && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) 2435 && (name[0] != '/') 2436 #ifdef MSWIN 2437 && name[0] != '\\' && name[1] != ':' 2438 #endif 2439 ) 2440 { 2441 if ((fullname = alloc(len)) != NULL) 2442 (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name); 2443 } 2444 else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) 2445 { 2446 /* Check for csdir to be non empty to avoid empty path concatenated to 2447 * cscope output. */ 2448 fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE); 2449 } 2450 else 2451 { 2452 fullname = (char *)vim_strsave((char_u *)name); 2453 } 2454 2455 vim_free(csdir); 2456 return fullname; 2457 } 2458 2459 2460 /* 2461 * Show all cscope connections. 2462 */ 2463 static int 2464 cs_show(exarg_T *eap UNUSED) 2465 { 2466 short i; 2467 if (cs_cnt_connections() == 0) 2468 msg_puts(_("no cscope connections\n")); 2469 else 2470 { 2471 msg_puts_attr( 2472 _(" # pid database name prepend path\n"), 2473 HL_ATTR(HLF_T)); 2474 for (i = 0; i < csinfo_size; i++) 2475 { 2476 if (csinfo[i].fname == NULL) 2477 continue; 2478 2479 if (csinfo[i].ppath != NULL) 2480 (void)smsg("%2d %-5ld %-34s %-32s", 2481 i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath); 2482 else 2483 (void)smsg("%2d %-5ld %-34s <none>", 2484 i, (long)csinfo[i].pid, csinfo[i].fname); 2485 } 2486 } 2487 2488 wait_return(TRUE); 2489 return CSCOPE_SUCCESS; 2490 } /* cs_show */ 2491 2492 2493 /* 2494 * Only called when VIM exits to quit any cscope sessions. 2495 */ 2496 void 2497 cs_end(void) 2498 { 2499 int i; 2500 2501 for (i = 0; i < csinfo_size; i++) 2502 cs_release_csp(i, TRUE); 2503 vim_free(csinfo); 2504 csinfo_size = 0; 2505 } 2506 2507 #endif /* FEAT_CSCOPE */ 2508 2509 /* the end */ 2510