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