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