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