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