1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * Code to handle tags and the tag stack 12 */ 13 14 #include "vim.h" 15 16 /* 17 * Structure to hold pointers to various items in a tag line. 18 */ 19 typedef struct tag_pointers 20 { 21 /* filled in by parse_tag_line(): */ 22 char_u *tagname; /* start of tag name (skip "file:") */ 23 char_u *tagname_end; /* char after tag name */ 24 char_u *fname; /* first char of file name */ 25 char_u *fname_end; /* char after file name */ 26 char_u *command; /* first char of command */ 27 /* filled in by parse_match(): */ 28 char_u *command_end; /* first char after command */ 29 char_u *tag_fname; /* file name of the tags file */ 30 #ifdef FEAT_EMACS_TAGS 31 int is_etag; /* TRUE for emacs tag */ 32 #endif 33 char_u *tagkind; /* "kind:" value */ 34 char_u *tagkind_end; /* end of tagkind */ 35 } tagptrs_T; 36 37 /* 38 * The matching tags are first stored in one of the hash tables. In 39 * which one depends on the priority of the match. 40 * ht_match[] is used to find duplicates, ga_match[] to keep them in sequence. 41 * At the end, all the matches from ga_match[] are concatenated, to make a list 42 * sorted on priority. 43 */ 44 #define MT_ST_CUR 0 /* static match in current file */ 45 #define MT_GL_CUR 1 /* global match in current file */ 46 #define MT_GL_OTH 2 /* global match in other file */ 47 #define MT_ST_OTH 3 /* static match in other file */ 48 #define MT_IC_OFF 4 /* add for icase match */ 49 #define MT_RE_OFF 8 /* add for regexp match */ 50 #define MT_MASK 7 /* mask for printing priority */ 51 #define MT_COUNT 16 52 53 static char *mt_names[MT_COUNT/2] = 54 {"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "}; 55 56 #define NOTAGFILE 99 /* return value for jumpto_tag */ 57 static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */ 58 59 static void taglen_advance(int l); 60 61 static int jumpto_tag(char_u *lbuf, int forceit, int keep_help); 62 #ifdef FEAT_EMACS_TAGS 63 static int parse_tag_line(char_u *lbuf, int is_etag, tagptrs_T *tagp); 64 #else 65 static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp); 66 #endif 67 static int test_for_static(tagptrs_T *); 68 static int parse_match(char_u *lbuf, tagptrs_T *tagp); 69 static char_u *tag_full_fname(tagptrs_T *tagp); 70 static char_u *expand_tag_fname(char_u *fname, char_u *tag_fname, int expand); 71 #ifdef FEAT_EMACS_TAGS 72 static int test_for_current(int, char_u *, char_u *, char_u *, char_u *); 73 #else 74 static int test_for_current(char_u *, char_u *, char_u *, char_u *); 75 #endif 76 static int find_extra(char_u **pp); 77 78 static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack"); 79 static char_u *topmsg = (char_u *)N_("E556: at top of tag stack"); 80 81 static char_u *tagmatchname = NULL; /* name of last used tag */ 82 83 #if defined(FEAT_QUICKFIX) 84 /* 85 * Tag for preview window is remembered separately, to avoid messing up the 86 * normal tagstack. 87 */ 88 static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0}; 89 #endif 90 91 /* 92 * Jump to tag; handling of tag commands and tag stack 93 * 94 * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack 95 * 96 * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again 97 * type == DT_HELP: like DT_TAG, but don't use regexp. 98 * type == DT_POP: ":pop" or CTRL-T, jump to old position 99 * type == DT_NEXT: jump to next match of same tag 100 * type == DT_PREV: jump to previous match of same tag 101 * type == DT_FIRST: jump to first match of same tag 102 * type == DT_LAST: jump to last match of same tag 103 * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches 104 * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list 105 * type == DT_CSCOPE: use cscope to find the tag 106 * type == DT_LTAG: use location list for displaying tag matches 107 * type == DT_FREE: free cached matches 108 * 109 * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise 110 */ 111 int 112 do_tag( 113 char_u *tag, /* tag (pattern) to jump to */ 114 int type, 115 int count, 116 int forceit, /* :ta with ! */ 117 int verbose) /* print "tag not found" message */ 118 { 119 taggy_T *tagstack = curwin->w_tagstack; 120 int tagstackidx = curwin->w_tagstackidx; 121 int tagstacklen = curwin->w_tagstacklen; 122 int cur_match = 0; 123 int cur_fnum = curbuf->b_fnum; 124 int oldtagstackidx = tagstackidx; 125 int prevtagstackidx = tagstackidx; 126 int prev_num_matches; 127 int new_tag = FALSE; 128 int other_name; 129 int i, j, k; 130 int idx; 131 int ic; 132 char_u *p; 133 char_u *name; 134 int no_regexp = FALSE; 135 int error_cur_match = 0; 136 char_u *command_end; 137 int save_pos = FALSE; 138 fmark_T saved_fmark; 139 int taglen; 140 #ifdef FEAT_CSCOPE 141 int jumped_to_tag = FALSE; 142 #endif 143 tagptrs_T tagp, tagp2; 144 int new_num_matches; 145 char_u **new_matches; 146 int attr; 147 int use_tagstack; 148 int skip_msg = FALSE; 149 char_u *buf_ffname = curbuf->b_ffname; /* name to use for 150 priority computation */ 151 152 /* remember the matches for the last used tag */ 153 static int num_matches = 0; 154 static int max_num_matches = 0; /* limit used for match search */ 155 static char_u **matches = NULL; 156 static int flags; 157 158 #ifdef EXITFREE 159 if (type == DT_FREE) 160 { 161 /* remove the list of matches */ 162 FreeWild(num_matches, matches); 163 # ifdef FEAT_CSCOPE 164 cs_free_tags(); 165 # endif 166 num_matches = 0; 167 return FALSE; 168 } 169 #endif 170 171 if (type == DT_HELP) 172 { 173 type = DT_TAG; 174 no_regexp = TRUE; 175 } 176 177 prev_num_matches = num_matches; 178 free_string_option(nofile_fname); 179 nofile_fname = NULL; 180 181 CLEAR_POS(&saved_fmark.mark); /* shutup gcc 4.0 */ 182 saved_fmark.fnum = 0; 183 184 /* 185 * Don't add a tag to the tagstack if 'tagstack' has been reset. 186 */ 187 if ((!p_tgst && *tag != NUL)) 188 { 189 use_tagstack = FALSE; 190 new_tag = TRUE; 191 #if defined(FEAT_QUICKFIX) 192 if (g_do_tagpreview != 0) 193 { 194 vim_free(ptag_entry.tagname); 195 if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) 196 goto end_do_tag; 197 } 198 #endif 199 } 200 else 201 { 202 #if defined(FEAT_QUICKFIX) 203 if (g_do_tagpreview != 0) 204 use_tagstack = FALSE; 205 else 206 #endif 207 use_tagstack = TRUE; 208 209 /* new pattern, add to the tag stack */ 210 if (*tag != NUL 211 && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP 212 #ifdef FEAT_QUICKFIX 213 || type == DT_LTAG 214 #endif 215 #ifdef FEAT_CSCOPE 216 || type == DT_CSCOPE 217 #endif 218 )) 219 { 220 #if defined(FEAT_QUICKFIX) 221 if (g_do_tagpreview != 0) 222 { 223 if (ptag_entry.tagname != NULL 224 && STRCMP(ptag_entry.tagname, tag) == 0) 225 { 226 /* Jumping to same tag: keep the current match, so that 227 * the CursorHold autocommand example works. */ 228 cur_match = ptag_entry.cur_match; 229 cur_fnum = ptag_entry.cur_fnum; 230 } 231 else 232 { 233 vim_free(ptag_entry.tagname); 234 if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) 235 goto end_do_tag; 236 } 237 } 238 else 239 #endif 240 { 241 /* 242 * If the last used entry is not at the top, delete all tag 243 * stack entries above it. 244 */ 245 while (tagstackidx < tagstacklen) 246 vim_free(tagstack[--tagstacklen].tagname); 247 248 /* if the tagstack is full: remove oldest entry */ 249 if (++tagstacklen > TAGSTACKSIZE) 250 { 251 tagstacklen = TAGSTACKSIZE; 252 vim_free(tagstack[0].tagname); 253 for (i = 1; i < tagstacklen; ++i) 254 tagstack[i - 1] = tagstack[i]; 255 --tagstackidx; 256 } 257 258 /* 259 * put the tag name in the tag stack 260 */ 261 if ((tagstack[tagstackidx].tagname = vim_strsave(tag)) == NULL) 262 { 263 curwin->w_tagstacklen = tagstacklen - 1; 264 goto end_do_tag; 265 } 266 curwin->w_tagstacklen = tagstacklen; 267 268 save_pos = TRUE; /* save the cursor position below */ 269 } 270 271 new_tag = TRUE; 272 } 273 else 274 { 275 if ( 276 #if defined(FEAT_QUICKFIX) 277 g_do_tagpreview != 0 ? ptag_entry.tagname == NULL : 278 #endif 279 tagstacklen == 0) 280 { 281 /* empty stack */ 282 emsg(_(e_tagstack)); 283 goto end_do_tag; 284 } 285 286 if (type == DT_POP) /* go to older position */ 287 { 288 #ifdef FEAT_FOLDING 289 int old_KeyTyped = KeyTyped; 290 #endif 291 if ((tagstackidx -= count) < 0) 292 { 293 emsg(_(bottommsg)); 294 if (tagstackidx + count == 0) 295 { 296 /* We did [num]^T from the bottom of the stack */ 297 tagstackidx = 0; 298 goto end_do_tag; 299 } 300 /* We weren't at the bottom of the stack, so jump all the 301 * way to the bottom now. 302 */ 303 tagstackidx = 0; 304 } 305 else if (tagstackidx >= tagstacklen) /* count == 0? */ 306 { 307 emsg(_(topmsg)); 308 goto end_do_tag; 309 } 310 311 /* Make a copy of the fmark, autocommands may invalidate the 312 * tagstack before it's used. */ 313 saved_fmark = tagstack[tagstackidx].fmark; 314 if (saved_fmark.fnum != curbuf->b_fnum) 315 { 316 /* 317 * Jump to other file. If this fails (e.g. because the 318 * file was changed) keep original position in tag stack. 319 */ 320 if (buflist_getfile(saved_fmark.fnum, saved_fmark.mark.lnum, 321 GETF_SETMARK, forceit) == FAIL) 322 { 323 tagstackidx = oldtagstackidx; /* back to old posn */ 324 goto end_do_tag; 325 } 326 /* An BufReadPost autocommand may jump to the '" mark, but 327 * we don't what that here. */ 328 curwin->w_cursor.lnum = saved_fmark.mark.lnum; 329 } 330 else 331 { 332 setpcmark(); 333 curwin->w_cursor.lnum = saved_fmark.mark.lnum; 334 } 335 curwin->w_cursor.col = saved_fmark.mark.col; 336 curwin->w_set_curswant = TRUE; 337 check_cursor(); 338 #ifdef FEAT_FOLDING 339 if ((fdo_flags & FDO_TAG) && old_KeyTyped) 340 foldOpenCursor(); 341 #endif 342 343 /* remove the old list of matches */ 344 FreeWild(num_matches, matches); 345 #ifdef FEAT_CSCOPE 346 cs_free_tags(); 347 #endif 348 num_matches = 0; 349 tag_freematch(); 350 goto end_do_tag; 351 } 352 353 if (type == DT_TAG 354 #if defined(FEAT_QUICKFIX) 355 || type == DT_LTAG 356 #endif 357 ) 358 { 359 #if defined(FEAT_QUICKFIX) 360 if (g_do_tagpreview != 0) 361 { 362 cur_match = ptag_entry.cur_match; 363 cur_fnum = ptag_entry.cur_fnum; 364 } 365 else 366 #endif 367 { 368 /* ":tag" (no argument): go to newer pattern */ 369 save_pos = TRUE; /* save the cursor position below */ 370 if ((tagstackidx += count - 1) >= tagstacklen) 371 { 372 /* 373 * Beyond the last one, just give an error message and 374 * go to the last one. Don't store the cursor 375 * position. 376 */ 377 tagstackidx = tagstacklen - 1; 378 emsg(_(topmsg)); 379 save_pos = FALSE; 380 } 381 else if (tagstackidx < 0) /* must have been count == 0 */ 382 { 383 emsg(_(bottommsg)); 384 tagstackidx = 0; 385 goto end_do_tag; 386 } 387 cur_match = tagstack[tagstackidx].cur_match; 388 cur_fnum = tagstack[tagstackidx].cur_fnum; 389 } 390 new_tag = TRUE; 391 } 392 else /* go to other matching tag */ 393 { 394 /* Save index for when selection is cancelled. */ 395 prevtagstackidx = tagstackidx; 396 397 #if defined(FEAT_QUICKFIX) 398 if (g_do_tagpreview != 0) 399 { 400 cur_match = ptag_entry.cur_match; 401 cur_fnum = ptag_entry.cur_fnum; 402 } 403 else 404 #endif 405 { 406 if (--tagstackidx < 0) 407 tagstackidx = 0; 408 cur_match = tagstack[tagstackidx].cur_match; 409 cur_fnum = tagstack[tagstackidx].cur_fnum; 410 } 411 switch (type) 412 { 413 case DT_FIRST: cur_match = count - 1; break; 414 case DT_SELECT: 415 case DT_JUMP: 416 #ifdef FEAT_CSCOPE 417 case DT_CSCOPE: 418 #endif 419 case DT_LAST: cur_match = MAXCOL - 1; break; 420 case DT_NEXT: cur_match += count; break; 421 case DT_PREV: cur_match -= count; break; 422 } 423 if (cur_match >= MAXCOL) 424 cur_match = MAXCOL - 1; 425 else if (cur_match < 0) 426 { 427 emsg(_("E425: Cannot go before first matching tag")); 428 skip_msg = TRUE; 429 cur_match = 0; 430 cur_fnum = curbuf->b_fnum; 431 } 432 } 433 } 434 435 #if defined(FEAT_QUICKFIX) 436 if (g_do_tagpreview != 0) 437 { 438 if (type != DT_SELECT && type != DT_JUMP) 439 { 440 ptag_entry.cur_match = cur_match; 441 ptag_entry.cur_fnum = cur_fnum; 442 } 443 } 444 else 445 #endif 446 { 447 /* 448 * For ":tag [arg]" or ":tselect" remember position before the jump. 449 */ 450 saved_fmark = tagstack[tagstackidx].fmark; 451 if (save_pos) 452 { 453 tagstack[tagstackidx].fmark.mark = curwin->w_cursor; 454 tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum; 455 } 456 457 /* Curwin will change in the call to jumpto_tag() if ":stag" was 458 * used or an autocommand jumps to another window; store value of 459 * tagstackidx now. */ 460 curwin->w_tagstackidx = tagstackidx; 461 if (type != DT_SELECT && type != DT_JUMP) 462 { 463 curwin->w_tagstack[tagstackidx].cur_match = cur_match; 464 curwin->w_tagstack[tagstackidx].cur_fnum = cur_fnum; 465 } 466 } 467 } 468 469 /* When not using the current buffer get the name of buffer "cur_fnum". 470 * Makes sure that the tag order doesn't change when using a remembered 471 * position for "cur_match". */ 472 if (cur_fnum != curbuf->b_fnum) 473 { 474 buf_T *buf = buflist_findnr(cur_fnum); 475 476 if (buf != NULL) 477 buf_ffname = buf->b_ffname; 478 } 479 480 /* 481 * Repeat searching for tags, when a file has not been found. 482 */ 483 for (;;) 484 { 485 /* 486 * When desired match not found yet, try to find it (and others). 487 */ 488 if (use_tagstack) 489 name = tagstack[tagstackidx].tagname; 490 #if defined(FEAT_QUICKFIX) 491 else if (g_do_tagpreview != 0) 492 name = ptag_entry.tagname; 493 #endif 494 else 495 name = tag; 496 other_name = (tagmatchname == NULL || STRCMP(tagmatchname, name) != 0); 497 if (new_tag 498 || (cur_match >= num_matches && max_num_matches != MAXCOL) 499 || other_name) 500 { 501 if (other_name) 502 { 503 vim_free(tagmatchname); 504 tagmatchname = vim_strsave(name); 505 } 506 507 if (type == DT_TAG || type == DT_SELECT || type == DT_JUMP 508 #if defined(FEAT_QUICKFIX) 509 || type == DT_LTAG 510 #endif 511 ) 512 cur_match = MAXCOL - 1; 513 max_num_matches = cur_match + 1; 514 515 /* when the argument starts with '/', use it as a regexp */ 516 if (!no_regexp && *name == '/') 517 { 518 flags = TAG_REGEXP; 519 ++name; 520 } 521 else 522 flags = TAG_NOIC; 523 524 #ifdef FEAT_CSCOPE 525 if (type == DT_CSCOPE) 526 flags = TAG_CSCOPE; 527 #endif 528 if (verbose) 529 flags |= TAG_VERBOSE; 530 if (find_tags(name, &new_num_matches, &new_matches, flags, 531 max_num_matches, buf_ffname) == OK 532 && new_num_matches < max_num_matches) 533 max_num_matches = MAXCOL; /* If less than max_num_matches 534 found: all matches found. */ 535 536 /* If there already were some matches for the same name, move them 537 * to the start. Avoids that the order changes when using 538 * ":tnext" and jumping to another file. */ 539 if (!new_tag && !other_name) 540 { 541 /* Find the position of each old match in the new list. Need 542 * to use parse_match() to find the tag line. */ 543 idx = 0; 544 for (j = 0; j < num_matches; ++j) 545 { 546 parse_match(matches[j], &tagp); 547 for (i = idx; i < new_num_matches; ++i) 548 { 549 parse_match(new_matches[i], &tagp2); 550 if (STRCMP(tagp.tagname, tagp2.tagname) == 0) 551 { 552 p = new_matches[i]; 553 for (k = i; k > idx; --k) 554 new_matches[k] = new_matches[k - 1]; 555 new_matches[idx++] = p; 556 break; 557 } 558 } 559 } 560 } 561 FreeWild(num_matches, matches); 562 num_matches = new_num_matches; 563 matches = new_matches; 564 } 565 566 if (num_matches <= 0) 567 { 568 if (verbose) 569 semsg(_("E426: tag not found: %s"), name); 570 #if defined(FEAT_QUICKFIX) 571 g_do_tagpreview = 0; 572 #endif 573 } 574 else 575 { 576 int ask_for_selection = FALSE; 577 578 #ifdef FEAT_CSCOPE 579 if (type == DT_CSCOPE && num_matches > 1) 580 { 581 cs_print_tags(); 582 ask_for_selection = TRUE; 583 } 584 else 585 #endif 586 if (type == DT_TAG) 587 /* 588 * If a count is supplied to the ":tag <name>" command, then 589 * jump to count'th matching tag. 590 */ 591 cur_match = count > 0 ? count - 1 : 0; 592 else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1)) 593 { 594 /* 595 * List all the matching tags. 596 * Assume that the first match indicates how long the tags can 597 * be, and align the file names to that. 598 */ 599 parse_match(matches[0], &tagp); 600 taglen = (int)(tagp.tagname_end - tagp.tagname + 2); 601 if (taglen < 18) 602 taglen = 18; 603 if (taglen > Columns - 25) 604 taglen = MAXCOL; 605 if (msg_col == 0) 606 msg_didout = FALSE; /* overwrite previous message */ 607 msg_start(); 608 msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T)); 609 msg_clr_eos(); 610 taglen_advance(taglen); 611 msg_puts_attr(_("file\n"), HL_ATTR(HLF_T)); 612 613 for (i = 0; i < num_matches && !got_int; ++i) 614 { 615 parse_match(matches[i], &tagp); 616 if (!new_tag && ( 617 #if defined(FEAT_QUICKFIX) 618 (g_do_tagpreview != 0 619 && i == ptag_entry.cur_match) || 620 #endif 621 (use_tagstack 622 && i == tagstack[tagstackidx].cur_match))) 623 *IObuff = '>'; 624 else 625 *IObuff = ' '; 626 vim_snprintf((char *)IObuff + 1, IOSIZE - 1, 627 "%2d %s ", i + 1, 628 mt_names[matches[i][0] & MT_MASK]); 629 msg_puts((char *)IObuff); 630 if (tagp.tagkind != NULL) 631 msg_outtrans_len(tagp.tagkind, 632 (int)(tagp.tagkind_end - tagp.tagkind)); 633 msg_advance(13); 634 msg_outtrans_len_attr(tagp.tagname, 635 (int)(tagp.tagname_end - tagp.tagname), 636 HL_ATTR(HLF_T)); 637 msg_putchar(' '); 638 taglen_advance(taglen); 639 640 /* Find out the actual file name. If it is long, truncate 641 * it and put "..." in the middle */ 642 p = tag_full_fname(&tagp); 643 if (p != NULL) 644 { 645 msg_outtrans_long_attr(p, HL_ATTR(HLF_D)); 646 vim_free(p); 647 } 648 if (msg_col > 0) 649 msg_putchar('\n'); 650 if (got_int) 651 break; 652 msg_advance(15); 653 654 /* print any extra fields */ 655 command_end = tagp.command_end; 656 if (command_end != NULL) 657 { 658 p = command_end + 3; 659 while (*p && *p != '\r' && *p != '\n') 660 { 661 while (*p == TAB) 662 ++p; 663 664 /* skip "file:" without a value (static tag) */ 665 if (STRNCMP(p, "file:", 5) == 0 666 && vim_isspace(p[5])) 667 { 668 p += 5; 669 continue; 670 } 671 /* skip "kind:<kind>" and "<kind>" */ 672 if (p == tagp.tagkind 673 || (p + 5 == tagp.tagkind 674 && STRNCMP(p, "kind:", 5) == 0)) 675 { 676 p = tagp.tagkind_end; 677 continue; 678 } 679 /* print all other extra fields */ 680 attr = HL_ATTR(HLF_CM); 681 while (*p && *p != '\r' && *p != '\n') 682 { 683 if (msg_col + ptr2cells(p) >= Columns) 684 { 685 msg_putchar('\n'); 686 if (got_int) 687 break; 688 msg_advance(15); 689 } 690 p = msg_outtrans_one(p, attr); 691 if (*p == TAB) 692 { 693 msg_puts_attr(" ", attr); 694 break; 695 } 696 if (*p == ':') 697 attr = 0; 698 } 699 } 700 if (msg_col > 15) 701 { 702 msg_putchar('\n'); 703 if (got_int) 704 break; 705 msg_advance(15); 706 } 707 } 708 else 709 { 710 for (p = tagp.command; 711 *p && *p != '\r' && *p != '\n'; ++p) 712 ; 713 command_end = p; 714 } 715 716 /* 717 * Put the info (in several lines) at column 15. 718 * Don't display "/^" and "?^". 719 */ 720 p = tagp.command; 721 if (*p == '/' || *p == '?') 722 { 723 ++p; 724 if (*p == '^') 725 ++p; 726 } 727 /* Remove leading whitespace from pattern */ 728 while (p != command_end && vim_isspace(*p)) 729 ++p; 730 731 while (p != command_end) 732 { 733 if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns) 734 msg_putchar('\n'); 735 if (got_int) 736 break; 737 msg_advance(15); 738 739 /* skip backslash used for escaping a command char or 740 * a backslash */ 741 if (*p == '\\' && (*(p + 1) == *tagp.command 742 || *(p + 1) == '\\')) 743 ++p; 744 745 if (*p == TAB) 746 { 747 msg_putchar(' '); 748 ++p; 749 } 750 else 751 p = msg_outtrans_one(p, 0); 752 753 /* don't display the "$/;\"" and "$?;\"" */ 754 if (p == command_end - 2 && *p == '$' 755 && *(p + 1) == *tagp.command) 756 break; 757 /* don't display matching '/' or '?' */ 758 if (p == command_end - 1 && *p == *tagp.command 759 && (*p == '/' || *p == '?')) 760 break; 761 } 762 if (msg_col) 763 msg_putchar('\n'); 764 ui_breakcheck(); 765 } 766 if (got_int) 767 got_int = FALSE; /* only stop the listing */ 768 ask_for_selection = TRUE; 769 } 770 #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL) 771 else if (type == DT_LTAG) 772 { 773 list_T *list; 774 char_u tag_name[128 + 1]; 775 char_u *fname; 776 char_u *cmd; 777 778 /* 779 * Add the matching tags to the location list for the current 780 * window. 781 */ 782 783 fname = alloc(MAXPATHL + 1); 784 cmd = alloc(CMDBUFFSIZE + 1); 785 list = list_alloc(); 786 if (list == NULL || fname == NULL || cmd == NULL) 787 { 788 vim_free(cmd); 789 vim_free(fname); 790 if (list != NULL) 791 list_free(list); 792 goto end_do_tag; 793 } 794 795 for (i = 0; i < num_matches; ++i) 796 { 797 int len, cmd_len; 798 long lnum; 799 dict_T *dict; 800 801 parse_match(matches[i], &tagp); 802 803 /* Save the tag name */ 804 len = (int)(tagp.tagname_end - tagp.tagname); 805 if (len > 128) 806 len = 128; 807 vim_strncpy(tag_name, tagp.tagname, len); 808 tag_name[len] = NUL; 809 810 /* Save the tag file name */ 811 p = tag_full_fname(&tagp); 812 if (p == NULL) 813 continue; 814 vim_strncpy(fname, p, MAXPATHL); 815 vim_free(p); 816 817 /* 818 * Get the line number or the search pattern used to locate 819 * the tag. 820 */ 821 lnum = 0; 822 if (isdigit(*tagp.command)) 823 /* Line number is used to locate the tag */ 824 lnum = atol((char *)tagp.command); 825 else 826 { 827 char_u *cmd_start, *cmd_end; 828 829 /* Search pattern is used to locate the tag */ 830 831 /* Locate the end of the command */ 832 cmd_start = tagp.command; 833 cmd_end = tagp.command_end; 834 if (cmd_end == NULL) 835 { 836 for (p = tagp.command; 837 *p && *p != '\r' && *p != '\n'; ++p) 838 ; 839 cmd_end = p; 840 } 841 842 /* 843 * Now, cmd_end points to the character after the 844 * command. Adjust it to point to the last 845 * character of the command. 846 */ 847 cmd_end--; 848 849 /* 850 * Skip the '/' and '?' characters at the 851 * beginning and end of the search pattern. 852 */ 853 if (*cmd_start == '/' || *cmd_start == '?') 854 cmd_start++; 855 856 if (*cmd_end == '/' || *cmd_end == '?') 857 cmd_end--; 858 859 len = 0; 860 cmd[0] = NUL; 861 862 /* 863 * If "^" is present in the tag search pattern, then 864 * copy it first. 865 */ 866 if (*cmd_start == '^') 867 { 868 STRCPY(cmd, "^"); 869 cmd_start++; 870 len++; 871 } 872 873 /* 874 * Precede the tag pattern with \V to make it very 875 * nomagic. 876 */ 877 STRCAT(cmd, "\\V"); 878 len += 2; 879 880 cmd_len = (int)(cmd_end - cmd_start + 1); 881 if (cmd_len > (CMDBUFFSIZE - 5)) 882 cmd_len = CMDBUFFSIZE - 5; 883 STRNCAT(cmd, cmd_start, cmd_len); 884 len += cmd_len; 885 886 if (cmd[len - 1] == '$') 887 { 888 /* 889 * Replace '$' at the end of the search pattern 890 * with '\$' 891 */ 892 cmd[len - 1] = '\\'; 893 cmd[len] = '$'; 894 len++; 895 } 896 897 cmd[len] = NUL; 898 } 899 900 if ((dict = dict_alloc()) == NULL) 901 continue; 902 if (list_append_dict(list, dict) == FAIL) 903 { 904 vim_free(dict); 905 continue; 906 } 907 908 dict_add_string(dict, "text", tag_name); 909 dict_add_string(dict, "filename", fname); 910 dict_add_number(dict, "lnum", lnum); 911 if (lnum == 0) 912 dict_add_string(dict, "pattern", cmd); 913 } 914 915 vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag); 916 set_errorlist(curwin, list, ' ', IObuff, NULL); 917 918 list_free(list); 919 vim_free(fname); 920 vim_free(cmd); 921 922 cur_match = 0; /* Jump to the first tag */ 923 } 924 #endif 925 926 if (ask_for_selection == TRUE) 927 { 928 /* 929 * Ask to select a tag from the list. 930 */ 931 i = prompt_for_number(NULL); 932 if (i <= 0 || i > num_matches || got_int) 933 { 934 /* no valid choice: don't change anything */ 935 if (use_tagstack) 936 { 937 tagstack[tagstackidx].fmark = saved_fmark; 938 tagstackidx = prevtagstackidx; 939 } 940 #ifdef FEAT_CSCOPE 941 cs_free_tags(); 942 jumped_to_tag = TRUE; 943 #endif 944 break; 945 } 946 cur_match = i - 1; 947 } 948 949 if (cur_match >= num_matches) 950 { 951 /* Avoid giving this error when a file wasn't found and we're 952 * looking for a match in another file, which wasn't found. 953 * There will be an emsg("file doesn't exist") below then. */ 954 if ((type == DT_NEXT || type == DT_FIRST) 955 && nofile_fname == NULL) 956 { 957 if (num_matches == 1) 958 emsg(_("E427: There is only one matching tag")); 959 else 960 emsg(_("E428: Cannot go beyond last matching tag")); 961 skip_msg = TRUE; 962 } 963 cur_match = num_matches - 1; 964 } 965 if (use_tagstack) 966 { 967 tagstack[tagstackidx].cur_match = cur_match; 968 tagstack[tagstackidx].cur_fnum = cur_fnum; 969 ++tagstackidx; 970 } 971 #if defined(FEAT_QUICKFIX) 972 else if (g_do_tagpreview != 0) 973 { 974 ptag_entry.cur_match = cur_match; 975 ptag_entry.cur_fnum = cur_fnum; 976 } 977 #endif 978 979 /* 980 * Only when going to try the next match, report that the previous 981 * file didn't exist. Otherwise an emsg() is given below. 982 */ 983 if (nofile_fname != NULL && error_cur_match != cur_match) 984 smsg(_("File \"%s\" does not exist"), nofile_fname); 985 986 987 ic = (matches[cur_match][0] & MT_IC_OFF); 988 if (type != DT_TAG && type != DT_SELECT && type != DT_JUMP 989 #ifdef FEAT_CSCOPE 990 && type != DT_CSCOPE 991 #endif 992 && (num_matches > 1 || ic) 993 && !skip_msg) 994 { 995 /* Give an indication of the number of matching tags */ 996 sprintf((char *)IObuff, _("tag %d of %d%s"), 997 cur_match + 1, 998 num_matches, 999 max_num_matches != MAXCOL ? _(" or more") : ""); 1000 if (ic) 1001 STRCAT(IObuff, _(" Using tag with different case!")); 1002 if ((num_matches > prev_num_matches || new_tag) 1003 && num_matches > 1) 1004 { 1005 if (ic) 1006 msg_attr((char *)IObuff, HL_ATTR(HLF_W)); 1007 else 1008 msg((char *)IObuff); 1009 msg_scroll = TRUE; /* don't overwrite this message */ 1010 } 1011 else 1012 give_warning(IObuff, ic); 1013 if (ic && !msg_scrolled && msg_silent == 0) 1014 { 1015 out_flush(); 1016 ui_delay(1000L, TRUE); 1017 } 1018 } 1019 1020 #if defined(FEAT_EVAL) 1021 /* Let the SwapExists event know what tag we are jumping to. */ 1022 vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name); 1023 set_vim_var_string(VV_SWAPCOMMAND, IObuff, -1); 1024 #endif 1025 1026 /* 1027 * Jump to the desired match. 1028 */ 1029 i = jumpto_tag(matches[cur_match], forceit, type != DT_CSCOPE); 1030 1031 #if defined(FEAT_EVAL) 1032 set_vim_var_string(VV_SWAPCOMMAND, NULL, -1); 1033 #endif 1034 1035 if (i == NOTAGFILE) 1036 { 1037 /* File not found: try again with another matching tag */ 1038 if ((type == DT_PREV && cur_match > 0) 1039 || ((type == DT_TAG || type == DT_NEXT 1040 || type == DT_FIRST) 1041 && (max_num_matches != MAXCOL 1042 || cur_match < num_matches - 1))) 1043 { 1044 error_cur_match = cur_match; 1045 if (use_tagstack) 1046 --tagstackidx; 1047 if (type == DT_PREV) 1048 --cur_match; 1049 else 1050 { 1051 type = DT_NEXT; 1052 ++cur_match; 1053 } 1054 continue; 1055 } 1056 semsg(_("E429: File \"%s\" does not exist"), nofile_fname); 1057 } 1058 else 1059 { 1060 /* We may have jumped to another window, check that 1061 * tagstackidx is still valid. */ 1062 if (use_tagstack && tagstackidx > curwin->w_tagstacklen) 1063 tagstackidx = curwin->w_tagstackidx; 1064 #ifdef FEAT_CSCOPE 1065 jumped_to_tag = TRUE; 1066 #endif 1067 } 1068 } 1069 break; 1070 } 1071 1072 end_do_tag: 1073 /* Only store the new index when using the tagstack and it's valid. */ 1074 if (use_tagstack && tagstackidx <= curwin->w_tagstacklen) 1075 curwin->w_tagstackidx = tagstackidx; 1076 postponed_split = 0; /* don't split next time */ 1077 # ifdef FEAT_QUICKFIX 1078 g_do_tagpreview = 0; /* don't do tag preview next time */ 1079 # endif 1080 1081 #ifdef FEAT_CSCOPE 1082 return jumped_to_tag; 1083 #else 1084 return FALSE; 1085 #endif 1086 } 1087 1088 /* 1089 * Free cached tags. 1090 */ 1091 void 1092 tag_freematch(void) 1093 { 1094 VIM_CLEAR(tagmatchname); 1095 } 1096 1097 static void 1098 taglen_advance(int l) 1099 { 1100 if (l == MAXCOL) 1101 { 1102 msg_putchar('\n'); 1103 msg_advance(24); 1104 } 1105 else 1106 msg_advance(13 + l); 1107 } 1108 1109 /* 1110 * Print the tag stack 1111 */ 1112 void 1113 do_tags(exarg_T *eap UNUSED) 1114 { 1115 int i; 1116 char_u *name; 1117 taggy_T *tagstack = curwin->w_tagstack; 1118 int tagstackidx = curwin->w_tagstackidx; 1119 int tagstacklen = curwin->w_tagstacklen; 1120 1121 /* Highlight title */ 1122 msg_puts_title(_("\n # TO tag FROM line in file/text")); 1123 for (i = 0; i < tagstacklen; ++i) 1124 { 1125 if (tagstack[i].tagname != NULL) 1126 { 1127 name = fm_getname(&(tagstack[i].fmark), 30); 1128 if (name == NULL) /* file name not available */ 1129 continue; 1130 1131 msg_putchar('\n'); 1132 vim_snprintf((char *)IObuff, IOSIZE, "%c%2d %2d %-15s %5ld ", 1133 i == tagstackidx ? '>' : ' ', 1134 i + 1, 1135 tagstack[i].cur_match + 1, 1136 tagstack[i].tagname, 1137 tagstack[i].fmark.mark.lnum); 1138 msg_outtrans(IObuff); 1139 msg_outtrans_attr(name, tagstack[i].fmark.fnum == curbuf->b_fnum 1140 ? HL_ATTR(HLF_D) : 0); 1141 vim_free(name); 1142 } 1143 out_flush(); /* show one line at a time */ 1144 } 1145 if (tagstackidx == tagstacklen) /* idx at top of stack */ 1146 msg_puts("\n>"); 1147 } 1148 1149 /* When not using a CR for line separator, use vim_fgets() to read tag lines. 1150 * For the Mac use tag_fgets(). It can handle any line separator, but is much 1151 * slower than vim_fgets(). 1152 */ 1153 #ifndef USE_CR 1154 # define tag_fgets vim_fgets 1155 #endif 1156 1157 #ifdef FEAT_TAG_BINS 1158 /* 1159 * Compare two strings, for length "len", ignoring case the ASCII way. 1160 * return 0 for match, < 0 for smaller, > 0 for bigger 1161 * Make sure case is folded to uppercase in comparison (like for 'sort -f') 1162 */ 1163 static int 1164 tag_strnicmp(char_u *s1, char_u *s2, size_t len) 1165 { 1166 int i; 1167 1168 while (len > 0) 1169 { 1170 i = (int)TOUPPER_ASC(*s1) - (int)TOUPPER_ASC(*s2); 1171 if (i != 0) 1172 return i; /* this character different */ 1173 if (*s1 == NUL) 1174 break; /* strings match until NUL */ 1175 ++s1; 1176 ++s2; 1177 --len; 1178 } 1179 return 0; /* strings match */ 1180 } 1181 #endif 1182 1183 /* 1184 * Structure to hold info about the tag pattern being used. 1185 */ 1186 typedef struct 1187 { 1188 char_u *pat; /* the pattern */ 1189 int len; /* length of pat[] */ 1190 char_u *head; /* start of pattern head */ 1191 int headlen; /* length of head[] */ 1192 regmatch_T regmatch; /* regexp program, may be NULL */ 1193 } pat_T; 1194 1195 /* 1196 * Extract info from the tag search pattern "pats->pat". 1197 */ 1198 static void 1199 prepare_pats(pat_T *pats, int has_re) 1200 { 1201 pats->head = pats->pat; 1202 pats->headlen = pats->len; 1203 if (has_re) 1204 { 1205 /* When the pattern starts with '^' or "\\<", binary searching can be 1206 * used (much faster). */ 1207 if (pats->pat[0] == '^') 1208 pats->head = pats->pat + 1; 1209 else if (pats->pat[0] == '\\' && pats->pat[1] == '<') 1210 pats->head = pats->pat + 2; 1211 if (pats->head == pats->pat) 1212 pats->headlen = 0; 1213 else 1214 for (pats->headlen = 0; pats->head[pats->headlen] != NUL; 1215 ++pats->headlen) 1216 if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"), 1217 pats->head[pats->headlen]) != NULL) 1218 break; 1219 if (p_tl != 0 && pats->headlen > p_tl) /* adjust for 'taglength' */ 1220 pats->headlen = p_tl; 1221 } 1222 1223 if (has_re) 1224 pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0); 1225 else 1226 pats->regmatch.regprog = NULL; 1227 } 1228 1229 /* 1230 * find_tags() - search for tags in tags files 1231 * 1232 * Return FAIL if search completely failed (*num_matches will be 0, *matchesp 1233 * will be NULL), OK otherwise. 1234 * 1235 * There is a priority in which type of tag is recognized. 1236 * 1237 * 6. A static or global tag with a full matching tag for the current file. 1238 * 5. A global tag with a full matching tag for another file. 1239 * 4. A static tag with a full matching tag for another file. 1240 * 3. A static or global tag with an ignore-case matching tag for the 1241 * current file. 1242 * 2. A global tag with an ignore-case matching tag for another file. 1243 * 1. A static tag with an ignore-case matching tag for another file. 1244 * 1245 * Tags in an emacs-style tags file are always global. 1246 * 1247 * flags: 1248 * TAG_HELP only search for help tags 1249 * TAG_NAMES only return name of tag 1250 * TAG_REGEXP use "pat" as a regexp 1251 * TAG_NOIC don't always ignore case 1252 * TAG_KEEP_LANG keep language 1253 * TAG_CSCOPE use cscope results for tags 1254 */ 1255 int 1256 find_tags( 1257 char_u *pat, /* pattern to search for */ 1258 int *num_matches, /* return: number of matches found */ 1259 char_u ***matchesp, /* return: array of matches found */ 1260 int flags, 1261 int mincount, /* MAXCOL: find all matches 1262 other: minimal number of matches */ 1263 char_u *buf_ffname) /* name of buffer for priority */ 1264 { 1265 FILE *fp; 1266 char_u *lbuf; /* line buffer */ 1267 int lbuf_size = LSIZE; /* length of lbuf */ 1268 char_u *tag_fname; /* name of tag file */ 1269 tagname_T tn; /* info for get_tagfname() */ 1270 int first_file; /* trying first tag file */ 1271 tagptrs_T tagp; 1272 int did_open = FALSE; /* did open a tag file */ 1273 int stop_searching = FALSE; /* stop when match found or error */ 1274 int retval = FAIL; /* return value */ 1275 int is_static; /* current tag line is static */ 1276 int is_current; /* file name matches */ 1277 int eof = FALSE; /* found end-of-file */ 1278 char_u *p; 1279 char_u *s; 1280 int i; 1281 #ifdef FEAT_TAG_BINS 1282 int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */ 1283 struct tag_search_info /* Binary search file offsets */ 1284 { 1285 off_T low_offset; /* offset for first char of first line that 1286 could match */ 1287 off_T high_offset; /* offset of char after last line that could 1288 match */ 1289 off_T curr_offset; /* Current file offset in search range */ 1290 off_T curr_offset_used; /* curr_offset used when skipping back */ 1291 off_T match_offset; /* Where the binary search found a tag */ 1292 int low_char; /* first char at low_offset */ 1293 int high_char; /* first char at high_offset */ 1294 } search_info; 1295 off_T filesize; 1296 int tagcmp; 1297 off_T offset; 1298 int round; 1299 #endif 1300 enum 1301 { 1302 TS_START, /* at start of file */ 1303 TS_LINEAR /* linear searching forward, till EOF */ 1304 #ifdef FEAT_TAG_BINS 1305 , TS_BINARY, /* binary searching */ 1306 TS_SKIP_BACK, /* skipping backwards */ 1307 TS_STEP_FORWARD /* stepping forwards */ 1308 #endif 1309 } state; /* Current search state */ 1310 1311 int cmplen; 1312 int match; /* matches */ 1313 int match_no_ic = 0;/* matches with rm_ic == FALSE */ 1314 int match_re; /* match with regexp */ 1315 int matchoff = 0; 1316 int save_emsg_off; 1317 1318 #ifdef FEAT_EMACS_TAGS 1319 /* 1320 * Stack for included emacs-tags file. 1321 * It has a fixed size, to truncate cyclic includes. jw 1322 */ 1323 # define INCSTACK_SIZE 42 1324 struct 1325 { 1326 FILE *fp; 1327 char_u *etag_fname; 1328 } incstack[INCSTACK_SIZE]; 1329 1330 int incstack_idx = 0; /* index in incstack */ 1331 char_u *ebuf; /* additional buffer for etag fname */ 1332 int is_etag; /* current file is emaces style */ 1333 #endif 1334 1335 char_u *mfp; 1336 garray_T ga_match[MT_COUNT]; /* stores matches in sequence */ 1337 hashtab_T ht_match[MT_COUNT]; /* stores matches by key */ 1338 hash_T hash = 0; 1339 int match_count = 0; /* number of matches found */ 1340 char_u **matches; 1341 int mtt; 1342 int help_save; 1343 #ifdef FEAT_MULTI_LANG 1344 int help_pri = 0; 1345 char_u *help_lang_find = NULL; /* lang to be found */ 1346 char_u help_lang[3]; /* lang of current tags file */ 1347 char_u *saved_pat = NULL; /* copy of pat[] */ 1348 int is_txt = FALSE; /* flag of file extension */ 1349 #endif 1350 1351 pat_T orgpat; /* holds unconverted pattern info */ 1352 vimconv_T vimconv; 1353 1354 #ifdef FEAT_TAG_BINS 1355 int findall = (mincount == MAXCOL || mincount == TAG_MANY); 1356 /* find all matching tags */ 1357 int sort_error = FALSE; /* tags file not sorted */ 1358 int linear; /* do a linear search */ 1359 int sortic = FALSE; /* tag file sorted in nocase */ 1360 #endif 1361 int line_error = FALSE; /* syntax error */ 1362 int has_re = (flags & TAG_REGEXP); /* regexp used */ 1363 int help_only = (flags & TAG_HELP); 1364 int name_only = (flags & TAG_NAMES); 1365 int noic = (flags & TAG_NOIC); 1366 int get_it_again = FALSE; 1367 #ifdef FEAT_CSCOPE 1368 int use_cscope = (flags & TAG_CSCOPE); 1369 #endif 1370 int verbose = (flags & TAG_VERBOSE); 1371 int save_p_ic = p_ic; 1372 1373 /* 1374 * Change the value of 'ignorecase' according to 'tagcase' for the 1375 * duration of this function. 1376 */ 1377 switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) 1378 { 1379 case TC_FOLLOWIC: break; 1380 case TC_IGNORE: p_ic = TRUE; break; 1381 case TC_MATCH: p_ic = FALSE; break; 1382 case TC_FOLLOWSCS: p_ic = ignorecase(pat); break; 1383 case TC_SMART: p_ic = ignorecase_opt(pat, TRUE, TRUE); break; 1384 } 1385 1386 help_save = curbuf->b_help; 1387 orgpat.pat = pat; 1388 vimconv.vc_type = CONV_NONE; 1389 1390 /* 1391 * Allocate memory for the buffers that are used 1392 */ 1393 lbuf = alloc(lbuf_size); 1394 tag_fname = alloc(MAXPATHL + 1); 1395 #ifdef FEAT_EMACS_TAGS 1396 ebuf = alloc(LSIZE); 1397 #endif 1398 for (mtt = 0; mtt < MT_COUNT; ++mtt) 1399 { 1400 ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100); 1401 hash_init(&ht_match[mtt]); 1402 } 1403 1404 /* check for out of memory situation */ 1405 if (lbuf == NULL || tag_fname == NULL 1406 #ifdef FEAT_EMACS_TAGS 1407 || ebuf == NULL 1408 #endif 1409 ) 1410 goto findtag_end; 1411 1412 #ifdef FEAT_CSCOPE 1413 STRCPY(tag_fname, "from cscope"); /* for error messages */ 1414 #endif 1415 1416 /* 1417 * Initialize a few variables 1418 */ 1419 if (help_only) /* want tags from help file */ 1420 curbuf->b_help = TRUE; /* will be restored later */ 1421 #ifdef FEAT_CSCOPE 1422 else if (use_cscope) 1423 { 1424 /* Make sure we don't mix help and cscope, confuses Coverity. */ 1425 help_only = FALSE; 1426 curbuf->b_help = FALSE; 1427 } 1428 #endif 1429 1430 orgpat.len = (int)STRLEN(pat); 1431 #ifdef FEAT_MULTI_LANG 1432 if (curbuf->b_help) 1433 { 1434 /* When "@ab" is specified use only the "ab" language, otherwise 1435 * search all languages. */ 1436 if (orgpat.len > 3 && pat[orgpat.len - 3] == '@' 1437 && ASCII_ISALPHA(pat[orgpat.len - 2]) 1438 && ASCII_ISALPHA(pat[orgpat.len - 1])) 1439 { 1440 saved_pat = vim_strnsave(pat, orgpat.len - 3); 1441 if (saved_pat != NULL) 1442 { 1443 help_lang_find = &pat[orgpat.len - 2]; 1444 orgpat.pat = saved_pat; 1445 orgpat.len -= 3; 1446 } 1447 } 1448 } 1449 #endif 1450 if (p_tl != 0 && orgpat.len > p_tl) /* adjust for 'taglength' */ 1451 orgpat.len = p_tl; 1452 1453 save_emsg_off = emsg_off; 1454 emsg_off = TRUE; /* don't want error for invalid RE here */ 1455 prepare_pats(&orgpat, has_re); 1456 emsg_off = save_emsg_off; 1457 if (has_re && orgpat.regmatch.regprog == NULL) 1458 goto findtag_end; 1459 1460 #ifdef FEAT_TAG_BINS 1461 /* This is only to avoid a compiler warning for using search_info 1462 * uninitialised. */ 1463 vim_memset(&search_info, 0, (size_t)1); 1464 #endif 1465 1466 /* 1467 * When finding a specified number of matches, first try with matching 1468 * case, so binary search can be used, and try ignore-case matches in a 1469 * second loop. 1470 * When finding all matches, 'tagbsearch' is off, or there is no fixed 1471 * string to look for, ignore case right away to avoid going though the 1472 * tags files twice. 1473 * When the tag file is case-fold sorted, it is either one or the other. 1474 * Only ignore case when TAG_NOIC not used or 'ignorecase' set. 1475 */ 1476 #ifdef FEAT_MULTI_LANG 1477 /* Set a flag if the file extension is .txt */ 1478 if ((flags & TAG_KEEP_LANG) 1479 && help_lang_find == NULL 1480 && curbuf->b_fname != NULL 1481 && (i = (int)STRLEN(curbuf->b_fname)) > 4 1482 && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) 1483 is_txt = TRUE; 1484 #endif 1485 #ifdef FEAT_TAG_BINS 1486 orgpat.regmatch.rm_ic = ((p_ic || !noic) 1487 && (findall || orgpat.headlen == 0 || !p_tbs)); 1488 for (round = 1; round <= 2; ++round) 1489 { 1490 linear = (orgpat.headlen == 0 || !p_tbs || round == 2); 1491 #else 1492 orgpat.regmatch.rm_ic = (p_ic || !noic); 1493 #endif 1494 1495 /* 1496 * Try tag file names from tags option one by one. 1497 */ 1498 for (first_file = TRUE; 1499 #ifdef FEAT_CSCOPE 1500 use_cscope || 1501 #endif 1502 get_tagfname(&tn, first_file, tag_fname) == OK; 1503 first_file = FALSE) 1504 { 1505 /* 1506 * A file that doesn't exist is silently ignored. Only when not a 1507 * single file is found, an error message is given (further on). 1508 */ 1509 #ifdef FEAT_CSCOPE 1510 if (use_cscope) 1511 fp = NULL; /* avoid GCC warning */ 1512 else 1513 #endif 1514 { 1515 #ifdef FEAT_MULTI_LANG 1516 if (curbuf->b_help) 1517 { 1518 /* Keep en if the file extension is .txt*/ 1519 if (is_txt) 1520 STRCPY(help_lang, "en"); 1521 else 1522 { 1523 /* Prefer help tags according to 'helplang'. Put the 1524 * two-letter language name in help_lang[]. */ 1525 i = (int)STRLEN(tag_fname); 1526 if (i > 3 && tag_fname[i - 3] == '-') 1527 STRCPY(help_lang, tag_fname + i - 2); 1528 else 1529 STRCPY(help_lang, "en"); 1530 } 1531 /* When searching for a specific language skip tags files 1532 * for other languages. */ 1533 if (help_lang_find != NULL 1534 && STRICMP(help_lang, help_lang_find) != 0) 1535 continue; 1536 1537 /* For CTRL-] in a help file prefer a match with the same 1538 * language. */ 1539 if ((flags & TAG_KEEP_LANG) 1540 && help_lang_find == NULL 1541 && curbuf->b_fname != NULL 1542 && (i = (int)STRLEN(curbuf->b_fname)) > 4 1543 && curbuf->b_fname[i - 1] == 'x' 1544 && curbuf->b_fname[i - 4] == '.' 1545 && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) 1546 help_pri = 0; 1547 else 1548 { 1549 help_pri = 1; 1550 for (s = p_hlg; *s != NUL; ++s) 1551 { 1552 if (STRNICMP(s, help_lang, 2) == 0) 1553 break; 1554 ++help_pri; 1555 if ((s = vim_strchr(s, ',')) == NULL) 1556 break; 1557 } 1558 if (s == NULL || *s == NUL) 1559 { 1560 /* Language not in 'helplang': use last, prefer English, 1561 * unless found already. */ 1562 ++help_pri; 1563 if (STRICMP(help_lang, "en") != 0) 1564 ++help_pri; 1565 } 1566 } 1567 } 1568 #endif 1569 1570 if ((fp = mch_fopen((char *)tag_fname, "r")) == NULL) 1571 continue; 1572 1573 if (p_verbose >= 5) 1574 { 1575 verbose_enter(); 1576 smsg(_("Searching tags file %s"), tag_fname); 1577 verbose_leave(); 1578 } 1579 } 1580 did_open = TRUE; /* remember that we found at least one file */ 1581 1582 state = TS_START; /* we're at the start of the file */ 1583 #ifdef FEAT_EMACS_TAGS 1584 is_etag = 0; /* default is: not emacs style */ 1585 #endif 1586 1587 /* 1588 * Read and parse the lines in the file one by one 1589 */ 1590 for (;;) 1591 { 1592 #ifdef FEAT_TAG_BINS 1593 /* check for CTRL-C typed, more often when jumping around */ 1594 if (state == TS_BINARY || state == TS_SKIP_BACK) 1595 line_breakcheck(); 1596 else 1597 #endif 1598 fast_breakcheck(); 1599 #ifdef FEAT_INS_EXPAND 1600 if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */ 1601 ins_compl_check_keys(30, FALSE); 1602 if (got_int || compl_interrupted) 1603 #else 1604 if (got_int) 1605 #endif 1606 { 1607 stop_searching = TRUE; 1608 break; 1609 } 1610 /* When mincount is TAG_MANY, stop when enough matches have been 1611 * found (for completion). */ 1612 if (mincount == TAG_MANY && match_count >= TAG_MANY) 1613 { 1614 stop_searching = TRUE; 1615 retval = OK; 1616 break; 1617 } 1618 if (get_it_again) 1619 goto line_read_in; 1620 #ifdef FEAT_TAG_BINS 1621 /* 1622 * For binary search: compute the next offset to use. 1623 */ 1624 if (state == TS_BINARY) 1625 { 1626 offset = search_info.low_offset + ((search_info.high_offset 1627 - search_info.low_offset) / 2); 1628 if (offset == search_info.curr_offset) 1629 break; /* End the binary search without a match. */ 1630 else 1631 search_info.curr_offset = offset; 1632 } 1633 1634 /* 1635 * Skipping back (after a match during binary search). 1636 */ 1637 else if (state == TS_SKIP_BACK) 1638 { 1639 search_info.curr_offset -= LSIZE * 2; 1640 if (search_info.curr_offset < 0) 1641 { 1642 search_info.curr_offset = 0; 1643 rewind(fp); 1644 state = TS_STEP_FORWARD; 1645 } 1646 } 1647 1648 /* 1649 * When jumping around in the file, first read a line to find the 1650 * start of the next line. 1651 */ 1652 if (state == TS_BINARY || state == TS_SKIP_BACK) 1653 { 1654 /* Adjust the search file offset to the correct position */ 1655 search_info.curr_offset_used = search_info.curr_offset; 1656 vim_fseek(fp, search_info.curr_offset, SEEK_SET); 1657 eof = tag_fgets(lbuf, LSIZE, fp); 1658 if (!eof && search_info.curr_offset != 0) 1659 { 1660 /* The explicit cast is to work around a bug in gcc 3.4.2 1661 * (repeated below). */ 1662 search_info.curr_offset = vim_ftell(fp); 1663 if (search_info.curr_offset == search_info.high_offset) 1664 { 1665 /* oops, gone a bit too far; try from low offset */ 1666 vim_fseek(fp, search_info.low_offset, SEEK_SET); 1667 search_info.curr_offset = search_info.low_offset; 1668 } 1669 eof = tag_fgets(lbuf, LSIZE, fp); 1670 } 1671 /* skip empty and blank lines */ 1672 while (!eof && vim_isblankline(lbuf)) 1673 { 1674 search_info.curr_offset = vim_ftell(fp); 1675 eof = tag_fgets(lbuf, LSIZE, fp); 1676 } 1677 if (eof) 1678 { 1679 /* Hit end of file. Skip backwards. */ 1680 state = TS_SKIP_BACK; 1681 search_info.match_offset = vim_ftell(fp); 1682 search_info.curr_offset = search_info.curr_offset_used; 1683 continue; 1684 } 1685 } 1686 1687 /* 1688 * Not jumping around in the file: Read the next line. 1689 */ 1690 else 1691 #endif 1692 { 1693 /* skip empty and blank lines */ 1694 do 1695 { 1696 #ifdef FEAT_CSCOPE 1697 if (use_cscope) 1698 eof = cs_fgets(lbuf, LSIZE); 1699 else 1700 #endif 1701 eof = tag_fgets(lbuf, LSIZE, fp); 1702 } while (!eof && vim_isblankline(lbuf)); 1703 1704 if (eof) 1705 { 1706 #ifdef FEAT_EMACS_TAGS 1707 if (incstack_idx) /* this was an included file */ 1708 { 1709 --incstack_idx; 1710 fclose(fp); /* end of this file ... */ 1711 fp = incstack[incstack_idx].fp; 1712 STRCPY(tag_fname, incstack[incstack_idx].etag_fname); 1713 vim_free(incstack[incstack_idx].etag_fname); 1714 is_etag = 1; /* (only etags can include) */ 1715 continue; /* ... continue with parent file */ 1716 } 1717 else 1718 #endif 1719 break; /* end of file */ 1720 } 1721 } 1722 line_read_in: 1723 1724 if (vimconv.vc_type != CONV_NONE) 1725 { 1726 char_u *conv_line; 1727 int len; 1728 1729 /* Convert every line. Converting the pattern from 'enc' to 1730 * the tags file encoding doesn't work, because characters are 1731 * not recognized. */ 1732 conv_line = string_convert(&vimconv, lbuf, NULL); 1733 if (conv_line != NULL) 1734 { 1735 /* Copy or swap lbuf and conv_line. */ 1736 len = (int)STRLEN(conv_line) + 1; 1737 if (len > lbuf_size) 1738 { 1739 vim_free(lbuf); 1740 lbuf = conv_line; 1741 lbuf_size = len; 1742 } 1743 else 1744 { 1745 STRCPY(lbuf, conv_line); 1746 vim_free(conv_line); 1747 } 1748 } 1749 } 1750 1751 1752 #ifdef FEAT_EMACS_TAGS 1753 /* 1754 * Emacs tags line with CTRL-L: New file name on next line. 1755 * The file name is followed by a ','. 1756 * Remember etag file name in ebuf. 1757 */ 1758 if (*lbuf == Ctrl_L 1759 # ifdef FEAT_CSCOPE 1760 && !use_cscope 1761 # endif 1762 ) 1763 { 1764 is_etag = 1; /* in case at the start */ 1765 state = TS_LINEAR; 1766 if (!tag_fgets(ebuf, LSIZE, fp)) 1767 { 1768 for (p = ebuf; *p && *p != ','; p++) 1769 ; 1770 *p = NUL; 1771 1772 /* 1773 * atoi(p+1) is the number of bytes before the next ^L 1774 * unless it is an include statement. 1775 */ 1776 if (STRNCMP(p + 1, "include", 7) == 0 1777 && incstack_idx < INCSTACK_SIZE) 1778 { 1779 /* Save current "fp" and "tag_fname" in the stack. */ 1780 if ((incstack[incstack_idx].etag_fname = 1781 vim_strsave(tag_fname)) != NULL) 1782 { 1783 char_u *fullpath_ebuf; 1784 1785 incstack[incstack_idx].fp = fp; 1786 fp = NULL; 1787 1788 /* Figure out "tag_fname" and "fp" to use for 1789 * included file. */ 1790 fullpath_ebuf = expand_tag_fname(ebuf, 1791 tag_fname, FALSE); 1792 if (fullpath_ebuf != NULL) 1793 { 1794 fp = mch_fopen((char *)fullpath_ebuf, "r"); 1795 if (fp != NULL) 1796 { 1797 if (STRLEN(fullpath_ebuf) > LSIZE) 1798 semsg(_("E430: Tag file path truncated for %s\n"), ebuf); 1799 vim_strncpy(tag_fname, fullpath_ebuf, 1800 MAXPATHL); 1801 ++incstack_idx; 1802 is_etag = 0; /* we can include anything */ 1803 } 1804 vim_free(fullpath_ebuf); 1805 } 1806 if (fp == NULL) 1807 { 1808 /* Can't open the included file, skip it and 1809 * restore old value of "fp". */ 1810 fp = incstack[incstack_idx].fp; 1811 vim_free(incstack[incstack_idx].etag_fname); 1812 } 1813 } 1814 } 1815 } 1816 continue; 1817 } 1818 #endif 1819 1820 /* 1821 * When still at the start of the file, check for Emacs tags file 1822 * format, and for "not sorted" flag. 1823 */ 1824 if (state == TS_START) 1825 { 1826 /* The header ends when the line sorts below "!_TAG_". When 1827 * case is folded lower case letters sort before "_". */ 1828 if (STRNCMP(lbuf, "!_TAG_", 6) <= 0 1829 || (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1]))) 1830 { 1831 if (STRNCMP(lbuf, "!_TAG_", 6) != 0) 1832 /* Non-header item before the header, e.g. "!" itself. 1833 */ 1834 goto parse_line; 1835 1836 /* 1837 * Read header line. 1838 */ 1839 #ifdef FEAT_TAG_BINS 1840 if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) 1841 tag_file_sorted = lbuf[18]; 1842 #endif 1843 if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) 1844 { 1845 /* Prepare to convert every line from the specified 1846 * encoding to 'encoding'. */ 1847 for (p = lbuf + 20; *p > ' ' && *p < 127; ++p) 1848 ; 1849 *p = NUL; 1850 convert_setup(&vimconv, lbuf + 20, p_enc); 1851 } 1852 1853 /* Read the next line. Unrecognized flags are ignored. */ 1854 continue; 1855 } 1856 1857 /* Headers ends. */ 1858 1859 #ifdef FEAT_TAG_BINS 1860 /* 1861 * When there is no tag head, or ignoring case, need to do a 1862 * linear search. 1863 * When no "!_TAG_" is found, default to binary search. If 1864 * the tag file isn't sorted, the second loop will find it. 1865 * When "!_TAG_FILE_SORTED" found: start binary search if 1866 * flag set. 1867 * For cscope, it's always linear. 1868 */ 1869 # ifdef FEAT_CSCOPE 1870 if (linear || use_cscope) 1871 # else 1872 if (linear) 1873 # endif 1874 state = TS_LINEAR; 1875 else if (tag_file_sorted == NUL) 1876 state = TS_BINARY; 1877 else if (tag_file_sorted == '1') 1878 state = TS_BINARY; 1879 else if (tag_file_sorted == '2') 1880 { 1881 state = TS_BINARY; 1882 sortic = TRUE; 1883 orgpat.regmatch.rm_ic = (p_ic || !noic); 1884 } 1885 else 1886 state = TS_LINEAR; 1887 1888 if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic) 1889 { 1890 /* Binary search won't work for ignoring case, use linear 1891 * search. */ 1892 linear = TRUE; 1893 state = TS_LINEAR; 1894 } 1895 #else 1896 state = TS_LINEAR; 1897 #endif 1898 1899 #ifdef FEAT_TAG_BINS 1900 /* 1901 * When starting a binary search, get the size of the file and 1902 * compute the first offset. 1903 */ 1904 if (state == TS_BINARY) 1905 { 1906 /* Get the tag file size (don't use mch_fstat(), it's not 1907 * portable). */ 1908 if ((filesize = vim_lseek(fileno(fp), 1909 (off_T)0L, SEEK_END)) <= 0) 1910 state = TS_LINEAR; 1911 else 1912 { 1913 vim_lseek(fileno(fp), (off_T)0L, SEEK_SET); 1914 1915 /* Calculate the first read offset in the file. Start 1916 * the search in the middle of the file. */ 1917 search_info.low_offset = 0; 1918 search_info.low_char = 0; 1919 search_info.high_offset = filesize; 1920 search_info.curr_offset = 0; 1921 search_info.high_char = 0xff; 1922 } 1923 continue; 1924 } 1925 #endif 1926 } 1927 1928 parse_line: 1929 /* 1930 * Figure out where the different strings are in this line. 1931 * For "normal" tags: Do a quick check if the tag matches. 1932 * This speeds up tag searching a lot! 1933 */ 1934 if (orgpat.headlen 1935 #ifdef FEAT_EMACS_TAGS 1936 && !is_etag 1937 #endif 1938 ) 1939 { 1940 vim_memset(&tagp, 0, sizeof(tagp)); 1941 tagp.tagname = lbuf; 1942 #ifdef FEAT_TAG_ANYWHITE 1943 tagp.tagname_end = skiptowhite(lbuf); 1944 if (*tagp.tagname_end == NUL) 1945 #else 1946 tagp.tagname_end = vim_strchr(lbuf, TAB); 1947 if (tagp.tagname_end == NULL) 1948 #endif 1949 { 1950 if (vim_strchr(lbuf, NL) == NULL) 1951 { 1952 /* Truncated line, ignore it. Has been reported for 1953 * Mozilla JS with extremely long names. */ 1954 if (p_verbose >= 5) 1955 { 1956 verbose_enter(); 1957 msg(_("Ignoring long line in tags file")); 1958 verbose_leave(); 1959 } 1960 #ifdef FEAT_TAG_BINS 1961 if (state != TS_LINEAR) 1962 { 1963 /* Avoid getting stuck. */ 1964 linear = TRUE; 1965 state = TS_LINEAR; 1966 vim_fseek(fp, search_info.low_offset, SEEK_SET); 1967 } 1968 #endif 1969 continue; 1970 } 1971 1972 /* Corrupted tag line. */ 1973 line_error = TRUE; 1974 break; 1975 } 1976 1977 #ifdef FEAT_TAG_OLDSTATIC 1978 /* 1979 * Check for old style static tag: "file:tag file .." 1980 */ 1981 tagp.fname = NULL; 1982 for (p = lbuf; p < tagp.tagname_end; ++p) 1983 { 1984 if (*p == ':') 1985 { 1986 if (tagp.fname == NULL) 1987 # ifdef FEAT_TAG_ANYWHITE 1988 tagp.fname = skipwhite(tagp.tagname_end); 1989 # else 1990 tagp.fname = tagp.tagname_end + 1; 1991 # endif 1992 if ( fnamencmp(lbuf, tagp.fname, p - lbuf) == 0 1993 # ifdef FEAT_TAG_ANYWHITE 1994 && VIM_ISWHITE(tagp.fname[p - lbuf]) 1995 # else 1996 && tagp.fname[p - lbuf] == TAB 1997 # endif 1998 ) 1999 { 2000 /* found one */ 2001 tagp.tagname = p + 1; 2002 break; 2003 } 2004 } 2005 } 2006 #endif 2007 2008 /* 2009 * Skip this line if the length of the tag is different and 2010 * there is no regexp, or the tag is too short. 2011 */ 2012 cmplen = (int)(tagp.tagname_end - tagp.tagname); 2013 if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ 2014 cmplen = p_tl; 2015 if (has_re && orgpat.headlen < cmplen) 2016 cmplen = orgpat.headlen; 2017 else if (state == TS_LINEAR && orgpat.headlen != cmplen) 2018 continue; 2019 2020 #ifdef FEAT_TAG_BINS 2021 if (state == TS_BINARY) 2022 { 2023 /* 2024 * Simplistic check for unsorted tags file. 2025 */ 2026 i = (int)tagp.tagname[0]; 2027 if (sortic) 2028 i = (int)TOUPPER_ASC(tagp.tagname[0]); 2029 if (i < search_info.low_char || i > search_info.high_char) 2030 sort_error = TRUE; 2031 2032 /* 2033 * Compare the current tag with the searched tag. 2034 */ 2035 if (sortic) 2036 tagcmp = tag_strnicmp(tagp.tagname, orgpat.head, 2037 (size_t)cmplen); 2038 else 2039 tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen); 2040 2041 /* 2042 * A match with a shorter tag means to search forward. 2043 * A match with a longer tag means to search backward. 2044 */ 2045 if (tagcmp == 0) 2046 { 2047 if (cmplen < orgpat.headlen) 2048 tagcmp = -1; 2049 else if (cmplen > orgpat.headlen) 2050 tagcmp = 1; 2051 } 2052 2053 if (tagcmp == 0) 2054 { 2055 /* We've located the tag, now skip back and search 2056 * forward until the first matching tag is found. 2057 */ 2058 state = TS_SKIP_BACK; 2059 search_info.match_offset = search_info.curr_offset; 2060 continue; 2061 } 2062 if (tagcmp < 0) 2063 { 2064 search_info.curr_offset = vim_ftell(fp); 2065 if (search_info.curr_offset < search_info.high_offset) 2066 { 2067 search_info.low_offset = search_info.curr_offset; 2068 if (sortic) 2069 search_info.low_char = 2070 TOUPPER_ASC(tagp.tagname[0]); 2071 else 2072 search_info.low_char = tagp.tagname[0]; 2073 continue; 2074 } 2075 } 2076 if (tagcmp > 0 2077 && search_info.curr_offset != search_info.high_offset) 2078 { 2079 search_info.high_offset = search_info.curr_offset; 2080 if (sortic) 2081 search_info.high_char = 2082 TOUPPER_ASC(tagp.tagname[0]); 2083 else 2084 search_info.high_char = tagp.tagname[0]; 2085 continue; 2086 } 2087 2088 /* No match yet and are at the end of the binary search. */ 2089 break; 2090 } 2091 else if (state == TS_SKIP_BACK) 2092 { 2093 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2094 state = TS_STEP_FORWARD; 2095 else 2096 /* Have to skip back more. Restore the curr_offset 2097 * used, otherwise we get stuck at a long line. */ 2098 search_info.curr_offset = search_info.curr_offset_used; 2099 continue; 2100 } 2101 else if (state == TS_STEP_FORWARD) 2102 { 2103 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2104 { 2105 if ((off_T)vim_ftell(fp) > search_info.match_offset) 2106 break; /* past last match */ 2107 else 2108 continue; /* before first match */ 2109 } 2110 } 2111 else 2112 #endif 2113 /* skip this match if it can't match */ 2114 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2115 continue; 2116 2117 /* 2118 * Can be a matching tag, isolate the file name and command. 2119 */ 2120 #ifdef FEAT_TAG_OLDSTATIC 2121 if (tagp.fname == NULL) 2122 #endif 2123 #ifdef FEAT_TAG_ANYWHITE 2124 tagp.fname = skipwhite(tagp.tagname_end); 2125 #else 2126 tagp.fname = tagp.tagname_end + 1; 2127 #endif 2128 #ifdef FEAT_TAG_ANYWHITE 2129 tagp.fname_end = skiptowhite(tagp.fname); 2130 tagp.command = skipwhite(tagp.fname_end); 2131 if (*tagp.command == NUL) 2132 #else 2133 tagp.fname_end = vim_strchr(tagp.fname, TAB); 2134 tagp.command = tagp.fname_end + 1; 2135 if (tagp.fname_end == NULL) 2136 #endif 2137 i = FAIL; 2138 else 2139 i = OK; 2140 } 2141 else 2142 i = parse_tag_line(lbuf, 2143 #ifdef FEAT_EMACS_TAGS 2144 is_etag, 2145 #endif 2146 &tagp); 2147 if (i == FAIL) 2148 { 2149 line_error = TRUE; 2150 break; 2151 } 2152 2153 #ifdef FEAT_EMACS_TAGS 2154 if (is_etag) 2155 tagp.fname = ebuf; 2156 #endif 2157 /* 2158 * First try matching with the pattern literally (also when it is 2159 * a regexp). 2160 */ 2161 cmplen = (int)(tagp.tagname_end - tagp.tagname); 2162 if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ 2163 cmplen = p_tl; 2164 /* if tag length does not match, don't try comparing */ 2165 if (orgpat.len != cmplen) 2166 match = FALSE; 2167 else 2168 { 2169 if (orgpat.regmatch.rm_ic) 2170 { 2171 match = (MB_STRNICMP(tagp.tagname, orgpat.pat, cmplen) == 0); 2172 if (match) 2173 match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat, 2174 cmplen) == 0); 2175 } 2176 else 2177 match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0); 2178 } 2179 2180 /* 2181 * Has a regexp: Also find tags matching regexp. 2182 */ 2183 match_re = FALSE; 2184 if (!match && orgpat.regmatch.regprog != NULL) 2185 { 2186 int cc; 2187 2188 cc = *tagp.tagname_end; 2189 *tagp.tagname_end = NUL; 2190 match = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0); 2191 if (match) 2192 { 2193 matchoff = (int)(orgpat.regmatch.startp[0] - tagp.tagname); 2194 if (orgpat.regmatch.rm_ic) 2195 { 2196 orgpat.regmatch.rm_ic = FALSE; 2197 match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname, 2198 (colnr_T)0); 2199 orgpat.regmatch.rm_ic = TRUE; 2200 } 2201 } 2202 *tagp.tagname_end = cc; 2203 match_re = TRUE; 2204 } 2205 2206 /* 2207 * If a match is found, add it to ht_match[] and ga_match[]. 2208 */ 2209 if (match) 2210 { 2211 int len = 0; 2212 2213 #ifdef FEAT_CSCOPE 2214 if (use_cscope) 2215 { 2216 /* Don't change the ordering, always use the same table. */ 2217 mtt = MT_GL_OTH; 2218 } 2219 else 2220 #endif 2221 { 2222 /* Decide in which array to store this match. */ 2223 is_current = test_for_current( 2224 #ifdef FEAT_EMACS_TAGS 2225 is_etag, 2226 #endif 2227 tagp.fname, tagp.fname_end, tag_fname, 2228 buf_ffname); 2229 #ifdef FEAT_EMACS_TAGS 2230 is_static = FALSE; 2231 if (!is_etag) /* emacs tags are never static */ 2232 #endif 2233 { 2234 #ifdef FEAT_TAG_OLDSTATIC 2235 if (tagp.tagname != lbuf) 2236 is_static = TRUE; /* detected static tag before */ 2237 else 2238 #endif 2239 is_static = test_for_static(&tagp); 2240 } 2241 2242 /* decide in which of the sixteen tables to store this 2243 * match */ 2244 if (is_static) 2245 { 2246 if (is_current) 2247 mtt = MT_ST_CUR; 2248 else 2249 mtt = MT_ST_OTH; 2250 } 2251 else 2252 { 2253 if (is_current) 2254 mtt = MT_GL_CUR; 2255 else 2256 mtt = MT_GL_OTH; 2257 } 2258 if (orgpat.regmatch.rm_ic && !match_no_ic) 2259 mtt += MT_IC_OFF; 2260 if (match_re) 2261 mtt += MT_RE_OFF; 2262 } 2263 2264 /* 2265 * Add the found match in ht_match[mtt] and ga_match[mtt]. 2266 * Store the info we need later, which depends on the kind of 2267 * tags we are dealing with. 2268 */ 2269 if (help_only) 2270 { 2271 #ifdef FEAT_MULTI_LANG 2272 # define ML_EXTRA 3 2273 #else 2274 # define ML_EXTRA 0 2275 #endif 2276 /* 2277 * Append the help-heuristic number after the tagname, for 2278 * sorting it later. The heuristic is ignored for 2279 * detecting duplicates. 2280 * The format is {tagname}@{lang}NUL{heuristic}NUL 2281 */ 2282 *tagp.tagname_end = NUL; 2283 len = (int)(tagp.tagname_end - tagp.tagname); 2284 mfp = (char_u *)alloc((int)sizeof(char_u) 2285 + len + 10 + ML_EXTRA + 1); 2286 if (mfp != NULL) 2287 { 2288 int heuristic; 2289 2290 p = mfp; 2291 STRCPY(p, tagp.tagname); 2292 #ifdef FEAT_MULTI_LANG 2293 p[len] = '@'; 2294 STRCPY(p + len + 1, help_lang); 2295 #endif 2296 2297 heuristic = help_heuristic(tagp.tagname, 2298 match_re ? matchoff : 0, !match_no_ic); 2299 #ifdef FEAT_MULTI_LANG 2300 heuristic += help_pri; 2301 #endif 2302 sprintf((char *)p + len + 1 + ML_EXTRA, "%06d", 2303 heuristic); 2304 } 2305 *tagp.tagname_end = TAB; 2306 } 2307 else if (name_only) 2308 { 2309 if (get_it_again) 2310 { 2311 char_u *temp_end = tagp.command; 2312 2313 if (*temp_end == '/') 2314 while (*temp_end && *temp_end != '\r' 2315 && *temp_end != '\n' 2316 && *temp_end != '$') 2317 temp_end++; 2318 2319 if (tagp.command + 2 < temp_end) 2320 { 2321 len = (int)(temp_end - tagp.command - 2); 2322 mfp = (char_u *)alloc(len + 2); 2323 if (mfp != NULL) 2324 vim_strncpy(mfp, tagp.command + 2, len); 2325 } 2326 else 2327 mfp = NULL; 2328 get_it_again = FALSE; 2329 } 2330 else 2331 { 2332 len = (int)(tagp.tagname_end - tagp.tagname); 2333 mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1); 2334 if (mfp != NULL) 2335 vim_strncpy(mfp, tagp.tagname, len); 2336 2337 /* if wanted, re-read line to get long form too */ 2338 if (State & INSERT) 2339 get_it_again = p_sft; 2340 } 2341 } 2342 else 2343 { 2344 #define TAG_SEP 0x02 2345 size_t tag_fname_len = STRLEN(tag_fname); 2346 #ifdef FEAT_EMACS_TAGS 2347 size_t ebuf_len = 0; 2348 #endif 2349 2350 /* Save the tag in a buffer. 2351 * Use 0x02 to separate fields (Can't use NUL because the 2352 * hash key is terminated by NUL, or Ctrl_A because that is 2353 * part of some Emacs tag files -- see parse_tag_line). 2354 * Emacs tag: <mtt><tag_fname><0x02><ebuf><0x02><lbuf><NUL> 2355 * other tag: <mtt><tag_fname><0x02><0x02><lbuf><NUL> 2356 * without Emacs tags: <mtt><tag_fname><0x02><lbuf><NUL> 2357 * Here <mtt> is the "mtt" value plus 1 to avoid NUL. 2358 */ 2359 len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3; 2360 #ifdef FEAT_EMACS_TAGS 2361 if (is_etag) 2362 { 2363 ebuf_len = STRLEN(ebuf); 2364 len += (int)ebuf_len + 1; 2365 } 2366 else 2367 ++len; 2368 #endif 2369 mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1); 2370 if (mfp != NULL) 2371 { 2372 p = mfp; 2373 p[0] = mtt + 1; 2374 STRCPY(p + 1, tag_fname); 2375 #ifdef BACKSLASH_IN_FILENAME 2376 /* Ignore differences in slashes, avoid adding 2377 * both path/file and path\file. */ 2378 slash_adjust(p + 1); 2379 #endif 2380 p[tag_fname_len + 1] = TAG_SEP; 2381 s = p + 1 + tag_fname_len + 1; 2382 #ifdef FEAT_EMACS_TAGS 2383 if (is_etag) 2384 { 2385 STRCPY(s, ebuf); 2386 s[ebuf_len] = TAG_SEP; 2387 s += ebuf_len + 1; 2388 } 2389 else 2390 *s++ = TAG_SEP; 2391 #endif 2392 STRCPY(s, lbuf); 2393 } 2394 } 2395 2396 if (mfp != NULL) 2397 { 2398 hashitem_T *hi; 2399 2400 /* 2401 * Don't add identical matches. 2402 * Add all cscope tags, because they are all listed. 2403 * "mfp" is used as a hash key, there is a NUL byte to end 2404 * the part matters for comparing, more bytes may follow 2405 * after it. E.g. help tags store the priority after the 2406 * NUL. 2407 */ 2408 #ifdef FEAT_CSCOPE 2409 if (use_cscope) 2410 hash++; 2411 else 2412 #endif 2413 hash = hash_hash(mfp); 2414 hi = hash_lookup(&ht_match[mtt], mfp, hash); 2415 if (HASHITEM_EMPTY(hi)) 2416 { 2417 if (hash_add_item(&ht_match[mtt], hi, mfp, hash) 2418 == FAIL 2419 || ga_grow(&ga_match[mtt], 1) != OK) 2420 { 2421 /* Out of memory! Just forget about the rest. */ 2422 retval = OK; 2423 stop_searching = TRUE; 2424 break; 2425 } 2426 else 2427 { 2428 ((char_u **)(ga_match[mtt].ga_data)) 2429 [ga_match[mtt].ga_len++] = mfp; 2430 ++match_count; 2431 } 2432 } 2433 else 2434 /* duplicate tag, drop it */ 2435 vim_free(mfp); 2436 } 2437 } 2438 #ifdef FEAT_CSCOPE 2439 if (use_cscope && eof) 2440 break; 2441 #endif 2442 } /* forever */ 2443 2444 if (line_error) 2445 { 2446 semsg(_("E431: Format error in tags file \"%s\""), tag_fname); 2447 #ifdef FEAT_CSCOPE 2448 if (!use_cscope) 2449 #endif 2450 semsg(_("Before byte %ld"), (long)vim_ftell(fp)); 2451 stop_searching = TRUE; 2452 line_error = FALSE; 2453 } 2454 2455 #ifdef FEAT_CSCOPE 2456 if (!use_cscope) 2457 #endif 2458 fclose(fp); 2459 #ifdef FEAT_EMACS_TAGS 2460 while (incstack_idx) 2461 { 2462 --incstack_idx; 2463 fclose(incstack[incstack_idx].fp); 2464 vim_free(incstack[incstack_idx].etag_fname); 2465 } 2466 #endif 2467 if (vimconv.vc_type != CONV_NONE) 2468 convert_setup(&vimconv, NULL, NULL); 2469 2470 #ifdef FEAT_TAG_BINS 2471 tag_file_sorted = NUL; 2472 if (sort_error) 2473 { 2474 semsg(_("E432: Tags file not sorted: %s"), tag_fname); 2475 sort_error = FALSE; 2476 } 2477 #endif 2478 2479 /* 2480 * Stop searching if sufficient tags have been found. 2481 */ 2482 if (match_count >= mincount) 2483 { 2484 retval = OK; 2485 stop_searching = TRUE; 2486 } 2487 2488 #ifdef FEAT_CSCOPE 2489 if (stop_searching || use_cscope) 2490 #else 2491 if (stop_searching) 2492 #endif 2493 break; 2494 2495 } /* end of for-each-file loop */ 2496 2497 #ifdef FEAT_CSCOPE 2498 if (!use_cscope) 2499 #endif 2500 tagname_free(&tn); 2501 2502 #ifdef FEAT_TAG_BINS 2503 /* stop searching when already did a linear search, or when TAG_NOIC 2504 * used, and 'ignorecase' not set or already did case-ignore search */ 2505 if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) 2506 break; 2507 # ifdef FEAT_CSCOPE 2508 if (use_cscope) 2509 break; 2510 # endif 2511 orgpat.regmatch.rm_ic = TRUE; /* try another time while ignoring case */ 2512 } 2513 #endif 2514 2515 if (!stop_searching) 2516 { 2517 if (!did_open && verbose) /* never opened any tags file */ 2518 emsg(_("E433: No tags file")); 2519 retval = OK; /* It's OK even when no tag found */ 2520 } 2521 2522 findtag_end: 2523 vim_free(lbuf); 2524 vim_regfree(orgpat.regmatch.regprog); 2525 vim_free(tag_fname); 2526 #ifdef FEAT_EMACS_TAGS 2527 vim_free(ebuf); 2528 #endif 2529 2530 /* 2531 * Move the matches from the ga_match[] arrays into one list of 2532 * matches. When retval == FAIL, free the matches. 2533 */ 2534 if (retval == FAIL) 2535 match_count = 0; 2536 2537 if (match_count > 0) 2538 matches = (char_u **)lalloc((long_u)(match_count * sizeof(char_u *)), 2539 TRUE); 2540 else 2541 matches = NULL; 2542 match_count = 0; 2543 for (mtt = 0; mtt < MT_COUNT; ++mtt) 2544 { 2545 for (i = 0; i < ga_match[mtt].ga_len; ++i) 2546 { 2547 mfp = ((char_u **)(ga_match[mtt].ga_data))[i]; 2548 if (matches == NULL) 2549 vim_free(mfp); 2550 else 2551 { 2552 if (!name_only) 2553 { 2554 /* Change mtt back to zero-based. */ 2555 *mfp = *mfp - 1; 2556 2557 /* change the TAG_SEP back to NUL */ 2558 for (p = mfp + 1; *p != NUL; ++p) 2559 if (*p == TAG_SEP) 2560 *p = NUL; 2561 } 2562 matches[match_count++] = (char_u *)mfp; 2563 } 2564 } 2565 2566 ga_clear(&ga_match[mtt]); 2567 hash_clear(&ht_match[mtt]); 2568 } 2569 2570 *matchesp = matches; 2571 *num_matches = match_count; 2572 2573 curbuf->b_help = help_save; 2574 #ifdef FEAT_MULTI_LANG 2575 vim_free(saved_pat); 2576 #endif 2577 2578 p_ic = save_p_ic; 2579 2580 return retval; 2581 } 2582 2583 static garray_T tag_fnames = GA_EMPTY; 2584 2585 /* 2586 * Callback function for finding all "tags" and "tags-??" files in 2587 * 'runtimepath' doc directories. 2588 */ 2589 static void 2590 found_tagfile_cb(char_u *fname, void *cookie UNUSED) 2591 { 2592 if (ga_grow(&tag_fnames, 1) == OK) 2593 { 2594 char_u *tag_fname = vim_strsave(fname); 2595 2596 #ifdef BACKSLASH_IN_FILENAME 2597 slash_adjust(tag_fname); 2598 #endif 2599 simplify_filename(tag_fname); 2600 ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = tag_fname; 2601 } 2602 } 2603 2604 #if defined(EXITFREE) || defined(PROTO) 2605 void 2606 free_tag_stuff(void) 2607 { 2608 ga_clear_strings(&tag_fnames); 2609 do_tag(NULL, DT_FREE, 0, 0, 0); 2610 tag_freematch(); 2611 2612 # if defined(FEAT_QUICKFIX) 2613 if (ptag_entry.tagname) 2614 VIM_CLEAR(ptag_entry.tagname); 2615 # endif 2616 } 2617 #endif 2618 2619 /* 2620 * Get the next name of a tag file from the tag file list. 2621 * For help files, use "tags" file only. 2622 * 2623 * Return FAIL if no more tag file names, OK otherwise. 2624 */ 2625 int 2626 get_tagfname( 2627 tagname_T *tnp, /* holds status info */ 2628 int first, /* TRUE when first file name is wanted */ 2629 char_u *buf) /* pointer to buffer of MAXPATHL chars */ 2630 { 2631 char_u *fname = NULL; 2632 char_u *r_ptr; 2633 int i; 2634 2635 if (first) 2636 vim_memset(tnp, 0, sizeof(tagname_T)); 2637 2638 if (curbuf->b_help) 2639 { 2640 /* 2641 * For help files it's done in a completely different way: 2642 * Find "doc/tags" and "doc/tags-??" in all directories in 2643 * 'runtimepath'. 2644 */ 2645 if (first) 2646 { 2647 ga_clear_strings(&tag_fnames); 2648 ga_init2(&tag_fnames, (int)sizeof(char_u *), 10); 2649 do_in_runtimepath((char_u *) 2650 #ifdef FEAT_MULTI_LANG 2651 # ifdef VMS 2652 /* Functions decc$to_vms() and decc$translate_vms() crash 2653 * on some VMS systems with wildcards "??". Seems ECO 2654 * patches do fix the problem in C RTL, but we can't use 2655 * an #ifdef for that. */ 2656 "doc/tags doc/tags-*" 2657 # else 2658 "doc/tags doc/tags-??" 2659 # endif 2660 #else 2661 "doc/tags" 2662 #endif 2663 , DIP_ALL, found_tagfile_cb, NULL); 2664 } 2665 2666 if (tnp->tn_hf_idx >= tag_fnames.ga_len) 2667 { 2668 /* Not found in 'runtimepath', use 'helpfile', if it exists and 2669 * wasn't used yet, replacing "help.txt" with "tags". */ 2670 if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) 2671 return FAIL; 2672 ++tnp->tn_hf_idx; 2673 STRCPY(buf, p_hf); 2674 STRCPY(gettail(buf), "tags"); 2675 #ifdef BACKSLASH_IN_FILENAME 2676 slash_adjust(buf); 2677 #endif 2678 simplify_filename(buf); 2679 2680 for (i = 0; i < tag_fnames.ga_len; ++i) 2681 if (STRCMP(buf, ((char_u **)(tag_fnames.ga_data))[i]) == 0) 2682 return FAIL; // avoid duplicate file names 2683 } 2684 else 2685 vim_strncpy(buf, ((char_u **)(tag_fnames.ga_data))[ 2686 tnp->tn_hf_idx++], MAXPATHL - 1); 2687 return OK; 2688 } 2689 2690 if (first) 2691 { 2692 /* Init. We make a copy of 'tags', because autocommands may change 2693 * the value without notifying us. */ 2694 tnp->tn_tags = vim_strsave((*curbuf->b_p_tags != NUL) 2695 ? curbuf->b_p_tags : p_tags); 2696 if (tnp->tn_tags == NULL) 2697 return FAIL; 2698 tnp->tn_np = tnp->tn_tags; 2699 } 2700 2701 /* 2702 * Loop until we have found a file name that can be used. 2703 * There are two states: 2704 * tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'. 2705 * tnp->tn_did_filefind_init == TRUE: find next file in this part. 2706 */ 2707 for (;;) 2708 { 2709 if (tnp->tn_did_filefind_init) 2710 { 2711 fname = vim_findfile(tnp->tn_search_ctx); 2712 if (fname != NULL) 2713 break; 2714 2715 tnp->tn_did_filefind_init = FALSE; 2716 } 2717 else 2718 { 2719 char_u *filename = NULL; 2720 2721 /* Stop when used all parts of 'tags'. */ 2722 if (*tnp->tn_np == NUL) 2723 { 2724 vim_findfile_cleanup(tnp->tn_search_ctx); 2725 tnp->tn_search_ctx = NULL; 2726 return FAIL; 2727 } 2728 2729 /* 2730 * Copy next file name into buf. 2731 */ 2732 buf[0] = NUL; 2733 (void)copy_option_part(&tnp->tn_np, buf, MAXPATHL - 1, " ,"); 2734 2735 #ifdef FEAT_PATH_EXTRA 2736 r_ptr = vim_findfile_stopdir(buf); 2737 #else 2738 r_ptr = NULL; 2739 #endif 2740 /* move the filename one char forward and truncate the 2741 * filepath with a NUL */ 2742 filename = gettail(buf); 2743 STRMOVE(filename + 1, filename); 2744 *filename++ = NUL; 2745 2746 tnp->tn_search_ctx = vim_findfile_init(buf, filename, 2747 r_ptr, 100, 2748 FALSE, /* don't free visited list */ 2749 FINDFILE_FILE, /* we search for a file */ 2750 tnp->tn_search_ctx, TRUE, curbuf->b_ffname); 2751 if (tnp->tn_search_ctx != NULL) 2752 tnp->tn_did_filefind_init = TRUE; 2753 } 2754 } 2755 2756 STRCPY(buf, fname); 2757 vim_free(fname); 2758 return OK; 2759 } 2760 2761 /* 2762 * Free the contents of a tagname_T that was filled by get_tagfname(). 2763 */ 2764 void 2765 tagname_free(tagname_T *tnp) 2766 { 2767 vim_free(tnp->tn_tags); 2768 vim_findfile_cleanup(tnp->tn_search_ctx); 2769 tnp->tn_search_ctx = NULL; 2770 ga_clear_strings(&tag_fnames); 2771 } 2772 2773 /* 2774 * Parse one line from the tags file. Find start/end of tag name, start/end of 2775 * file name and start of search pattern. 2776 * 2777 * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set. 2778 * 2779 * Return FAIL if there is a format error in this line, OK otherwise. 2780 */ 2781 static int 2782 parse_tag_line( 2783 char_u *lbuf, /* line to be parsed */ 2784 #ifdef FEAT_EMACS_TAGS 2785 int is_etag, 2786 #endif 2787 tagptrs_T *tagp) 2788 { 2789 char_u *p; 2790 2791 #ifdef FEAT_EMACS_TAGS 2792 char_u *p_7f; 2793 2794 if (is_etag) 2795 { 2796 /* 2797 * There are two formats for an emacs tag line: 2798 * 1: struct EnvBase ^?EnvBase^A139,4627 2799 * 2: #define ARPB_WILD_WORLD ^?153,5194 2800 */ 2801 p_7f = vim_strchr(lbuf, 0x7f); 2802 if (p_7f == NULL) 2803 { 2804 etag_fail: 2805 if (vim_strchr(lbuf, '\n') == NULL) 2806 { 2807 /* Truncated line. Ignore it. */ 2808 if (p_verbose >= 5) 2809 { 2810 verbose_enter(); 2811 msg(_("Ignoring long line in tags file")); 2812 verbose_leave(); 2813 } 2814 tagp->command = lbuf; 2815 tagp->tagname = lbuf; 2816 tagp->tagname_end = lbuf; 2817 return OK; 2818 } 2819 return FAIL; 2820 } 2821 2822 /* Find ^A. If not found the line number is after the 0x7f */ 2823 p = vim_strchr(p_7f, Ctrl_A); 2824 if (p == NULL) 2825 p = p_7f + 1; 2826 else 2827 ++p; 2828 2829 if (!VIM_ISDIGIT(*p)) /* check for start of line number */ 2830 goto etag_fail; 2831 tagp->command = p; 2832 2833 2834 if (p[-1] == Ctrl_A) /* first format: explicit tagname given */ 2835 { 2836 tagp->tagname = p_7f + 1; 2837 tagp->tagname_end = p - 1; 2838 } 2839 else /* second format: isolate tagname */ 2840 { 2841 /* find end of tagname */ 2842 for (p = p_7f - 1; !vim_iswordc(*p); --p) 2843 if (p == lbuf) 2844 goto etag_fail; 2845 tagp->tagname_end = p + 1; 2846 while (p >= lbuf && vim_iswordc(*p)) 2847 --p; 2848 tagp->tagname = p + 1; 2849 } 2850 } 2851 else /* not an Emacs tag */ 2852 { 2853 #endif 2854 /* Isolate the tagname, from lbuf up to the first white */ 2855 tagp->tagname = lbuf; 2856 #ifdef FEAT_TAG_ANYWHITE 2857 p = skiptowhite(lbuf); 2858 #else 2859 p = vim_strchr(lbuf, TAB); 2860 if (p == NULL) 2861 return FAIL; 2862 #endif 2863 tagp->tagname_end = p; 2864 2865 /* Isolate file name, from first to second white space */ 2866 #ifdef FEAT_TAG_ANYWHITE 2867 p = skipwhite(p); 2868 #else 2869 if (*p != NUL) 2870 ++p; 2871 #endif 2872 tagp->fname = p; 2873 #ifdef FEAT_TAG_ANYWHITE 2874 p = skiptowhite(p); 2875 #else 2876 p = vim_strchr(p, TAB); 2877 if (p == NULL) 2878 return FAIL; 2879 #endif 2880 tagp->fname_end = p; 2881 2882 /* find start of search command, after second white space */ 2883 #ifdef FEAT_TAG_ANYWHITE 2884 p = skipwhite(p); 2885 #else 2886 if (*p != NUL) 2887 ++p; 2888 #endif 2889 if (*p == NUL) 2890 return FAIL; 2891 tagp->command = p; 2892 #ifdef FEAT_EMACS_TAGS 2893 } 2894 #endif 2895 2896 return OK; 2897 } 2898 2899 /* 2900 * Check if tagname is a static tag 2901 * 2902 * Static tags produced by the older ctags program have the format: 2903 * 'file:tag file /pattern'. 2904 * This is only recognized when both occurrence of 'file' are the same, to 2905 * avoid recognizing "string::string" or ":exit". 2906 * 2907 * Static tags produced by the new ctags program have the format: 2908 * 'tag file /pattern/;"<Tab>file:' " 2909 * 2910 * Return TRUE if it is a static tag and adjust *tagname to the real tag. 2911 * Return FALSE if it is not a static tag. 2912 */ 2913 static int 2914 test_for_static(tagptrs_T *tagp) 2915 { 2916 char_u *p; 2917 2918 #ifdef FEAT_TAG_OLDSTATIC 2919 int len; 2920 2921 /* 2922 * Check for old style static tag: "file:tag file .." 2923 */ 2924 len = (int)(tagp->fname_end - tagp->fname); 2925 p = tagp->tagname + len; 2926 if ( p < tagp->tagname_end 2927 && *p == ':' 2928 && fnamencmp(tagp->tagname, tagp->fname, len) == 0) 2929 { 2930 tagp->tagname = p + 1; 2931 return TRUE; 2932 } 2933 #endif 2934 2935 /* 2936 * Check for new style static tag ":...<Tab>file:[<Tab>...]" 2937 */ 2938 p = tagp->command; 2939 while ((p = vim_strchr(p, '\t')) != NULL) 2940 { 2941 ++p; 2942 if (STRNCMP(p, "file:", 5) == 0) 2943 return TRUE; 2944 } 2945 2946 return FALSE; 2947 } 2948 2949 /* 2950 * Returns the length of a matching tag line. 2951 */ 2952 static size_t 2953 matching_line_len(char_u *lbuf) 2954 { 2955 char_u *p = lbuf + 1; 2956 2957 /* does the same thing as parse_match() */ 2958 p += STRLEN(p) + 1; 2959 #ifdef FEAT_EMACS_TAGS 2960 p += STRLEN(p) + 1; 2961 #endif 2962 return (p - lbuf) + STRLEN(p); 2963 } 2964 2965 /* 2966 * Parse a line from a matching tag. Does not change the line itself. 2967 * 2968 * The line that we get looks like this: 2969 * Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf> 2970 * other tag: <mtt><tag_fname><NUL><NUL><lbuf> 2971 * without Emacs tags: <mtt><tag_fname><NUL><lbuf> 2972 * 2973 * Return OK or FAIL. 2974 */ 2975 static int 2976 parse_match( 2977 char_u *lbuf, /* input: matching line */ 2978 tagptrs_T *tagp) /* output: pointers into the line */ 2979 { 2980 int retval; 2981 char_u *p; 2982 char_u *pc, *pt; 2983 2984 tagp->tag_fname = lbuf + 1; 2985 lbuf += STRLEN(tagp->tag_fname) + 2; 2986 #ifdef FEAT_EMACS_TAGS 2987 if (*lbuf) 2988 { 2989 tagp->is_etag = TRUE; 2990 tagp->fname = lbuf; 2991 lbuf += STRLEN(lbuf); 2992 tagp->fname_end = lbuf++; 2993 } 2994 else 2995 { 2996 tagp->is_etag = FALSE; 2997 ++lbuf; 2998 } 2999 #endif 3000 3001 /* Find search pattern and the file name for non-etags. */ 3002 retval = parse_tag_line(lbuf, 3003 #ifdef FEAT_EMACS_TAGS 3004 tagp->is_etag, 3005 #endif 3006 tagp); 3007 3008 tagp->tagkind = NULL; 3009 tagp->command_end = NULL; 3010 3011 if (retval == OK) 3012 { 3013 /* Try to find a kind field: "kind:<kind>" or just "<kind>"*/ 3014 p = tagp->command; 3015 if (find_extra(&p) == OK) 3016 { 3017 tagp->command_end = p; 3018 p += 2; /* skip ";\"" */ 3019 if (*p++ == TAB) 3020 while (ASCII_ISALPHA(*p)) 3021 { 3022 if (STRNCMP(p, "kind:", 5) == 0) 3023 { 3024 tagp->tagkind = p + 5; 3025 break; 3026 } 3027 pc = vim_strchr(p, ':'); 3028 pt = vim_strchr(p, '\t'); 3029 if (pc == NULL || (pt != NULL && pc > pt)) 3030 { 3031 tagp->tagkind = p; 3032 break; 3033 } 3034 if (pt == NULL) 3035 break; 3036 p = pt + 1; 3037 } 3038 } 3039 if (tagp->tagkind != NULL) 3040 { 3041 for (p = tagp->tagkind; 3042 *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p) 3043 ; 3044 tagp->tagkind_end = p; 3045 } 3046 } 3047 return retval; 3048 } 3049 3050 /* 3051 * Find out the actual file name of a tag. Concatenate the tags file name 3052 * with the matching tag file name. 3053 * Returns an allocated string or NULL (out of memory). 3054 */ 3055 static char_u * 3056 tag_full_fname(tagptrs_T *tagp) 3057 { 3058 char_u *fullname; 3059 int c; 3060 3061 #ifdef FEAT_EMACS_TAGS 3062 if (tagp->is_etag) 3063 c = 0; /* to shut up GCC */ 3064 else 3065 #endif 3066 { 3067 c = *tagp->fname_end; 3068 *tagp->fname_end = NUL; 3069 } 3070 fullname = expand_tag_fname(tagp->fname, tagp->tag_fname, FALSE); 3071 3072 #ifdef FEAT_EMACS_TAGS 3073 if (!tagp->is_etag) 3074 #endif 3075 *tagp->fname_end = c; 3076 3077 return fullname; 3078 } 3079 3080 /* 3081 * Jump to a tag that has been found in one of the tag files 3082 * 3083 * returns OK for success, NOTAGFILE when file not found, FAIL otherwise. 3084 */ 3085 static int 3086 jumpto_tag( 3087 char_u *lbuf_arg, /* line from the tags file for this tag */ 3088 int forceit, /* :ta with ! */ 3089 int keep_help) /* keep help flag (FALSE for cscope) */ 3090 { 3091 int save_secure; 3092 int save_magic; 3093 int save_p_ws, save_p_scs, save_p_ic; 3094 linenr_T save_lnum; 3095 char_u *str; 3096 char_u *pbuf; /* search pattern buffer */ 3097 char_u *pbuf_end; 3098 char_u *tofree_fname = NULL; 3099 char_u *fname; 3100 tagptrs_T tagp; 3101 int retval = FAIL; 3102 int getfile_result = GETFILE_UNUSED; 3103 int search_options; 3104 #ifdef FEAT_SEARCH_EXTRA 3105 int save_no_hlsearch; 3106 #endif 3107 #if defined(FEAT_QUICKFIX) 3108 win_T *curwin_save = NULL; 3109 #endif 3110 char_u *full_fname = NULL; 3111 #ifdef FEAT_FOLDING 3112 int old_KeyTyped = KeyTyped; /* getting the file may reset it */ 3113 #endif 3114 size_t len; 3115 char_u *lbuf; 3116 3117 /* Make a copy of the line, it can become invalid when an autocommand calls 3118 * back here recursively. */ 3119 len = matching_line_len(lbuf_arg) + 1; 3120 lbuf = alloc((int)len); 3121 if (lbuf != NULL) 3122 mch_memmove(lbuf, lbuf_arg, len); 3123 3124 pbuf = alloc(LSIZE); 3125 3126 /* parse the match line into the tagp structure */ 3127 if (pbuf == NULL || lbuf == NULL || parse_match(lbuf, &tagp) == FAIL) 3128 { 3129 tagp.fname_end = NULL; 3130 goto erret; 3131 } 3132 3133 /* truncate the file name, so it can be used as a string */ 3134 *tagp.fname_end = NUL; 3135 fname = tagp.fname; 3136 3137 /* copy the command to pbuf[], remove trailing CR/NL */ 3138 str = tagp.command; 3139 for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) 3140 { 3141 #ifdef FEAT_EMACS_TAGS 3142 if (tagp.is_etag && *str == ',')/* stop at ',' after line number */ 3143 break; 3144 #endif 3145 *pbuf_end++ = *str++; 3146 } 3147 *pbuf_end = NUL; 3148 3149 #ifdef FEAT_EMACS_TAGS 3150 if (!tagp.is_etag) 3151 #endif 3152 { 3153 /* 3154 * Remove the "<Tab>fieldname:value" stuff; we don't need it here. 3155 */ 3156 str = pbuf; 3157 if (find_extra(&str) == OK) 3158 { 3159 pbuf_end = str; 3160 *pbuf_end = NUL; 3161 } 3162 } 3163 3164 /* 3165 * Expand file name, when needed (for environment variables). 3166 * If 'tagrelative' option set, may change file name. 3167 */ 3168 fname = expand_tag_fname(fname, tagp.tag_fname, TRUE); 3169 if (fname == NULL) 3170 goto erret; 3171 tofree_fname = fname; /* free() it later */ 3172 3173 /* 3174 * Check if the file with the tag exists before abandoning the current 3175 * file. Also accept a file name for which there is a matching BufReadCmd 3176 * autocommand event (e.g., http://sys/file). 3177 */ 3178 if (mch_getperm(fname) < 0 && !has_autocmd(EVENT_BUFREADCMD, fname, NULL)) 3179 { 3180 retval = NOTAGFILE; 3181 vim_free(nofile_fname); 3182 nofile_fname = vim_strsave(fname); 3183 if (nofile_fname == NULL) 3184 nofile_fname = empty_option; 3185 goto erret; 3186 } 3187 3188 ++RedrawingDisabled; 3189 3190 #ifdef FEAT_GUI 3191 need_mouse_correct = TRUE; 3192 #endif 3193 3194 #if defined(FEAT_QUICKFIX) 3195 if (g_do_tagpreview != 0) 3196 { 3197 postponed_split = 0; /* don't split again below */ 3198 curwin_save = curwin; /* Save current window */ 3199 3200 /* 3201 * If we are reusing a window, we may change dir when 3202 * entering it (autocommands) so turn the tag filename 3203 * into a fullpath 3204 */ 3205 if (!curwin->w_p_pvw) 3206 { 3207 full_fname = FullName_save(fname, FALSE); 3208 fname = full_fname; 3209 3210 /* 3211 * Make the preview window the current window. 3212 * Open a preview window when needed. 3213 */ 3214 prepare_tagpreview(TRUE); 3215 } 3216 } 3217 3218 /* If it was a CTRL-W CTRL-] command split window now. For ":tab tag" 3219 * open a new tab page. */ 3220 if (postponed_split && (swb_flags & (SWB_USEOPEN | SWB_USETAB))) 3221 { 3222 buf_T *existing_buf = buflist_findname_exp(fname); 3223 3224 if (existing_buf != NULL) 3225 { 3226 win_T *wp = NULL; 3227 3228 if (swb_flags & SWB_USEOPEN) 3229 wp = buf_jump_open_win(existing_buf); 3230 3231 /* If 'switchbuf' contains "usetab": jump to first window in any tab 3232 * page containing "existing_buf" if one exists */ 3233 if (wp == NULL && (swb_flags & SWB_USETAB)) 3234 wp = buf_jump_open_tab(existing_buf); 3235 /* We've switched to the buffer, the usual loading of the file must 3236 * be skipped. */ 3237 if (wp != NULL) 3238 getfile_result = GETFILE_SAME_FILE; 3239 } 3240 } 3241 if (getfile_result == GETFILE_UNUSED 3242 && (postponed_split || cmdmod.tab != 0)) 3243 { 3244 if (win_split(postponed_split > 0 ? postponed_split : 0, 3245 postponed_split_flags) == FAIL) 3246 { 3247 --RedrawingDisabled; 3248 goto erret; 3249 } 3250 RESET_BINDING(curwin); 3251 } 3252 #endif 3253 3254 if (keep_help) 3255 { 3256 /* A :ta from a help file will keep the b_help flag set. For ":ptag" 3257 * we need to use the flag from the window where we came from. */ 3258 #if defined(FEAT_QUICKFIX) 3259 if (g_do_tagpreview != 0) 3260 keep_help_flag = bt_help(curwin_save->w_buffer); 3261 else 3262 #endif 3263 keep_help_flag = curbuf->b_help; 3264 } 3265 3266 if (getfile_result == GETFILE_UNUSED) 3267 /* Careful: getfile() may trigger autocommands and call jumpto_tag() 3268 * recursively. */ 3269 getfile_result = getfile(0, fname, NULL, TRUE, (linenr_T)0, forceit); 3270 keep_help_flag = FALSE; 3271 3272 if (GETFILE_SUCCESS(getfile_result)) /* got to the right file */ 3273 { 3274 curwin->w_set_curswant = TRUE; 3275 postponed_split = 0; 3276 3277 save_secure = secure; 3278 secure = 1; 3279 #ifdef HAVE_SANDBOX 3280 ++sandbox; 3281 #endif 3282 save_magic = p_magic; 3283 p_magic = FALSE; /* always execute with 'nomagic' */ 3284 #ifdef FEAT_SEARCH_EXTRA 3285 /* Save value of no_hlsearch, jumping to a tag is not a real search */ 3286 save_no_hlsearch = no_hlsearch; 3287 #endif 3288 3289 /* 3290 * If 'cpoptions' contains 't', store the search pattern for the "n" 3291 * command. If 'cpoptions' does not contain 't', the search pattern 3292 * is not stored. 3293 */ 3294 if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) 3295 search_options = 0; 3296 else 3297 search_options = SEARCH_KEEP; 3298 3299 /* 3300 * If the command is a search, try here. 3301 * 3302 * Reset 'smartcase' for the search, since the search pattern was not 3303 * typed by the user. 3304 * Only use do_search() when there is a full search command, without 3305 * anything following. 3306 */ 3307 str = pbuf; 3308 if (pbuf[0] == '/' || pbuf[0] == '?') 3309 str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1; 3310 if (str > pbuf_end - 1) /* search command with nothing following */ 3311 { 3312 save_p_ws = p_ws; 3313 save_p_ic = p_ic; 3314 save_p_scs = p_scs; 3315 p_ws = TRUE; /* need 'wrapscan' for backward searches */ 3316 p_ic = FALSE; /* don't ignore case now */ 3317 p_scs = FALSE; 3318 #if 0 /* disabled for now */ 3319 #ifdef FEAT_CMDHIST 3320 /* put pattern in search history */ 3321 add_to_history(HIST_SEARCH, pbuf + 1, TRUE, pbuf[0]); 3322 #endif 3323 #endif 3324 save_lnum = curwin->w_cursor.lnum; 3325 curwin->w_cursor.lnum = 0; /* start search before first line */ 3326 if (do_search(NULL, pbuf[0], pbuf + 1, (long)1, 3327 search_options, NULL, NULL)) 3328 retval = OK; 3329 else 3330 { 3331 int found = 1; 3332 int cc; 3333 3334 /* 3335 * try again, ignore case now 3336 */ 3337 p_ic = TRUE; 3338 if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1, 3339 search_options, NULL, NULL)) 3340 { 3341 /* 3342 * Failed to find pattern, take a guess: "^func (" 3343 */ 3344 found = 2; 3345 (void)test_for_static(&tagp); 3346 cc = *tagp.tagname_end; 3347 *tagp.tagname_end = NUL; 3348 sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname); 3349 if (!do_search(NULL, '/', pbuf, (long)1, 3350 search_options, NULL, NULL)) 3351 { 3352 /* Guess again: "^char * \<func (" */ 3353 sprintf((char *)pbuf, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(", 3354 tagp.tagname); 3355 if (!do_search(NULL, '/', pbuf, (long)1, 3356 search_options, NULL, NULL)) 3357 found = 0; 3358 } 3359 *tagp.tagname_end = cc; 3360 } 3361 if (found == 0) 3362 { 3363 emsg(_("E434: Can't find tag pattern")); 3364 curwin->w_cursor.lnum = save_lnum; 3365 } 3366 else 3367 { 3368 /* 3369 * Only give a message when really guessed, not when 'ic' 3370 * is set and match found while ignoring case. 3371 */ 3372 if (found == 2 || !save_p_ic) 3373 { 3374 msg(_("E435: Couldn't find tag, just guessing!")); 3375 if (!msg_scrolled && msg_silent == 0) 3376 { 3377 out_flush(); 3378 ui_delay(1000L, TRUE); 3379 } 3380 } 3381 retval = OK; 3382 } 3383 } 3384 p_ws = save_p_ws; 3385 p_ic = save_p_ic; 3386 p_scs = save_p_scs; 3387 3388 /* A search command may have positioned the cursor beyond the end 3389 * of the line. May need to correct that here. */ 3390 check_cursor(); 3391 } 3392 else 3393 { 3394 curwin->w_cursor.lnum = 1; /* start command in line 1 */ 3395 do_cmdline_cmd(pbuf); 3396 retval = OK; 3397 } 3398 3399 /* 3400 * When the command has done something that is not allowed make sure 3401 * the error message can be seen. 3402 */ 3403 if (secure == 2) 3404 wait_return(TRUE); 3405 secure = save_secure; 3406 p_magic = save_magic; 3407 #ifdef HAVE_SANDBOX 3408 --sandbox; 3409 #endif 3410 #ifdef FEAT_SEARCH_EXTRA 3411 /* restore no_hlsearch when keeping the old search pattern */ 3412 if (search_options) 3413 set_no_hlsearch(save_no_hlsearch); 3414 #endif 3415 3416 /* Return OK if jumped to another file (at least we found the file!). */ 3417 if (getfile_result == GETFILE_OPEN_OTHER) 3418 retval = OK; 3419 3420 if (retval == OK) 3421 { 3422 /* 3423 * For a help buffer: Put the cursor line at the top of the window, 3424 * the help subject will be below it. 3425 */ 3426 if (curbuf->b_help) 3427 set_topline(curwin, curwin->w_cursor.lnum); 3428 #ifdef FEAT_FOLDING 3429 if ((fdo_flags & FDO_TAG) && old_KeyTyped) 3430 foldOpenCursor(); 3431 #endif 3432 } 3433 3434 #if defined(FEAT_QUICKFIX) 3435 if (g_do_tagpreview != 0 3436 && curwin != curwin_save && win_valid(curwin_save)) 3437 { 3438 /* Return cursor to where we were */ 3439 validate_cursor(); 3440 redraw_later(VALID); 3441 win_enter(curwin_save, TRUE); 3442 } 3443 #endif 3444 3445 --RedrawingDisabled; 3446 } 3447 else 3448 { 3449 --RedrawingDisabled; 3450 if (postponed_split) /* close the window */ 3451 { 3452 win_close(curwin, FALSE); 3453 postponed_split = 0; 3454 } 3455 } 3456 3457 erret: 3458 #if defined(FEAT_QUICKFIX) 3459 g_do_tagpreview = 0; /* For next time */ 3460 #endif 3461 vim_free(lbuf); 3462 vim_free(pbuf); 3463 vim_free(tofree_fname); 3464 vim_free(full_fname); 3465 3466 return retval; 3467 } 3468 3469 /* 3470 * If "expand" is TRUE, expand wildcards in fname. 3471 * If 'tagrelative' option set, change fname (name of file containing tag) 3472 * according to tag_fname (name of tag file containing fname). 3473 * Returns a pointer to allocated memory (or NULL when out of memory). 3474 */ 3475 static char_u * 3476 expand_tag_fname(char_u *fname, char_u *tag_fname, int expand) 3477 { 3478 char_u *p; 3479 char_u *retval; 3480 char_u *expanded_fname = NULL; 3481 expand_T xpc; 3482 3483 /* 3484 * Expand file name (for environment variables) when needed. 3485 */ 3486 if (expand && mch_has_wildcard(fname)) 3487 { 3488 ExpandInit(&xpc); 3489 xpc.xp_context = EXPAND_FILES; 3490 expanded_fname = ExpandOne(&xpc, (char_u *)fname, NULL, 3491 WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); 3492 if (expanded_fname != NULL) 3493 fname = expanded_fname; 3494 } 3495 3496 if ((p_tr || curbuf->b_help) 3497 && !vim_isAbsName(fname) 3498 && (p = gettail(tag_fname)) != tag_fname) 3499 { 3500 retval = alloc(MAXPATHL); 3501 if (retval != NULL) 3502 { 3503 STRCPY(retval, tag_fname); 3504 vim_strncpy(retval + (p - tag_fname), fname, 3505 MAXPATHL - (p - tag_fname) - 1); 3506 /* 3507 * Translate names like "src/a/../b/file.c" into "src/b/file.c". 3508 */ 3509 simplify_filename(retval); 3510 } 3511 } 3512 else 3513 retval = vim_strsave(fname); 3514 3515 vim_free(expanded_fname); 3516 3517 return retval; 3518 } 3519 3520 /* 3521 * Converts a file name into a canonical form. It simplifies a file name into 3522 * its simplest form by stripping out unneeded components, if any. The 3523 * resulting file name is simplified in place and will either be the same 3524 * length as that supplied, or shorter. 3525 */ 3526 void 3527 simplify_filename(char_u *filename) 3528 { 3529 #ifndef AMIGA /* Amiga doesn't have "..", it uses "/" */ 3530 int components = 0; 3531 char_u *p, *tail, *start; 3532 int stripping_disabled = FALSE; 3533 int relative = TRUE; 3534 3535 p = filename; 3536 #ifdef BACKSLASH_IN_FILENAME 3537 if (p[1] == ':') /* skip "x:" */ 3538 p += 2; 3539 #endif 3540 3541 if (vim_ispathsep(*p)) 3542 { 3543 relative = FALSE; 3544 do 3545 ++p; 3546 while (vim_ispathsep(*p)); 3547 } 3548 start = p; /* remember start after "c:/" or "/" or "///" */ 3549 3550 do 3551 { 3552 /* At this point "p" is pointing to the char following a single "/" 3553 * or "p" is at the "start" of the (absolute or relative) path name. */ 3554 #ifdef VMS 3555 /* VMS allows device:[path] - don't strip the [ in directory */ 3556 if ((*p == '[' || *p == '<') && p > filename && p[-1] == ':') 3557 { 3558 /* :[ or :< composition: vms directory component */ 3559 ++components; 3560 p = getnextcomp(p + 1); 3561 } 3562 /* allow remote calls as host"user passwd"::device:[path] */ 3563 else if (p[0] == ':' && p[1] == ':' && p > filename && p[-1] == '"' ) 3564 { 3565 /* ":: composition: vms host/passwd component */ 3566 ++components; 3567 p = getnextcomp(p + 2); 3568 } 3569 else 3570 #endif 3571 if (vim_ispathsep(*p)) 3572 STRMOVE(p, p + 1); /* remove duplicate "/" */ 3573 else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL)) 3574 { 3575 if (p == start && relative) 3576 p += 1 + (p[1] != NUL); /* keep single "." or leading "./" */ 3577 else 3578 { 3579 /* Strip "./" or ".///". If we are at the end of the file name 3580 * and there is no trailing path separator, either strip "/." if 3581 * we are after "start", or strip "." if we are at the beginning 3582 * of an absolute path name . */ 3583 tail = p + 1; 3584 if (p[1] != NUL) 3585 while (vim_ispathsep(*tail)) 3586 MB_PTR_ADV(tail); 3587 else if (p > start) 3588 --p; /* strip preceding path separator */ 3589 STRMOVE(p, tail); 3590 } 3591 } 3592 else if (p[0] == '.' && p[1] == '.' && 3593 (vim_ispathsep(p[2]) || p[2] == NUL)) 3594 { 3595 /* Skip to after ".." or "../" or "..///". */ 3596 tail = p + 2; 3597 while (vim_ispathsep(*tail)) 3598 MB_PTR_ADV(tail); 3599 3600 if (components > 0) /* strip one preceding component */ 3601 { 3602 int do_strip = FALSE; 3603 char_u saved_char; 3604 stat_T st; 3605 3606 /* Don't strip for an erroneous file name. */ 3607 if (!stripping_disabled) 3608 { 3609 /* If the preceding component does not exist in the file 3610 * system, we strip it. On Unix, we don't accept a symbolic 3611 * link that refers to a non-existent file. */ 3612 saved_char = p[-1]; 3613 p[-1] = NUL; 3614 #ifdef UNIX 3615 if (mch_lstat((char *)filename, &st) < 0) 3616 #else 3617 if (mch_stat((char *)filename, &st) < 0) 3618 #endif 3619 do_strip = TRUE; 3620 p[-1] = saved_char; 3621 3622 --p; 3623 /* Skip back to after previous '/'. */ 3624 while (p > start && !after_pathsep(start, p)) 3625 MB_PTR_BACK(start, p); 3626 3627 if (!do_strip) 3628 { 3629 /* If the component exists in the file system, check 3630 * that stripping it won't change the meaning of the 3631 * file name. First get information about the 3632 * unstripped file name. This may fail if the component 3633 * to strip is not a searchable directory (but a regular 3634 * file, for instance), since the trailing "/.." cannot 3635 * be applied then. We don't strip it then since we 3636 * don't want to replace an erroneous file name by 3637 * a valid one, and we disable stripping of later 3638 * components. */ 3639 saved_char = *tail; 3640 *tail = NUL; 3641 if (mch_stat((char *)filename, &st) >= 0) 3642 do_strip = TRUE; 3643 else 3644 stripping_disabled = TRUE; 3645 *tail = saved_char; 3646 #ifdef UNIX 3647 if (do_strip) 3648 { 3649 stat_T new_st; 3650 3651 /* On Unix, the check for the unstripped file name 3652 * above works also for a symbolic link pointing to 3653 * a searchable directory. But then the parent of 3654 * the directory pointed to by the link must be the 3655 * same as the stripped file name. (The latter 3656 * exists in the file system since it is the 3657 * component's parent directory.) */ 3658 if (p == start && relative) 3659 (void)mch_stat(".", &new_st); 3660 else 3661 { 3662 saved_char = *p; 3663 *p = NUL; 3664 (void)mch_stat((char *)filename, &new_st); 3665 *p = saved_char; 3666 } 3667 3668 if (new_st.st_ino != st.st_ino || 3669 new_st.st_dev != st.st_dev) 3670 { 3671 do_strip = FALSE; 3672 /* We don't disable stripping of later 3673 * components since the unstripped path name is 3674 * still valid. */ 3675 } 3676 } 3677 #endif 3678 } 3679 } 3680 3681 if (!do_strip) 3682 { 3683 /* Skip the ".." or "../" and reset the counter for the 3684 * components that might be stripped later on. */ 3685 p = tail; 3686 components = 0; 3687 } 3688 else 3689 { 3690 /* Strip previous component. If the result would get empty 3691 * and there is no trailing path separator, leave a single 3692 * "." instead. If we are at the end of the file name and 3693 * there is no trailing path separator and a preceding 3694 * component is left after stripping, strip its trailing 3695 * path separator as well. */ 3696 if (p == start && relative && tail[-1] == '.') 3697 { 3698 *p++ = '.'; 3699 *p = NUL; 3700 } 3701 else 3702 { 3703 if (p > start && tail[-1] == '.') 3704 --p; 3705 STRMOVE(p, tail); /* strip previous component */ 3706 } 3707 3708 --components; 3709 } 3710 } 3711 else if (p == start && !relative) /* leading "/.." or "/../" */ 3712 STRMOVE(p, tail); /* strip ".." or "../" */ 3713 else 3714 { 3715 if (p == start + 2 && p[-2] == '.') /* leading "./../" */ 3716 { 3717 STRMOVE(p - 2, p); /* strip leading "./" */ 3718 tail -= 2; 3719 } 3720 p = tail; /* skip to char after ".." or "../" */ 3721 } 3722 } 3723 else 3724 { 3725 ++components; /* simple path component */ 3726 p = getnextcomp(p); 3727 } 3728 } while (*p != NUL); 3729 #endif /* !AMIGA */ 3730 } 3731 3732 /* 3733 * Check if we have a tag for the buffer with name "buf_ffname". 3734 * This is a bit slow, because of the full path compare in fullpathcmp(). 3735 * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current 3736 * file. 3737 */ 3738 static int 3739 test_for_current( 3740 #ifdef FEAT_EMACS_TAGS 3741 int is_etag, 3742 #endif 3743 char_u *fname, 3744 char_u *fname_end, 3745 char_u *tag_fname, 3746 char_u *buf_ffname) 3747 { 3748 int c; 3749 int retval = FALSE; 3750 char_u *fullname; 3751 3752 if (buf_ffname != NULL) /* if the buffer has a name */ 3753 { 3754 #ifdef FEAT_EMACS_TAGS 3755 if (is_etag) 3756 c = 0; /* to shut up GCC */ 3757 else 3758 #endif 3759 { 3760 c = *fname_end; 3761 *fname_end = NUL; 3762 } 3763 fullname = expand_tag_fname(fname, tag_fname, TRUE); 3764 if (fullname != NULL) 3765 { 3766 retval = (fullpathcmp(fullname, buf_ffname, TRUE) & FPC_SAME); 3767 vim_free(fullname); 3768 } 3769 #ifdef FEAT_EMACS_TAGS 3770 if (!is_etag) 3771 #endif 3772 *fname_end = c; 3773 } 3774 3775 return retval; 3776 } 3777 3778 /* 3779 * Find the end of the tagaddress. 3780 * Return OK if ";\"" is following, FAIL otherwise. 3781 */ 3782 static int 3783 find_extra(char_u **pp) 3784 { 3785 char_u *str = *pp; 3786 3787 /* Repeat for addresses separated with ';' */ 3788 for (;;) 3789 { 3790 if (VIM_ISDIGIT(*str)) 3791 str = skipdigits(str); 3792 else if (*str == '/' || *str == '?') 3793 { 3794 str = skip_regexp(str + 1, *str, FALSE, NULL); 3795 if (*str != **pp) 3796 str = NULL; 3797 else 3798 ++str; 3799 } 3800 else 3801 str = NULL; 3802 if (str == NULL || *str != ';' 3803 || !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?')) 3804 break; 3805 ++str; /* skip ';' */ 3806 } 3807 3808 if (str != NULL && STRNCMP(str, ";\"", 2) == 0) 3809 { 3810 *pp = str; 3811 return OK; 3812 } 3813 return FAIL; 3814 } 3815 3816 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 3817 int 3818 expand_tags( 3819 int tagnames, /* expand tag names */ 3820 char_u *pat, 3821 int *num_file, 3822 char_u ***file) 3823 { 3824 int i; 3825 int c; 3826 int tagnmflag; 3827 char_u tagnm[100]; 3828 tagptrs_T t_p; 3829 int ret; 3830 3831 if (tagnames) 3832 tagnmflag = TAG_NAMES; 3833 else 3834 tagnmflag = 0; 3835 if (pat[0] == '/') 3836 ret = find_tags(pat + 1, num_file, file, 3837 TAG_REGEXP | tagnmflag | TAG_VERBOSE, 3838 TAG_MANY, curbuf->b_ffname); 3839 else 3840 ret = find_tags(pat, num_file, file, 3841 TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NOIC, 3842 TAG_MANY, curbuf->b_ffname); 3843 if (ret == OK && !tagnames) 3844 { 3845 /* Reorganize the tags for display and matching as strings of: 3846 * "<tagname>\0<kind>\0<filename>\0" 3847 */ 3848 for (i = 0; i < *num_file; i++) 3849 { 3850 parse_match((*file)[i], &t_p); 3851 c = (int)(t_p.tagname_end - t_p.tagname); 3852 mch_memmove(tagnm, t_p.tagname, (size_t)c); 3853 tagnm[c++] = 0; 3854 tagnm[c++] = (t_p.tagkind != NULL && *t_p.tagkind) 3855 ? *t_p.tagkind : 'f'; 3856 tagnm[c++] = 0; 3857 mch_memmove((*file)[i] + c, t_p.fname, t_p.fname_end - t_p.fname); 3858 (*file)[i][c + (t_p.fname_end - t_p.fname)] = 0; 3859 mch_memmove((*file)[i], tagnm, (size_t)c); 3860 } 3861 } 3862 return ret; 3863 } 3864 #endif 3865 3866 #if defined(FEAT_EVAL) || defined(PROTO) 3867 /* 3868 * Add a tag field to the dictionary "dict". 3869 * Return OK or FAIL. 3870 */ 3871 static int 3872 add_tag_field( 3873 dict_T *dict, 3874 char *field_name, 3875 char_u *start, /* start of the value */ 3876 char_u *end) /* after the value; can be NULL */ 3877 { 3878 char_u *buf; 3879 int len = 0; 3880 int retval; 3881 3882 /* check that the field name doesn't exist yet */ 3883 if (dict_find(dict, (char_u *)field_name, -1) != NULL) 3884 { 3885 if (p_verbose > 0) 3886 { 3887 verbose_enter(); 3888 smsg(_("Duplicate field name: %s"), field_name); 3889 verbose_leave(); 3890 } 3891 return FAIL; 3892 } 3893 buf = alloc(MAXPATHL); 3894 if (buf == NULL) 3895 return FAIL; 3896 if (start != NULL) 3897 { 3898 if (end == NULL) 3899 { 3900 end = start + STRLEN(start); 3901 while (end > start && (end[-1] == '\r' || end[-1] == '\n')) 3902 --end; 3903 } 3904 len = (int)(end - start); 3905 if (len > MAXPATHL - 1) 3906 len = MAXPATHL - 1; 3907 vim_strncpy(buf, start, len); 3908 } 3909 buf[len] = NUL; 3910 retval = dict_add_string(dict, field_name, buf); 3911 vim_free(buf); 3912 return retval; 3913 } 3914 3915 /* 3916 * Add the tags matching the specified pattern "pat" to the list "list" 3917 * as a dictionary. Use "buf_fname" for priority, unless NULL. 3918 */ 3919 int 3920 get_tags(list_T *list, char_u *pat, char_u *buf_fname) 3921 { 3922 int num_matches, i, ret; 3923 char_u **matches, *p; 3924 char_u *full_fname; 3925 dict_T *dict; 3926 tagptrs_T tp; 3927 long is_static; 3928 3929 ret = find_tags(pat, &num_matches, &matches, 3930 TAG_REGEXP | TAG_NOIC, (int)MAXCOL, buf_fname); 3931 if (ret == OK && num_matches > 0) 3932 { 3933 for (i = 0; i < num_matches; ++i) 3934 { 3935 parse_match(matches[i], &tp); 3936 is_static = test_for_static(&tp); 3937 3938 /* Skip pseudo-tag lines. */ 3939 if (STRNCMP(tp.tagname, "!_TAG_", 6) == 0) 3940 continue; 3941 3942 if ((dict = dict_alloc()) == NULL) 3943 ret = FAIL; 3944 if (list_append_dict(list, dict) == FAIL) 3945 ret = FAIL; 3946 3947 full_fname = tag_full_fname(&tp); 3948 if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL 3949 || add_tag_field(dict, "filename", full_fname, 3950 NULL) == FAIL 3951 || add_tag_field(dict, "cmd", tp.command, 3952 tp.command_end) == FAIL 3953 || add_tag_field(dict, "kind", tp.tagkind, 3954 tp.tagkind_end) == FAIL 3955 || dict_add_number(dict, "static", is_static) == FAIL) 3956 ret = FAIL; 3957 3958 vim_free(full_fname); 3959 3960 if (tp.command_end != NULL) 3961 { 3962 for (p = tp.command_end + 3; 3963 *p != NUL && *p != '\n' && *p != '\r'; ++p) 3964 { 3965 if (p == tp.tagkind || (p + 5 == tp.tagkind 3966 && STRNCMP(p, "kind:", 5) == 0)) 3967 /* skip "kind:<kind>" and "<kind>" */ 3968 p = tp.tagkind_end - 1; 3969 else if (STRNCMP(p, "file:", 5) == 0) 3970 /* skip "file:" (static tag) */ 3971 p += 4; 3972 else if (!VIM_ISWHITE(*p)) 3973 { 3974 char_u *s, *n; 3975 int len; 3976 3977 /* Add extra field as a dict entry. Fields are 3978 * separated by Tabs. */ 3979 n = p; 3980 while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') 3981 ++p; 3982 len = (int)(p - n); 3983 if (*p == ':' && len > 0) 3984 { 3985 s = ++p; 3986 while (*p != NUL && *p >= ' ') 3987 ++p; 3988 n[len] = NUL; 3989 if (add_tag_field(dict, (char *)n, s, p) == FAIL) 3990 ret = FAIL; 3991 n[len] = ':'; 3992 } 3993 else 3994 /* Skip field without colon. */ 3995 while (*p != NUL && *p >= ' ') 3996 ++p; 3997 if (*p == NUL) 3998 break; 3999 } 4000 } 4001 } 4002 4003 vim_free(matches[i]); 4004 } 4005 vim_free(matches); 4006 } 4007 return ret; 4008 } 4009 4010 /* 4011 * Return information about 'tag' in dict 'retdict'. 4012 */ 4013 static void 4014 get_tag_details(taggy_T *tag, dict_T *retdict) 4015 { 4016 list_T *pos; 4017 fmark_T *fmark; 4018 4019 dict_add_string(retdict, "tagname", tag->tagname); 4020 dict_add_number(retdict, "matchnr", tag->cur_match + 1); 4021 dict_add_number(retdict, "bufnr", tag->cur_fnum); 4022 4023 if ((pos = list_alloc_id(aid_tagstack_from)) == NULL) 4024 return; 4025 dict_add_list(retdict, "from", pos); 4026 4027 fmark = &tag->fmark; 4028 list_append_number(pos, 4029 (varnumber_T)(fmark->fnum != -1 ? fmark->fnum : 0)); 4030 list_append_number(pos, (varnumber_T)fmark->mark.lnum); 4031 list_append_number(pos, (varnumber_T)(fmark->mark.col == MAXCOL ? 4032 MAXCOL : fmark->mark.col + 1)); 4033 list_append_number(pos, (varnumber_T)fmark->mark.coladd); 4034 } 4035 4036 /* 4037 * Return the tag stack entries of the specified window 'wp' in dictionary 4038 * 'retdict'. 4039 */ 4040 void 4041 get_tagstack(win_T *wp, dict_T *retdict) 4042 { 4043 list_T *l; 4044 int i; 4045 dict_T *d; 4046 4047 dict_add_number(retdict, "length", wp->w_tagstacklen); 4048 dict_add_number(retdict, "curidx", wp->w_tagstackidx + 1); 4049 l = list_alloc_id(aid_tagstack_items); 4050 if (l == NULL) 4051 return; 4052 dict_add_list(retdict, "items", l); 4053 4054 for (i = 0; i < wp->w_tagstacklen; i++) 4055 { 4056 if ((d = dict_alloc_id(aid_tagstack_details)) == NULL) 4057 return; 4058 list_append_dict(l, d); 4059 4060 get_tag_details(&wp->w_tagstack[i], d); 4061 } 4062 } 4063 4064 /* 4065 * Free all the entries in the tag stack of the specified window 4066 */ 4067 static void 4068 tagstack_clear(win_T *wp) 4069 { 4070 int i; 4071 4072 // Free the current tag stack 4073 for (i = 0; i < wp->w_tagstacklen; ++i) 4074 vim_free(wp->w_tagstack[i].tagname); 4075 wp->w_tagstacklen = 0; 4076 wp->w_tagstackidx = 0; 4077 } 4078 4079 /* 4080 * Remove the oldest entry from the tag stack and shift the rest of 4081 * the entires to free up the top of the stack. 4082 */ 4083 static void 4084 tagstack_shift(win_T *wp) 4085 { 4086 taggy_T *tagstack = wp->w_tagstack; 4087 int i; 4088 4089 vim_free(tagstack[0].tagname); 4090 for (i = 1; i < wp->w_tagstacklen; ++i) 4091 tagstack[i - 1] = tagstack[i]; 4092 wp->w_tagstacklen--; 4093 } 4094 4095 /* 4096 * Push a new item to the tag stack 4097 */ 4098 static void 4099 tagstack_push_item( 4100 win_T *wp, 4101 char_u *tagname, 4102 int cur_fnum, 4103 int cur_match, 4104 pos_T mark, 4105 int fnum) 4106 { 4107 taggy_T *tagstack = wp->w_tagstack; 4108 int idx = wp->w_tagstacklen; // top of the stack 4109 4110 // if the tagstack is full: remove the oldest entry 4111 if (idx >= TAGSTACKSIZE) 4112 { 4113 tagstack_shift(wp); 4114 idx = TAGSTACKSIZE - 1; 4115 } 4116 4117 wp->w_tagstacklen++; 4118 tagstack[idx].tagname = tagname; 4119 tagstack[idx].cur_fnum = cur_fnum; 4120 tagstack[idx].cur_match = cur_match; 4121 if (tagstack[idx].cur_match < 0) 4122 tagstack[idx].cur_match = 0; 4123 tagstack[idx].fmark.mark = mark; 4124 tagstack[idx].fmark.fnum = fnum; 4125 } 4126 4127 /* 4128 * Add a list of items to the tag stack in the specified window 4129 */ 4130 static void 4131 tagstack_push_items(win_T *wp, list_T *l) 4132 { 4133 listitem_T *li; 4134 dictitem_T *di; 4135 dict_T *itemdict; 4136 char_u *tagname; 4137 pos_T mark; 4138 int fnum; 4139 4140 // Add one entry at a time to the tag stack 4141 for (li = l->lv_first; li != NULL; li = li->li_next) 4142 { 4143 if (li->li_tv.v_type != VAR_DICT || li->li_tv.vval.v_dict == NULL) 4144 continue; // Skip non-dict items 4145 itemdict = li->li_tv.vval.v_dict; 4146 4147 // parse 'from' for the cursor position before the tag jump 4148 if ((di = dict_find(itemdict, (char_u *)"from", -1)) == NULL) 4149 continue; 4150 if (list2fpos(&di->di_tv, &mark, &fnum, NULL) != OK) 4151 continue; 4152 if ((tagname = 4153 dict_get_string(itemdict, (char_u *)"tagname", TRUE)) == NULL) 4154 continue; 4155 4156 if (mark.col > 0) 4157 mark.col--; 4158 tagstack_push_item(wp, tagname, 4159 (int)dict_get_number(itemdict, (char_u *)"bufnr"), 4160 (int)dict_get_number(itemdict, (char_u *)"matchnr") - 1, 4161 mark, fnum); 4162 } 4163 } 4164 4165 /* 4166 * Set the current index in the tag stack. Valid values are between 0 4167 * and the stack length (inclusive). 4168 */ 4169 static void 4170 tagstack_set_curidx(win_T *wp, int curidx) 4171 { 4172 wp->w_tagstackidx = curidx; 4173 if (wp->w_tagstackidx < 0) // sanity check 4174 wp->w_tagstackidx = 0; 4175 if (wp->w_tagstackidx > wp->w_tagstacklen) 4176 wp->w_tagstackidx = wp->w_tagstacklen; 4177 } 4178 4179 /* 4180 * Set the tag stack entries of the specified window. 4181 * 'action' is set to either 'a' for append or 'r' for replace. 4182 */ 4183 int 4184 set_tagstack(win_T *wp, dict_T *d, int action) 4185 { 4186 dictitem_T *di; 4187 list_T *l; 4188 4189 if ((di = dict_find(d, (char_u *)"items", -1)) != NULL) 4190 { 4191 if (di->di_tv.v_type != VAR_LIST) 4192 { 4193 emsg(_(e_listreq)); 4194 return FAIL; 4195 } 4196 l = di->di_tv.vval.v_list; 4197 4198 if (action == 'r') 4199 tagstack_clear(wp); 4200 4201 tagstack_push_items(wp, l); 4202 } 4203 4204 if ((di = dict_find(d, (char_u *)"curidx", -1)) != NULL) 4205 tagstack_set_curidx(wp, (int)tv_get_number(&di->di_tv) - 1); 4206 4207 return OK; 4208 } 4209 #endif 4210