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