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_WINDOWS) && 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, {INIT_POS_T(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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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_WINDOWS) && 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 EMSG2(_("E426: tag not found: %s"), name); 570 #if defined(FEAT_WINDOWS) && 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_WINDOWS) && 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(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_puts_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((char_u *)" ", 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_nr_str(dict, "text", 0L, tag_name); 909 dict_add_nr_str(dict, "filename", 0L, fname); 910 dict_add_nr_str(dict, "lnum", lnum, NULL); 911 if (lnum == 0) 912 dict_add_nr_str(dict, "pattern", 0L, 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_WINDOWS) && 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((char_u *)_("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(IObuff, HL_ATTR(HLF_W)); 1007 else 1008 msg(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 #ifdef FEAT_AUTOCMD 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 #ifdef FEAT_AUTOCMD 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 EMSG2(_("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 #ifdef FEAT_WINDOWS 1077 postponed_split = 0; /* don't split next time */ 1078 # ifdef FEAT_QUICKFIX 1079 g_do_tagpreview = 0; /* don't do tag preview next time */ 1080 # endif 1081 #endif 1082 1083 #ifdef FEAT_CSCOPE 1084 return jumped_to_tag; 1085 #else 1086 return FALSE; 1087 #endif 1088 } 1089 1090 /* 1091 * Free cached tags. 1092 */ 1093 void 1094 tag_freematch(void) 1095 { 1096 vim_free(tagmatchname); 1097 tagmatchname = NULL; 1098 } 1099 1100 static void 1101 taglen_advance(int l) 1102 { 1103 if (l == MAXCOL) 1104 { 1105 msg_putchar('\n'); 1106 msg_advance(24); 1107 } 1108 else 1109 msg_advance(13 + l); 1110 } 1111 1112 /* 1113 * Print the tag stack 1114 */ 1115 void 1116 do_tags(exarg_T *eap UNUSED) 1117 { 1118 int i; 1119 char_u *name; 1120 taggy_T *tagstack = curwin->w_tagstack; 1121 int tagstackidx = curwin->w_tagstackidx; 1122 int tagstacklen = curwin->w_tagstacklen; 1123 1124 /* Highlight title */ 1125 MSG_PUTS_TITLE(_("\n # TO tag FROM line in file/text")); 1126 for (i = 0; i < tagstacklen; ++i) 1127 { 1128 if (tagstack[i].tagname != NULL) 1129 { 1130 name = fm_getname(&(tagstack[i].fmark), 30); 1131 if (name == NULL) /* file name not available */ 1132 continue; 1133 1134 msg_putchar('\n'); 1135 sprintf((char *)IObuff, "%c%2d %2d %-15s %5ld ", 1136 i == tagstackidx ? '>' : ' ', 1137 i + 1, 1138 tagstack[i].cur_match + 1, 1139 tagstack[i].tagname, 1140 tagstack[i].fmark.mark.lnum); 1141 msg_outtrans(IObuff); 1142 msg_outtrans_attr(name, tagstack[i].fmark.fnum == curbuf->b_fnum 1143 ? HL_ATTR(HLF_D) : 0); 1144 vim_free(name); 1145 } 1146 out_flush(); /* show one line at a time */ 1147 } 1148 if (tagstackidx == tagstacklen) /* idx at top of stack */ 1149 MSG_PUTS("\n>"); 1150 } 1151 1152 /* When not using a CR for line separator, use vim_fgets() to read tag lines. 1153 * For the Mac use tag_fgets(). It can handle any line separator, but is much 1154 * slower than vim_fgets(). 1155 */ 1156 #ifndef USE_CR 1157 # define tag_fgets vim_fgets 1158 #endif 1159 1160 #ifdef FEAT_TAG_BINS 1161 static int tag_strnicmp(char_u *s1, char_u *s2, size_t len); 1162 1163 /* 1164 * Compare two strings, for length "len", ignoring case the ASCII way. 1165 * return 0 for match, < 0 for smaller, > 0 for bigger 1166 * Make sure case is folded to uppercase in comparison (like for 'sort -f') 1167 */ 1168 static int 1169 tag_strnicmp(char_u *s1, char_u *s2, size_t len) 1170 { 1171 int i; 1172 1173 while (len > 0) 1174 { 1175 i = (int)TOUPPER_ASC(*s1) - (int)TOUPPER_ASC(*s2); 1176 if (i != 0) 1177 return i; /* this character different */ 1178 if (*s1 == NUL) 1179 break; /* strings match until NUL */ 1180 ++s1; 1181 ++s2; 1182 --len; 1183 } 1184 return 0; /* strings match */ 1185 } 1186 #endif 1187 1188 /* 1189 * Structure to hold info about the tag pattern being used. 1190 */ 1191 typedef struct 1192 { 1193 char_u *pat; /* the pattern */ 1194 int len; /* length of pat[] */ 1195 char_u *head; /* start of pattern head */ 1196 int headlen; /* length of head[] */ 1197 regmatch_T regmatch; /* regexp program, may be NULL */ 1198 } pat_T; 1199 1200 static void prepare_pats(pat_T *pats, int has_re); 1201 1202 /* 1203 * Extract info from the tag search pattern "pats->pat". 1204 */ 1205 static void 1206 prepare_pats(pat_T *pats, int has_re) 1207 { 1208 pats->head = pats->pat; 1209 pats->headlen = pats->len; 1210 if (has_re) 1211 { 1212 /* When the pattern starts with '^' or "\\<", binary searching can be 1213 * used (much faster). */ 1214 if (pats->pat[0] == '^') 1215 pats->head = pats->pat + 1; 1216 else if (pats->pat[0] == '\\' && pats->pat[1] == '<') 1217 pats->head = pats->pat + 2; 1218 if (pats->head == pats->pat) 1219 pats->headlen = 0; 1220 else 1221 for (pats->headlen = 0; pats->head[pats->headlen] != NUL; 1222 ++pats->headlen) 1223 if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"), 1224 pats->head[pats->headlen]) != NULL) 1225 break; 1226 if (p_tl != 0 && pats->headlen > p_tl) /* adjust for 'taglength' */ 1227 pats->headlen = p_tl; 1228 } 1229 1230 if (has_re) 1231 pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0); 1232 else 1233 pats->regmatch.regprog = NULL; 1234 } 1235 1236 /* 1237 * find_tags() - search for tags in tags files 1238 * 1239 * Return FAIL if search completely failed (*num_matches will be 0, *matchesp 1240 * will be NULL), OK otherwise. 1241 * 1242 * There is a priority in which type of tag is recognized. 1243 * 1244 * 6. A static or global tag with a full matching tag for the current file. 1245 * 5. A global tag with a full matching tag for another file. 1246 * 4. A static tag with a full matching tag for another file. 1247 * 3. A static or global tag with an ignore-case matching tag for the 1248 * current file. 1249 * 2. A global tag with an ignore-case matching tag for another file. 1250 * 1. A static tag with an ignore-case matching tag for another file. 1251 * 1252 * Tags in an emacs-style tags file are always global. 1253 * 1254 * flags: 1255 * TAG_HELP only search for help tags 1256 * TAG_NAMES only return name of tag 1257 * TAG_REGEXP use "pat" as a regexp 1258 * TAG_NOIC don't always ignore case 1259 * TAG_KEEP_LANG keep language 1260 * TAG_CSCOPE use cscope results for tags 1261 */ 1262 int 1263 find_tags( 1264 char_u *pat, /* pattern to search for */ 1265 int *num_matches, /* return: number of matches found */ 1266 char_u ***matchesp, /* return: array of matches found */ 1267 int flags, 1268 int mincount, /* MAXCOL: find all matches 1269 other: minimal number of matches */ 1270 char_u *buf_ffname) /* name of buffer for priority */ 1271 { 1272 FILE *fp; 1273 char_u *lbuf; /* line buffer */ 1274 int lbuf_size = LSIZE; /* length of lbuf */ 1275 char_u *tag_fname; /* name of tag file */ 1276 tagname_T tn; /* info for get_tagfname() */ 1277 int first_file; /* trying first tag file */ 1278 tagptrs_T tagp; 1279 int did_open = FALSE; /* did open a tag file */ 1280 int stop_searching = FALSE; /* stop when match found or error */ 1281 int retval = FAIL; /* return value */ 1282 int is_static; /* current tag line is static */ 1283 int is_current; /* file name matches */ 1284 int eof = FALSE; /* found end-of-file */ 1285 char_u *p; 1286 char_u *s; 1287 int i; 1288 #ifdef FEAT_TAG_BINS 1289 int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */ 1290 struct tag_search_info /* Binary search file offsets */ 1291 { 1292 off_T low_offset; /* offset for first char of first line that 1293 could match */ 1294 off_T high_offset; /* offset of char after last line that could 1295 match */ 1296 off_T curr_offset; /* Current file offset in search range */ 1297 off_T curr_offset_used; /* curr_offset used when skipping back */ 1298 off_T match_offset; /* Where the binary search found a tag */ 1299 int low_char; /* first char at low_offset */ 1300 int high_char; /* first char at high_offset */ 1301 } search_info; 1302 off_T filesize; 1303 int tagcmp; 1304 off_T offset; 1305 int round; 1306 #endif 1307 enum 1308 { 1309 TS_START, /* at start of file */ 1310 TS_LINEAR /* linear searching forward, till EOF */ 1311 #ifdef FEAT_TAG_BINS 1312 , TS_BINARY, /* binary searching */ 1313 TS_SKIP_BACK, /* skipping backwards */ 1314 TS_STEP_FORWARD /* stepping forwards */ 1315 #endif 1316 } state; /* Current search state */ 1317 1318 int cmplen; 1319 int match; /* matches */ 1320 int match_no_ic = 0;/* matches with rm_ic == FALSE */ 1321 int match_re; /* match with regexp */ 1322 int matchoff = 0; 1323 int save_emsg_off; 1324 1325 #ifdef FEAT_EMACS_TAGS 1326 /* 1327 * Stack for included emacs-tags file. 1328 * It has a fixed size, to truncate cyclic includes. jw 1329 */ 1330 # define INCSTACK_SIZE 42 1331 struct 1332 { 1333 FILE *fp; 1334 char_u *etag_fname; 1335 } incstack[INCSTACK_SIZE]; 1336 1337 int incstack_idx = 0; /* index in incstack */ 1338 char_u *ebuf; /* additional buffer for etag fname */ 1339 int is_etag; /* current file is emaces style */ 1340 #endif 1341 1342 char_u *mfp; 1343 garray_T ga_match[MT_COUNT]; /* stores matches in sequence */ 1344 hashtab_T ht_match[MT_COUNT]; /* stores matches by key */ 1345 hash_T hash = 0; 1346 int match_count = 0; /* number of matches found */ 1347 char_u **matches; 1348 int mtt; 1349 int help_save; 1350 #ifdef FEAT_MULTI_LANG 1351 int help_pri = 0; 1352 char_u *help_lang_find = NULL; /* lang to be found */ 1353 char_u help_lang[3]; /* lang of current tags file */ 1354 char_u *saved_pat = NULL; /* copy of pat[] */ 1355 int is_txt = FALSE; /* flag of file extension */ 1356 #endif 1357 1358 pat_T orgpat; /* holds unconverted pattern info */ 1359 #ifdef FEAT_MBYTE 1360 vimconv_T vimconv; 1361 #endif 1362 1363 #ifdef FEAT_TAG_BINS 1364 int findall = (mincount == MAXCOL || mincount == TAG_MANY); 1365 /* find all matching tags */ 1366 int sort_error = FALSE; /* tags file not sorted */ 1367 int linear; /* do a linear search */ 1368 int sortic = FALSE; /* tag file sorted in nocase */ 1369 #endif 1370 int line_error = FALSE; /* syntax error */ 1371 int has_re = (flags & TAG_REGEXP); /* regexp used */ 1372 int help_only = (flags & TAG_HELP); 1373 int name_only = (flags & TAG_NAMES); 1374 int noic = (flags & TAG_NOIC); 1375 int get_it_again = FALSE; 1376 #ifdef FEAT_CSCOPE 1377 int use_cscope = (flags & TAG_CSCOPE); 1378 #endif 1379 int verbose = (flags & TAG_VERBOSE); 1380 int save_p_ic = p_ic; 1381 1382 /* 1383 * Change the value of 'ignorecase' according to 'tagcase' for the 1384 * duration of this function. 1385 */ 1386 switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) 1387 { 1388 case TC_FOLLOWIC: break; 1389 case TC_IGNORE: p_ic = TRUE; break; 1390 case TC_MATCH: p_ic = FALSE; break; 1391 case TC_FOLLOWSCS: p_ic = ignorecase(pat); break; 1392 case TC_SMART: p_ic = ignorecase_opt(pat, TRUE, TRUE); break; 1393 } 1394 1395 help_save = curbuf->b_help; 1396 orgpat.pat = pat; 1397 #ifdef FEAT_MBYTE 1398 vimconv.vc_type = CONV_NONE; 1399 #endif 1400 1401 /* 1402 * Allocate memory for the buffers that are used 1403 */ 1404 lbuf = alloc(lbuf_size); 1405 tag_fname = alloc(MAXPATHL + 1); 1406 #ifdef FEAT_EMACS_TAGS 1407 ebuf = alloc(LSIZE); 1408 #endif 1409 for (mtt = 0; mtt < MT_COUNT; ++mtt) 1410 { 1411 ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100); 1412 hash_init(&ht_match[mtt]); 1413 } 1414 1415 /* check for out of memory situation */ 1416 if (lbuf == NULL || tag_fname == NULL 1417 #ifdef FEAT_EMACS_TAGS 1418 || ebuf == NULL 1419 #endif 1420 ) 1421 goto findtag_end; 1422 1423 #ifdef FEAT_CSCOPE 1424 STRCPY(tag_fname, "from cscope"); /* for error messages */ 1425 #endif 1426 1427 /* 1428 * Initialize a few variables 1429 */ 1430 if (help_only) /* want tags from help file */ 1431 curbuf->b_help = TRUE; /* will be restored later */ 1432 #ifdef FEAT_CSCOPE 1433 else if (use_cscope) 1434 { 1435 /* Make sure we don't mix help and cscope, confuses Coverity. */ 1436 help_only = FALSE; 1437 curbuf->b_help = FALSE; 1438 } 1439 #endif 1440 1441 orgpat.len = (int)STRLEN(pat); 1442 #ifdef FEAT_MULTI_LANG 1443 if (curbuf->b_help) 1444 { 1445 /* When "@ab" is specified use only the "ab" language, otherwise 1446 * search all languages. */ 1447 if (orgpat.len > 3 && pat[orgpat.len - 3] == '@' 1448 && ASCII_ISALPHA(pat[orgpat.len - 2]) 1449 && ASCII_ISALPHA(pat[orgpat.len - 1])) 1450 { 1451 saved_pat = vim_strnsave(pat, orgpat.len - 3); 1452 if (saved_pat != NULL) 1453 { 1454 help_lang_find = &pat[orgpat.len - 2]; 1455 orgpat.pat = saved_pat; 1456 orgpat.len -= 3; 1457 } 1458 } 1459 } 1460 #endif 1461 if (p_tl != 0 && orgpat.len > p_tl) /* adjust for 'taglength' */ 1462 orgpat.len = p_tl; 1463 1464 save_emsg_off = emsg_off; 1465 emsg_off = TRUE; /* don't want error for invalid RE here */ 1466 prepare_pats(&orgpat, has_re); 1467 emsg_off = save_emsg_off; 1468 if (has_re && orgpat.regmatch.regprog == NULL) 1469 goto findtag_end; 1470 1471 #ifdef FEAT_TAG_BINS 1472 /* This is only to avoid a compiler warning for using search_info 1473 * uninitialised. */ 1474 vim_memset(&search_info, 0, (size_t)1); 1475 #endif 1476 1477 /* 1478 * When finding a specified number of matches, first try with matching 1479 * case, so binary search can be used, and try ignore-case matches in a 1480 * second loop. 1481 * When finding all matches, 'tagbsearch' is off, or there is no fixed 1482 * string to look for, ignore case right away to avoid going though the 1483 * tags files twice. 1484 * When the tag file is case-fold sorted, it is either one or the other. 1485 * Only ignore case when TAG_NOIC not used or 'ignorecase' set. 1486 */ 1487 #ifdef FEAT_MULTI_LANG 1488 /* Set a flag if the file extension is .txt */ 1489 if ((flags & TAG_KEEP_LANG) 1490 && help_lang_find == NULL 1491 && curbuf->b_fname != NULL 1492 && (i = (int)STRLEN(curbuf->b_fname)) > 4 1493 && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) 1494 is_txt = TRUE; 1495 #endif 1496 #ifdef FEAT_TAG_BINS 1497 orgpat.regmatch.rm_ic = ((p_ic || !noic) 1498 && (findall || orgpat.headlen == 0 || !p_tbs)); 1499 for (round = 1; round <= 2; ++round) 1500 { 1501 linear = (orgpat.headlen == 0 || !p_tbs || round == 2); 1502 #else 1503 orgpat.regmatch.rm_ic = (p_ic || !noic); 1504 #endif 1505 1506 /* 1507 * Try tag file names from tags option one by one. 1508 */ 1509 for (first_file = TRUE; 1510 #ifdef FEAT_CSCOPE 1511 use_cscope || 1512 #endif 1513 get_tagfname(&tn, first_file, tag_fname) == OK; 1514 first_file = FALSE) 1515 { 1516 /* 1517 * A file that doesn't exist is silently ignored. Only when not a 1518 * single file is found, an error message is given (further on). 1519 */ 1520 #ifdef FEAT_CSCOPE 1521 if (use_cscope) 1522 fp = NULL; /* avoid GCC warning */ 1523 else 1524 #endif 1525 { 1526 #ifdef FEAT_MULTI_LANG 1527 if (curbuf->b_help) 1528 { 1529 /* Keep en if the file extension is .txt*/ 1530 if (is_txt) 1531 STRCPY(help_lang, "en"); 1532 else 1533 { 1534 /* Prefer help tags according to 'helplang'. Put the 1535 * two-letter language name in help_lang[]. */ 1536 i = (int)STRLEN(tag_fname); 1537 if (i > 3 && tag_fname[i - 3] == '-') 1538 STRCPY(help_lang, tag_fname + i - 2); 1539 else 1540 STRCPY(help_lang, "en"); 1541 } 1542 /* When searching for a specific language skip tags files 1543 * for other languages. */ 1544 if (help_lang_find != NULL 1545 && STRICMP(help_lang, help_lang_find) != 0) 1546 continue; 1547 1548 /* For CTRL-] in a help file prefer a match with the same 1549 * language. */ 1550 if ((flags & TAG_KEEP_LANG) 1551 && help_lang_find == NULL 1552 && curbuf->b_fname != NULL 1553 && (i = (int)STRLEN(curbuf->b_fname)) > 4 1554 && curbuf->b_fname[i - 1] == 'x' 1555 && curbuf->b_fname[i - 4] == '.' 1556 && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) 1557 help_pri = 0; 1558 else 1559 { 1560 help_pri = 1; 1561 for (s = p_hlg; *s != NUL; ++s) 1562 { 1563 if (STRNICMP(s, help_lang, 2) == 0) 1564 break; 1565 ++help_pri; 1566 if ((s = vim_strchr(s, ',')) == NULL) 1567 break; 1568 } 1569 if (s == NULL || *s == NUL) 1570 { 1571 /* Language not in 'helplang': use last, prefer English, 1572 * unless found already. */ 1573 ++help_pri; 1574 if (STRICMP(help_lang, "en") != 0) 1575 ++help_pri; 1576 } 1577 } 1578 } 1579 #endif 1580 1581 if ((fp = mch_fopen((char *)tag_fname, "r")) == NULL) 1582 continue; 1583 1584 if (p_verbose >= 5) 1585 { 1586 verbose_enter(); 1587 smsg((char_u *)_("Searching tags file %s"), tag_fname); 1588 verbose_leave(); 1589 } 1590 } 1591 did_open = TRUE; /* remember that we found at least one file */ 1592 1593 state = TS_START; /* we're at the start of the file */ 1594 #ifdef FEAT_EMACS_TAGS 1595 is_etag = 0; /* default is: not emacs style */ 1596 #endif 1597 1598 /* 1599 * Read and parse the lines in the file one by one 1600 */ 1601 for (;;) 1602 { 1603 #ifdef FEAT_TAG_BINS 1604 /* check for CTRL-C typed, more often when jumping around */ 1605 if (state == TS_BINARY || state == TS_SKIP_BACK) 1606 line_breakcheck(); 1607 else 1608 #endif 1609 fast_breakcheck(); 1610 #ifdef FEAT_INS_EXPAND 1611 if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */ 1612 ins_compl_check_keys(30, FALSE); 1613 if (got_int || compl_interrupted) 1614 #else 1615 if (got_int) 1616 #endif 1617 { 1618 stop_searching = TRUE; 1619 break; 1620 } 1621 /* When mincount is TAG_MANY, stop when enough matches have been 1622 * found (for completion). */ 1623 if (mincount == TAG_MANY && match_count >= TAG_MANY) 1624 { 1625 stop_searching = TRUE; 1626 retval = OK; 1627 break; 1628 } 1629 if (get_it_again) 1630 goto line_read_in; 1631 #ifdef FEAT_TAG_BINS 1632 /* 1633 * For binary search: compute the next offset to use. 1634 */ 1635 if (state == TS_BINARY) 1636 { 1637 offset = search_info.low_offset + ((search_info.high_offset 1638 - search_info.low_offset) / 2); 1639 if (offset == search_info.curr_offset) 1640 break; /* End the binary search without a match. */ 1641 else 1642 search_info.curr_offset = offset; 1643 } 1644 1645 /* 1646 * Skipping back (after a match during binary search). 1647 */ 1648 else if (state == TS_SKIP_BACK) 1649 { 1650 search_info.curr_offset -= LSIZE * 2; 1651 if (search_info.curr_offset < 0) 1652 { 1653 search_info.curr_offset = 0; 1654 rewind(fp); 1655 state = TS_STEP_FORWARD; 1656 } 1657 } 1658 1659 /* 1660 * When jumping around in the file, first read a line to find the 1661 * start of the next line. 1662 */ 1663 if (state == TS_BINARY || state == TS_SKIP_BACK) 1664 { 1665 /* Adjust the search file offset to the correct position */ 1666 search_info.curr_offset_used = search_info.curr_offset; 1667 vim_fseek(fp, search_info.curr_offset, SEEK_SET); 1668 eof = tag_fgets(lbuf, LSIZE, fp); 1669 if (!eof && search_info.curr_offset != 0) 1670 { 1671 /* The explicit cast is to work around a bug in gcc 3.4.2 1672 * (repeated below). */ 1673 search_info.curr_offset = vim_ftell(fp); 1674 if (search_info.curr_offset == search_info.high_offset) 1675 { 1676 /* oops, gone a bit too far; try from low offset */ 1677 vim_fseek(fp, search_info.low_offset, SEEK_SET); 1678 search_info.curr_offset = search_info.low_offset; 1679 } 1680 eof = tag_fgets(lbuf, LSIZE, fp); 1681 } 1682 /* skip empty and blank lines */ 1683 while (!eof && vim_isblankline(lbuf)) 1684 { 1685 search_info.curr_offset = vim_ftell(fp); 1686 eof = tag_fgets(lbuf, LSIZE, fp); 1687 } 1688 if (eof) 1689 { 1690 /* Hit end of file. Skip backwards. */ 1691 state = TS_SKIP_BACK; 1692 search_info.match_offset = vim_ftell(fp); 1693 search_info.curr_offset = search_info.curr_offset_used; 1694 continue; 1695 } 1696 } 1697 1698 /* 1699 * Not jumping around in the file: Read the next line. 1700 */ 1701 else 1702 #endif 1703 { 1704 /* skip empty and blank lines */ 1705 do 1706 { 1707 #ifdef FEAT_CSCOPE 1708 if (use_cscope) 1709 eof = cs_fgets(lbuf, LSIZE); 1710 else 1711 #endif 1712 eof = tag_fgets(lbuf, LSIZE, fp); 1713 } while (!eof && vim_isblankline(lbuf)); 1714 1715 if (eof) 1716 { 1717 #ifdef FEAT_EMACS_TAGS 1718 if (incstack_idx) /* this was an included file */ 1719 { 1720 --incstack_idx; 1721 fclose(fp); /* end of this file ... */ 1722 fp = incstack[incstack_idx].fp; 1723 STRCPY(tag_fname, incstack[incstack_idx].etag_fname); 1724 vim_free(incstack[incstack_idx].etag_fname); 1725 is_etag = 1; /* (only etags can include) */ 1726 continue; /* ... continue with parent file */ 1727 } 1728 else 1729 #endif 1730 break; /* end of file */ 1731 } 1732 } 1733 line_read_in: 1734 1735 #ifdef FEAT_MBYTE 1736 if (vimconv.vc_type != CONV_NONE) 1737 { 1738 char_u *conv_line; 1739 int len; 1740 1741 /* Convert every line. Converting the pattern from 'enc' to 1742 * the tags file encoding doesn't work, because characters are 1743 * not recognized. */ 1744 conv_line = string_convert(&vimconv, lbuf, NULL); 1745 if (conv_line != NULL) 1746 { 1747 /* Copy or swap lbuf and conv_line. */ 1748 len = (int)STRLEN(conv_line) + 1; 1749 if (len > lbuf_size) 1750 { 1751 vim_free(lbuf); 1752 lbuf = conv_line; 1753 lbuf_size = len; 1754 } 1755 else 1756 { 1757 STRCPY(lbuf, conv_line); 1758 vim_free(conv_line); 1759 } 1760 } 1761 } 1762 #endif 1763 1764 1765 #ifdef FEAT_EMACS_TAGS 1766 /* 1767 * Emacs tags line with CTRL-L: New file name on next line. 1768 * The file name is followed by a ','. 1769 * Remember etag file name in ebuf. 1770 */ 1771 if (*lbuf == Ctrl_L 1772 # ifdef FEAT_CSCOPE 1773 && !use_cscope 1774 # endif 1775 ) 1776 { 1777 is_etag = 1; /* in case at the start */ 1778 state = TS_LINEAR; 1779 if (!tag_fgets(ebuf, LSIZE, fp)) 1780 { 1781 for (p = ebuf; *p && *p != ','; p++) 1782 ; 1783 *p = NUL; 1784 1785 /* 1786 * atoi(p+1) is the number of bytes before the next ^L 1787 * unless it is an include statement. 1788 */ 1789 if (STRNCMP(p + 1, "include", 7) == 0 1790 && incstack_idx < INCSTACK_SIZE) 1791 { 1792 /* Save current "fp" and "tag_fname" in the stack. */ 1793 if ((incstack[incstack_idx].etag_fname = 1794 vim_strsave(tag_fname)) != NULL) 1795 { 1796 char_u *fullpath_ebuf; 1797 1798 incstack[incstack_idx].fp = fp; 1799 fp = NULL; 1800 1801 /* Figure out "tag_fname" and "fp" to use for 1802 * included file. */ 1803 fullpath_ebuf = expand_tag_fname(ebuf, 1804 tag_fname, FALSE); 1805 if (fullpath_ebuf != NULL) 1806 { 1807 fp = mch_fopen((char *)fullpath_ebuf, "r"); 1808 if (fp != NULL) 1809 { 1810 if (STRLEN(fullpath_ebuf) > LSIZE) 1811 EMSG2(_("E430: Tag file path truncated for %s\n"), ebuf); 1812 vim_strncpy(tag_fname, fullpath_ebuf, 1813 MAXPATHL); 1814 ++incstack_idx; 1815 is_etag = 0; /* we can include anything */ 1816 } 1817 vim_free(fullpath_ebuf); 1818 } 1819 if (fp == NULL) 1820 { 1821 /* Can't open the included file, skip it and 1822 * restore old value of "fp". */ 1823 fp = incstack[incstack_idx].fp; 1824 vim_free(incstack[incstack_idx].etag_fname); 1825 } 1826 } 1827 } 1828 } 1829 continue; 1830 } 1831 #endif 1832 1833 /* 1834 * When still at the start of the file, check for Emacs tags file 1835 * format, and for "not sorted" flag. 1836 */ 1837 if (state == TS_START) 1838 { 1839 /* The header ends when the line sorts below "!_TAG_". When 1840 * case is folded lower case letters sort before "_". */ 1841 if (STRNCMP(lbuf, "!_TAG_", 6) <= 0 1842 || (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1]))) 1843 { 1844 if (STRNCMP(lbuf, "!_TAG_", 6) != 0) 1845 /* Non-header item before the header, e.g. "!" itself. 1846 */ 1847 goto parse_line; 1848 1849 /* 1850 * Read header line. 1851 */ 1852 #ifdef FEAT_TAG_BINS 1853 if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) 1854 tag_file_sorted = lbuf[18]; 1855 #endif 1856 #ifdef FEAT_MBYTE 1857 if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) 1858 { 1859 /* Prepare to convert every line from the specified 1860 * encoding to 'encoding'. */ 1861 for (p = lbuf + 20; *p > ' ' && *p < 127; ++p) 1862 ; 1863 *p = NUL; 1864 convert_setup(&vimconv, lbuf + 20, p_enc); 1865 } 1866 #endif 1867 1868 /* Read the next line. Unrecognized flags are ignored. */ 1869 continue; 1870 } 1871 1872 /* Headers ends. */ 1873 1874 #ifdef FEAT_TAG_BINS 1875 /* 1876 * When there is no tag head, or ignoring case, need to do a 1877 * linear search. 1878 * When no "!_TAG_" is found, default to binary search. If 1879 * the tag file isn't sorted, the second loop will find it. 1880 * When "!_TAG_FILE_SORTED" found: start binary search if 1881 * flag set. 1882 * For cscope, it's always linear. 1883 */ 1884 # ifdef FEAT_CSCOPE 1885 if (linear || use_cscope) 1886 # else 1887 if (linear) 1888 # endif 1889 state = TS_LINEAR; 1890 else if (tag_file_sorted == NUL) 1891 state = TS_BINARY; 1892 else if (tag_file_sorted == '1') 1893 state = TS_BINARY; 1894 else if (tag_file_sorted == '2') 1895 { 1896 state = TS_BINARY; 1897 sortic = TRUE; 1898 orgpat.regmatch.rm_ic = (p_ic || !noic); 1899 } 1900 else 1901 state = TS_LINEAR; 1902 1903 if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic) 1904 { 1905 /* Binary search won't work for ignoring case, use linear 1906 * search. */ 1907 linear = TRUE; 1908 state = TS_LINEAR; 1909 } 1910 #else 1911 state = TS_LINEAR; 1912 #endif 1913 1914 #ifdef FEAT_TAG_BINS 1915 /* 1916 * When starting a binary search, get the size of the file and 1917 * compute the first offset. 1918 */ 1919 if (state == TS_BINARY) 1920 { 1921 /* Get the tag file size (don't use mch_fstat(), it's not 1922 * portable). */ 1923 if ((filesize = vim_lseek(fileno(fp), 1924 (off_T)0L, SEEK_END)) <= 0) 1925 state = TS_LINEAR; 1926 else 1927 { 1928 vim_lseek(fileno(fp), (off_T)0L, SEEK_SET); 1929 1930 /* Calculate the first read offset in the file. Start 1931 * the search in the middle of the file. */ 1932 search_info.low_offset = 0; 1933 search_info.low_char = 0; 1934 search_info.high_offset = filesize; 1935 search_info.curr_offset = 0; 1936 search_info.high_char = 0xff; 1937 } 1938 continue; 1939 } 1940 #endif 1941 } 1942 1943 parse_line: 1944 /* 1945 * Figure out where the different strings are in this line. 1946 * For "normal" tags: Do a quick check if the tag matches. 1947 * This speeds up tag searching a lot! 1948 */ 1949 if (orgpat.headlen 1950 #ifdef FEAT_EMACS_TAGS 1951 && !is_etag 1952 #endif 1953 ) 1954 { 1955 tagp.tagname = lbuf; 1956 #ifdef FEAT_TAG_ANYWHITE 1957 tagp.tagname_end = skiptowhite(lbuf); 1958 if (*tagp.tagname_end == NUL) 1959 #else 1960 tagp.tagname_end = vim_strchr(lbuf, TAB); 1961 if (tagp.tagname_end == NULL) 1962 #endif 1963 { 1964 if (vim_strchr(lbuf, NL) == NULL) 1965 { 1966 /* Truncated line, ignore it. Has been reported for 1967 * Mozilla JS with extremely long names. */ 1968 if (p_verbose >= 5) 1969 { 1970 verbose_enter(); 1971 MSG(_("Ignoring long line in tags file")); 1972 verbose_leave(); 1973 } 1974 #ifdef FEAT_TAG_BINS 1975 if (state != TS_LINEAR) 1976 { 1977 /* Avoid getting stuck. */ 1978 linear = TRUE; 1979 state = TS_LINEAR; 1980 vim_fseek(fp, search_info.low_offset, SEEK_SET); 1981 } 1982 #endif 1983 continue; 1984 } 1985 1986 /* Corrupted tag line. */ 1987 line_error = TRUE; 1988 break; 1989 } 1990 1991 #ifdef FEAT_TAG_OLDSTATIC 1992 /* 1993 * Check for old style static tag: "file:tag file .." 1994 */ 1995 tagp.fname = NULL; 1996 for (p = lbuf; p < tagp.tagname_end; ++p) 1997 { 1998 if (*p == ':') 1999 { 2000 if (tagp.fname == NULL) 2001 #ifdef FEAT_TAG_ANYWHITE 2002 tagp.fname = skipwhite(tagp.tagname_end); 2003 #else 2004 tagp.fname = tagp.tagname_end + 1; 2005 #endif 2006 if ( fnamencmp(lbuf, tagp.fname, p - lbuf) == 0 2007 #ifdef FEAT_TAG_ANYWHITE 2008 && VIM_ISWHITE(tagp.fname[p - lbuf]) 2009 #else 2010 && tagp.fname[p - lbuf] == TAB 2011 #endif 2012 ) 2013 { 2014 /* found one */ 2015 tagp.tagname = p + 1; 2016 break; 2017 } 2018 } 2019 } 2020 #endif 2021 2022 /* 2023 * Skip this line if the length of the tag is different and 2024 * there is no regexp, or the tag is too short. 2025 */ 2026 cmplen = (int)(tagp.tagname_end - tagp.tagname); 2027 if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ 2028 cmplen = p_tl; 2029 if (has_re && orgpat.headlen < cmplen) 2030 cmplen = orgpat.headlen; 2031 else if (state == TS_LINEAR && orgpat.headlen != cmplen) 2032 continue; 2033 2034 #ifdef FEAT_TAG_BINS 2035 if (state == TS_BINARY) 2036 { 2037 /* 2038 * Simplistic check for unsorted tags file. 2039 */ 2040 i = (int)tagp.tagname[0]; 2041 if (sortic) 2042 i = (int)TOUPPER_ASC(tagp.tagname[0]); 2043 if (i < search_info.low_char || i > search_info.high_char) 2044 sort_error = TRUE; 2045 2046 /* 2047 * Compare the current tag with the searched tag. 2048 */ 2049 if (sortic) 2050 tagcmp = tag_strnicmp(tagp.tagname, orgpat.head, 2051 (size_t)cmplen); 2052 else 2053 tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen); 2054 2055 /* 2056 * A match with a shorter tag means to search forward. 2057 * A match with a longer tag means to search backward. 2058 */ 2059 if (tagcmp == 0) 2060 { 2061 if (cmplen < orgpat.headlen) 2062 tagcmp = -1; 2063 else if (cmplen > orgpat.headlen) 2064 tagcmp = 1; 2065 } 2066 2067 if (tagcmp == 0) 2068 { 2069 /* We've located the tag, now skip back and search 2070 * forward until the first matching tag is found. 2071 */ 2072 state = TS_SKIP_BACK; 2073 search_info.match_offset = search_info.curr_offset; 2074 continue; 2075 } 2076 if (tagcmp < 0) 2077 { 2078 search_info.curr_offset = vim_ftell(fp); 2079 if (search_info.curr_offset < search_info.high_offset) 2080 { 2081 search_info.low_offset = search_info.curr_offset; 2082 if (sortic) 2083 search_info.low_char = 2084 TOUPPER_ASC(tagp.tagname[0]); 2085 else 2086 search_info.low_char = tagp.tagname[0]; 2087 continue; 2088 } 2089 } 2090 if (tagcmp > 0 2091 && search_info.curr_offset != search_info.high_offset) 2092 { 2093 search_info.high_offset = search_info.curr_offset; 2094 if (sortic) 2095 search_info.high_char = 2096 TOUPPER_ASC(tagp.tagname[0]); 2097 else 2098 search_info.high_char = tagp.tagname[0]; 2099 continue; 2100 } 2101 2102 /* No match yet and are at the end of the binary search. */ 2103 break; 2104 } 2105 else if (state == TS_SKIP_BACK) 2106 { 2107 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2108 state = TS_STEP_FORWARD; 2109 else 2110 /* Have to skip back more. Restore the curr_offset 2111 * used, otherwise we get stuck at a long line. */ 2112 search_info.curr_offset = search_info.curr_offset_used; 2113 continue; 2114 } 2115 else if (state == TS_STEP_FORWARD) 2116 { 2117 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2118 { 2119 if ((off_T)vim_ftell(fp) > search_info.match_offset) 2120 break; /* past last match */ 2121 else 2122 continue; /* before first match */ 2123 } 2124 } 2125 else 2126 #endif 2127 /* skip this match if it can't match */ 2128 if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0) 2129 continue; 2130 2131 /* 2132 * Can be a matching tag, isolate the file name and command. 2133 */ 2134 #ifdef FEAT_TAG_OLDSTATIC 2135 if (tagp.fname == NULL) 2136 #endif 2137 #ifdef FEAT_TAG_ANYWHITE 2138 tagp.fname = skipwhite(tagp.tagname_end); 2139 #else 2140 tagp.fname = tagp.tagname_end + 1; 2141 #endif 2142 #ifdef FEAT_TAG_ANYWHITE 2143 tagp.fname_end = skiptowhite(tagp.fname); 2144 tagp.command = skipwhite(tagp.fname_end); 2145 if (*tagp.command == NUL) 2146 #else 2147 tagp.fname_end = vim_strchr(tagp.fname, TAB); 2148 tagp.command = tagp.fname_end + 1; 2149 if (tagp.fname_end == NULL) 2150 #endif 2151 i = FAIL; 2152 else 2153 i = OK; 2154 } 2155 else 2156 i = parse_tag_line(lbuf, 2157 #ifdef FEAT_EMACS_TAGS 2158 is_etag, 2159 #endif 2160 &tagp); 2161 if (i == FAIL) 2162 { 2163 line_error = TRUE; 2164 break; 2165 } 2166 2167 #ifdef FEAT_EMACS_TAGS 2168 if (is_etag) 2169 tagp.fname = ebuf; 2170 #endif 2171 /* 2172 * First try matching with the pattern literally (also when it is 2173 * a regexp). 2174 */ 2175 cmplen = (int)(tagp.tagname_end - tagp.tagname); 2176 if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ 2177 cmplen = p_tl; 2178 /* if tag length does not match, don't try comparing */ 2179 if (orgpat.len != cmplen) 2180 match = FALSE; 2181 else 2182 { 2183 if (orgpat.regmatch.rm_ic) 2184 { 2185 match = (MB_STRNICMP(tagp.tagname, orgpat.pat, cmplen) == 0); 2186 if (match) 2187 match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat, 2188 cmplen) == 0); 2189 } 2190 else 2191 match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0); 2192 } 2193 2194 /* 2195 * Has a regexp: Also find tags matching regexp. 2196 */ 2197 match_re = FALSE; 2198 if (!match && orgpat.regmatch.regprog != NULL) 2199 { 2200 int cc; 2201 2202 cc = *tagp.tagname_end; 2203 *tagp.tagname_end = NUL; 2204 match = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0); 2205 if (match) 2206 { 2207 matchoff = (int)(orgpat.regmatch.startp[0] - tagp.tagname); 2208 if (orgpat.regmatch.rm_ic) 2209 { 2210 orgpat.regmatch.rm_ic = FALSE; 2211 match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname, 2212 (colnr_T)0); 2213 orgpat.regmatch.rm_ic = TRUE; 2214 } 2215 } 2216 *tagp.tagname_end = cc; 2217 match_re = TRUE; 2218 } 2219 2220 /* 2221 * If a match is found, add it to ht_match[] and ga_match[]. 2222 */ 2223 if (match) 2224 { 2225 int len = 0; 2226 2227 #ifdef FEAT_CSCOPE 2228 if (use_cscope) 2229 { 2230 /* Don't change the ordering, always use the same table. */ 2231 mtt = MT_GL_OTH; 2232 } 2233 else 2234 #endif 2235 { 2236 /* Decide in which array to store this match. */ 2237 is_current = test_for_current( 2238 #ifdef FEAT_EMACS_TAGS 2239 is_etag, 2240 #endif 2241 tagp.fname, tagp.fname_end, tag_fname, 2242 buf_ffname); 2243 #ifdef FEAT_EMACS_TAGS 2244 is_static = FALSE; 2245 if (!is_etag) /* emacs tags are never static */ 2246 #endif 2247 { 2248 #ifdef FEAT_TAG_OLDSTATIC 2249 if (tagp.tagname != lbuf) 2250 is_static = TRUE; /* detected static tag before */ 2251 else 2252 #endif 2253 is_static = test_for_static(&tagp); 2254 } 2255 2256 /* decide in which of the sixteen tables to store this 2257 * match */ 2258 if (is_static) 2259 { 2260 if (is_current) 2261 mtt = MT_ST_CUR; 2262 else 2263 mtt = MT_ST_OTH; 2264 } 2265 else 2266 { 2267 if (is_current) 2268 mtt = MT_GL_CUR; 2269 else 2270 mtt = MT_GL_OTH; 2271 } 2272 if (orgpat.regmatch.rm_ic && !match_no_ic) 2273 mtt += MT_IC_OFF; 2274 if (match_re) 2275 mtt += MT_RE_OFF; 2276 } 2277 2278 /* 2279 * Add the found match in ht_match[mtt] and ga_match[mtt]. 2280 * Store the info we need later, which depends on the kind of 2281 * tags we are dealing with. 2282 */ 2283 if (help_only) 2284 { 2285 #ifdef FEAT_MULTI_LANG 2286 # define ML_EXTRA 3 2287 #else 2288 # define ML_EXTRA 0 2289 #endif 2290 /* 2291 * Append the help-heuristic number after the tagname, for 2292 * sorting it later. The heuristic is ignored for 2293 * detecting duplicates. 2294 * The format is {tagname}@{lang}NUL{heuristic}NUL 2295 */ 2296 *tagp.tagname_end = NUL; 2297 len = (int)(tagp.tagname_end - tagp.tagname); 2298 mfp = (char_u *)alloc((int)sizeof(char_u) 2299 + len + 10 + ML_EXTRA + 1); 2300 if (mfp != NULL) 2301 { 2302 int heuristic; 2303 2304 p = mfp; 2305 STRCPY(p, tagp.tagname); 2306 #ifdef FEAT_MULTI_LANG 2307 p[len] = '@'; 2308 STRCPY(p + len + 1, help_lang); 2309 #endif 2310 2311 heuristic = help_heuristic(tagp.tagname, 2312 match_re ? matchoff : 0, !match_no_ic); 2313 #ifdef FEAT_MULTI_LANG 2314 heuristic += help_pri; 2315 #endif 2316 sprintf((char *)p + len + 1 + ML_EXTRA, "%06d", 2317 heuristic); 2318 } 2319 *tagp.tagname_end = TAB; 2320 } 2321 else if (name_only) 2322 { 2323 if (get_it_again) 2324 { 2325 char_u *temp_end = tagp.command; 2326 2327 if (*temp_end == '/') 2328 while (*temp_end && *temp_end != '\r' 2329 && *temp_end != '\n' 2330 && *temp_end != '$') 2331 temp_end++; 2332 2333 if (tagp.command + 2 < temp_end) 2334 { 2335 len = (int)(temp_end - tagp.command - 2); 2336 mfp = (char_u *)alloc(len + 2); 2337 if (mfp != NULL) 2338 vim_strncpy(mfp, tagp.command + 2, len); 2339 } 2340 else 2341 mfp = NULL; 2342 get_it_again = FALSE; 2343 } 2344 else 2345 { 2346 len = (int)(tagp.tagname_end - tagp.tagname); 2347 mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1); 2348 if (mfp != NULL) 2349 vim_strncpy(mfp, tagp.tagname, len); 2350 2351 /* if wanted, re-read line to get long form too */ 2352 if (State & INSERT) 2353 get_it_again = p_sft; 2354 } 2355 } 2356 else 2357 { 2358 #define TAG_SEP 0x02 2359 size_t tag_fname_len = STRLEN(tag_fname); 2360 #ifdef FEAT_EMACS_TAGS 2361 size_t ebuf_len = 0; 2362 #endif 2363 2364 /* Save the tag in a buffer. 2365 * Use 0x02 to separate fields (Can't use NUL because the 2366 * hash key is terminated by NUL, or Ctrl_A because that is 2367 * part of some Emacs tag files -- see parse_tag_line). 2368 * Emacs tag: <mtt><tag_fname><0x02><ebuf><0x02><lbuf><NUL> 2369 * other tag: <mtt><tag_fname><0x02><0x02><lbuf><NUL> 2370 * without Emacs tags: <mtt><tag_fname><0x02><lbuf><NUL> 2371 * Here <mtt> is the "mtt" value plus 1 to avoid NUL. 2372 */ 2373 len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3; 2374 #ifdef FEAT_EMACS_TAGS 2375 if (is_etag) 2376 { 2377 ebuf_len = STRLEN(ebuf); 2378 len += (int)ebuf_len + 1; 2379 } 2380 else 2381 ++len; 2382 #endif 2383 mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1); 2384 if (mfp != NULL) 2385 { 2386 p = mfp; 2387 p[0] = mtt + 1; 2388 STRCPY(p + 1, tag_fname); 2389 #ifdef BACKSLASH_IN_FILENAME 2390 /* Ignore differences in slashes, avoid adding 2391 * both path/file and path\file. */ 2392 slash_adjust(p + 1); 2393 #endif 2394 p[tag_fname_len + 1] = TAG_SEP; 2395 s = p + 1 + tag_fname_len + 1; 2396 #ifdef FEAT_EMACS_TAGS 2397 if (is_etag) 2398 { 2399 STRCPY(s, ebuf); 2400 s[ebuf_len] = TAG_SEP; 2401 s += ebuf_len + 1; 2402 } 2403 else 2404 *s++ = TAG_SEP; 2405 #endif 2406 STRCPY(s, lbuf); 2407 } 2408 } 2409 2410 if (mfp != NULL) 2411 { 2412 hashitem_T *hi; 2413 2414 /* 2415 * Don't add identical matches. 2416 * Add all cscope tags, because they are all listed. 2417 * "mfp" is used as a hash key, there is a NUL byte to end 2418 * the part matters for comparing, more bytes may follow 2419 * after it. E.g. help tags store the priority after the 2420 * NUL. 2421 */ 2422 #ifdef FEAT_CSCOPE 2423 if (use_cscope) 2424 hash++; 2425 else 2426 #endif 2427 hash = hash_hash(mfp); 2428 hi = hash_lookup(&ht_match[mtt], mfp, hash); 2429 if (HASHITEM_EMPTY(hi)) 2430 { 2431 if (hash_add_item(&ht_match[mtt], hi, mfp, hash) 2432 == FAIL 2433 || ga_grow(&ga_match[mtt], 1) != OK) 2434 { 2435 /* Out of memory! Just forget about the rest. */ 2436 retval = OK; 2437 stop_searching = TRUE; 2438 break; 2439 } 2440 else 2441 { 2442 ((char_u **)(ga_match[mtt].ga_data)) 2443 [ga_match[mtt].ga_len++] = mfp; 2444 ++match_count; 2445 } 2446 } 2447 else 2448 /* duplicate tag, drop it */ 2449 vim_free(mfp); 2450 } 2451 } 2452 #ifdef FEAT_CSCOPE 2453 if (use_cscope && eof) 2454 break; 2455 #endif 2456 } /* forever */ 2457 2458 if (line_error) 2459 { 2460 EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname); 2461 #ifdef FEAT_CSCOPE 2462 if (!use_cscope) 2463 #endif 2464 EMSGN(_("Before byte %ld"), (long)vim_ftell(fp)); 2465 stop_searching = TRUE; 2466 line_error = FALSE; 2467 } 2468 2469 #ifdef FEAT_CSCOPE 2470 if (!use_cscope) 2471 #endif 2472 fclose(fp); 2473 #ifdef FEAT_EMACS_TAGS 2474 while (incstack_idx) 2475 { 2476 --incstack_idx; 2477 fclose(incstack[incstack_idx].fp); 2478 vim_free(incstack[incstack_idx].etag_fname); 2479 } 2480 #endif 2481 #ifdef FEAT_MBYTE 2482 if (vimconv.vc_type != CONV_NONE) 2483 convert_setup(&vimconv, NULL, NULL); 2484 #endif 2485 2486 #ifdef FEAT_TAG_BINS 2487 tag_file_sorted = NUL; 2488 if (sort_error) 2489 { 2490 EMSG2(_("E432: Tags file not sorted: %s"), tag_fname); 2491 sort_error = FALSE; 2492 } 2493 #endif 2494 2495 /* 2496 * Stop searching if sufficient tags have been found. 2497 */ 2498 if (match_count >= mincount) 2499 { 2500 retval = OK; 2501 stop_searching = TRUE; 2502 } 2503 2504 #ifdef FEAT_CSCOPE 2505 if (stop_searching || use_cscope) 2506 #else 2507 if (stop_searching) 2508 #endif 2509 break; 2510 2511 } /* end of for-each-file loop */ 2512 2513 #ifdef FEAT_CSCOPE 2514 if (!use_cscope) 2515 #endif 2516 tagname_free(&tn); 2517 2518 #ifdef FEAT_TAG_BINS 2519 /* stop searching when already did a linear search, or when TAG_NOIC 2520 * used, and 'ignorecase' not set or already did case-ignore search */ 2521 if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) 2522 break; 2523 # ifdef FEAT_CSCOPE 2524 if (use_cscope) 2525 break; 2526 # endif 2527 orgpat.regmatch.rm_ic = TRUE; /* try another time while ignoring case */ 2528 } 2529 #endif 2530 2531 if (!stop_searching) 2532 { 2533 if (!did_open && verbose) /* never opened any tags file */ 2534 EMSG(_("E433: No tags file")); 2535 retval = OK; /* It's OK even when no tag found */ 2536 } 2537 2538 findtag_end: 2539 vim_free(lbuf); 2540 vim_regfree(orgpat.regmatch.regprog); 2541 vim_free(tag_fname); 2542 #ifdef FEAT_EMACS_TAGS 2543 vim_free(ebuf); 2544 #endif 2545 2546 /* 2547 * Move the matches from the ga_match[] arrays into one list of 2548 * matches. When retval == FAIL, free the matches. 2549 */ 2550 if (retval == FAIL) 2551 match_count = 0; 2552 2553 if (match_count > 0) 2554 matches = (char_u **)lalloc((long_u)(match_count * sizeof(char_u *)), 2555 TRUE); 2556 else 2557 matches = NULL; 2558 match_count = 0; 2559 for (mtt = 0; mtt < MT_COUNT; ++mtt) 2560 { 2561 for (i = 0; i < ga_match[mtt].ga_len; ++i) 2562 { 2563 mfp = ((char_u **)(ga_match[mtt].ga_data))[i]; 2564 if (matches == NULL) 2565 vim_free(mfp); 2566 else 2567 { 2568 if (!name_only) 2569 { 2570 /* Change mtt back to zero-based. */ 2571 *mfp = *mfp - 1; 2572 2573 /* change the TAG_SEP back to NUL */ 2574 for (p = mfp + 1; *p != NUL; ++p) 2575 if (*p == TAG_SEP) 2576 *p = NUL; 2577 } 2578 matches[match_count++] = (char_u *)mfp; 2579 } 2580 } 2581 2582 ga_clear(&ga_match[mtt]); 2583 hash_clear(&ht_match[mtt]); 2584 } 2585 2586 *matchesp = matches; 2587 *num_matches = match_count; 2588 2589 curbuf->b_help = help_save; 2590 #ifdef FEAT_MULTI_LANG 2591 vim_free(saved_pat); 2592 #endif 2593 2594 p_ic = save_p_ic; 2595 2596 return retval; 2597 } 2598 2599 static garray_T tag_fnames = GA_EMPTY; 2600 static void found_tagfile_cb(char_u *fname, void *cookie); 2601 2602 /* 2603 * Callback function for finding all "tags" and "tags-??" files in 2604 * 'runtimepath' doc directories. 2605 */ 2606 static void 2607 found_tagfile_cb(char_u *fname, void *cookie UNUSED) 2608 { 2609 if (ga_grow(&tag_fnames, 1) == OK) 2610 ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = 2611 vim_strsave(fname); 2612 } 2613 2614 #if defined(EXITFREE) || defined(PROTO) 2615 void 2616 free_tag_stuff(void) 2617 { 2618 ga_clear_strings(&tag_fnames); 2619 do_tag(NULL, DT_FREE, 0, 0, 0); 2620 tag_freematch(); 2621 2622 # if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 2623 if (ptag_entry.tagname) 2624 { 2625 vim_free(ptag_entry.tagname); 2626 ptag_entry.tagname = NULL; 2627 } 2628 # endif 2629 } 2630 #endif 2631 2632 /* 2633 * Get the next name of a tag file from the tag file list. 2634 * For help files, use "tags" file only. 2635 * 2636 * Return FAIL if no more tag file names, OK otherwise. 2637 */ 2638 int 2639 get_tagfname( 2640 tagname_T *tnp, /* holds status info */ 2641 int first, /* TRUE when first file name is wanted */ 2642 char_u *buf) /* pointer to buffer of MAXPATHL chars */ 2643 { 2644 char_u *fname = NULL; 2645 char_u *r_ptr; 2646 2647 if (first) 2648 vim_memset(tnp, 0, sizeof(tagname_T)); 2649 2650 if (curbuf->b_help) 2651 { 2652 /* 2653 * For help files it's done in a completely different way: 2654 * Find "doc/tags" and "doc/tags-??" in all directories in 2655 * 'runtimepath'. 2656 */ 2657 if (first) 2658 { 2659 ga_clear_strings(&tag_fnames); 2660 ga_init2(&tag_fnames, (int)sizeof(char_u *), 10); 2661 do_in_runtimepath((char_u *) 2662 #ifdef FEAT_MULTI_LANG 2663 # ifdef VMS 2664 /* Functions decc$to_vms() and decc$translate_vms() crash 2665 * on some VMS systems with wildcards "??". Seems ECO 2666 * patches do fix the problem in C RTL, but we can't use 2667 * an #ifdef for that. */ 2668 "doc/tags doc/tags-*" 2669 # else 2670 "doc/tags doc/tags-??" 2671 # endif 2672 #else 2673 "doc/tags" 2674 #endif 2675 , DIP_ALL, found_tagfile_cb, NULL); 2676 } 2677 2678 if (tnp->tn_hf_idx >= tag_fnames.ga_len) 2679 { 2680 /* Not found in 'runtimepath', use 'helpfile', if it exists and 2681 * wasn't used yet, replacing "help.txt" with "tags". */ 2682 if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) 2683 return FAIL; 2684 ++tnp->tn_hf_idx; 2685 STRCPY(buf, p_hf); 2686 STRCPY(gettail(buf), "tags"); 2687 } 2688 else 2689 vim_strncpy(buf, ((char_u **)(tag_fnames.ga_data))[ 2690 tnp->tn_hf_idx++], MAXPATHL - 1); 2691 return OK; 2692 } 2693 2694 if (first) 2695 { 2696 /* Init. We make a copy of 'tags', because autocommands may change 2697 * the value without notifying us. */ 2698 tnp->tn_tags = vim_strsave((*curbuf->b_p_tags != NUL) 2699 ? curbuf->b_p_tags : p_tags); 2700 if (tnp->tn_tags == NULL) 2701 return FAIL; 2702 tnp->tn_np = tnp->tn_tags; 2703 } 2704 2705 /* 2706 * Loop until we have found a file name that can be used. 2707 * There are two states: 2708 * tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'. 2709 * tnp->tn_did_filefind_init == TRUE: find next file in this part. 2710 */ 2711 for (;;) 2712 { 2713 if (tnp->tn_did_filefind_init) 2714 { 2715 fname = vim_findfile(tnp->tn_search_ctx); 2716 if (fname != NULL) 2717 break; 2718 2719 tnp->tn_did_filefind_init = FALSE; 2720 } 2721 else 2722 { 2723 char_u *filename = NULL; 2724 2725 /* Stop when used all parts of 'tags'. */ 2726 if (*tnp->tn_np == NUL) 2727 { 2728 vim_findfile_cleanup(tnp->tn_search_ctx); 2729 tnp->tn_search_ctx = NULL; 2730 return FAIL; 2731 } 2732 2733 /* 2734 * Copy next file name into buf. 2735 */ 2736 buf[0] = NUL; 2737 (void)copy_option_part(&tnp->tn_np, buf, MAXPATHL - 1, " ,"); 2738 2739 #ifdef FEAT_PATH_EXTRA 2740 r_ptr = vim_findfile_stopdir(buf); 2741 #else 2742 r_ptr = NULL; 2743 #endif 2744 /* move the filename one char forward and truncate the 2745 * filepath with a NUL */ 2746 filename = gettail(buf); 2747 STRMOVE(filename + 1, filename); 2748 *filename++ = NUL; 2749 2750 tnp->tn_search_ctx = vim_findfile_init(buf, filename, 2751 r_ptr, 100, 2752 FALSE, /* don't free visited list */ 2753 FINDFILE_FILE, /* we search for a file */ 2754 tnp->tn_search_ctx, TRUE, curbuf->b_ffname); 2755 if (tnp->tn_search_ctx != NULL) 2756 tnp->tn_did_filefind_init = TRUE; 2757 } 2758 } 2759 2760 STRCPY(buf, fname); 2761 vim_free(fname); 2762 return OK; 2763 } 2764 2765 /* 2766 * Free the contents of a tagname_T that was filled by get_tagfname(). 2767 */ 2768 void 2769 tagname_free(tagname_T *tnp) 2770 { 2771 vim_free(tnp->tn_tags); 2772 vim_findfile_cleanup(tnp->tn_search_ctx); 2773 tnp->tn_search_ctx = NULL; 2774 ga_clear_strings(&tag_fnames); 2775 } 2776 2777 /* 2778 * Parse one line from the tags file. Find start/end of tag name, start/end of 2779 * file name and start of search pattern. 2780 * 2781 * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set. 2782 * 2783 * Return FAIL if there is a format error in this line, OK otherwise. 2784 */ 2785 static int 2786 parse_tag_line( 2787 char_u *lbuf, /* line to be parsed */ 2788 #ifdef FEAT_EMACS_TAGS 2789 int is_etag, 2790 #endif 2791 tagptrs_T *tagp) 2792 { 2793 char_u *p; 2794 2795 #ifdef FEAT_EMACS_TAGS 2796 char_u *p_7f; 2797 2798 if (is_etag) 2799 { 2800 /* 2801 * There are two formats for an emacs tag line: 2802 * 1: struct EnvBase ^?EnvBase^A139,4627 2803 * 2: #define ARPB_WILD_WORLD ^?153,5194 2804 */ 2805 p_7f = vim_strchr(lbuf, 0x7f); 2806 if (p_7f == NULL) 2807 { 2808 etag_fail: 2809 if (vim_strchr(lbuf, '\n') == NULL) 2810 { 2811 /* Truncated line. Ignore it. */ 2812 if (p_verbose >= 5) 2813 { 2814 verbose_enter(); 2815 MSG(_("Ignoring long line in tags file")); 2816 verbose_leave(); 2817 } 2818 tagp->command = lbuf; 2819 tagp->tagname = lbuf; 2820 tagp->tagname_end = lbuf; 2821 return OK; 2822 } 2823 return FAIL; 2824 } 2825 2826 /* Find ^A. If not found the line number is after the 0x7f */ 2827 p = vim_strchr(p_7f, Ctrl_A); 2828 if (p == NULL) 2829 p = p_7f + 1; 2830 else 2831 ++p; 2832 2833 if (!VIM_ISDIGIT(*p)) /* check for start of line number */ 2834 goto etag_fail; 2835 tagp->command = p; 2836 2837 2838 if (p[-1] == Ctrl_A) /* first format: explicit tagname given */ 2839 { 2840 tagp->tagname = p_7f + 1; 2841 tagp->tagname_end = p - 1; 2842 } 2843 else /* second format: isolate tagname */ 2844 { 2845 /* find end of tagname */ 2846 for (p = p_7f - 1; !vim_iswordc(*p); --p) 2847 if (p == lbuf) 2848 goto etag_fail; 2849 tagp->tagname_end = p + 1; 2850 while (p >= lbuf && vim_iswordc(*p)) 2851 --p; 2852 tagp->tagname = p + 1; 2853 } 2854 } 2855 else /* not an Emacs tag */ 2856 { 2857 #endif 2858 /* Isolate the tagname, from lbuf up to the first white */ 2859 tagp->tagname = lbuf; 2860 #ifdef FEAT_TAG_ANYWHITE 2861 p = skiptowhite(lbuf); 2862 #else 2863 p = vim_strchr(lbuf, TAB); 2864 if (p == NULL) 2865 return FAIL; 2866 #endif 2867 tagp->tagname_end = p; 2868 2869 /* Isolate file name, from first to second white space */ 2870 #ifdef FEAT_TAG_ANYWHITE 2871 p = skipwhite(p); 2872 #else 2873 if (*p != NUL) 2874 ++p; 2875 #endif 2876 tagp->fname = p; 2877 #ifdef FEAT_TAG_ANYWHITE 2878 p = skiptowhite(p); 2879 #else 2880 p = vim_strchr(p, TAB); 2881 if (p == NULL) 2882 return FAIL; 2883 #endif 2884 tagp->fname_end = p; 2885 2886 /* find start of search command, after second white space */ 2887 #ifdef FEAT_TAG_ANYWHITE 2888 p = skipwhite(p); 2889 #else 2890 if (*p != NUL) 2891 ++p; 2892 #endif 2893 if (*p == NUL) 2894 return FAIL; 2895 tagp->command = p; 2896 #ifdef FEAT_EMACS_TAGS 2897 } 2898 #endif 2899 2900 return OK; 2901 } 2902 2903 /* 2904 * Check if tagname is a static tag 2905 * 2906 * Static tags produced by the older ctags program have the format: 2907 * 'file:tag file /pattern'. 2908 * This is only recognized when both occurrence of 'file' are the same, to 2909 * avoid recognizing "string::string" or ":exit". 2910 * 2911 * Static tags produced by the new ctags program have the format: 2912 * 'tag file /pattern/;"<Tab>file:' " 2913 * 2914 * Return TRUE if it is a static tag and adjust *tagname to the real tag. 2915 * Return FALSE if it is not a static tag. 2916 */ 2917 static int 2918 test_for_static(tagptrs_T *tagp) 2919 { 2920 char_u *p; 2921 2922 #ifdef FEAT_TAG_OLDSTATIC 2923 int len; 2924 2925 /* 2926 * Check for old style static tag: "file:tag file .." 2927 */ 2928 len = (int)(tagp->fname_end - tagp->fname); 2929 p = tagp->tagname + len; 2930 if ( p < tagp->tagname_end 2931 && *p == ':' 2932 && fnamencmp(tagp->tagname, tagp->fname, len) == 0) 2933 { 2934 tagp->tagname = p + 1; 2935 return TRUE; 2936 } 2937 #endif 2938 2939 /* 2940 * Check for new style static tag ":...<Tab>file:[<Tab>...]" 2941 */ 2942 p = tagp->command; 2943 while ((p = vim_strchr(p, '\t')) != NULL) 2944 { 2945 ++p; 2946 if (STRNCMP(p, "file:", 5) == 0) 2947 return TRUE; 2948 } 2949 2950 return FALSE; 2951 } 2952 2953 /* 2954 * Parse a line from a matching tag. Does not change the line itself. 2955 * 2956 * The line that we get looks like this: 2957 * Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf> 2958 * other tag: <mtt><tag_fname><NUL><NUL><lbuf> 2959 * without Emacs tags: <mtt><tag_fname><NUL><lbuf> 2960 * 2961 * Return OK or FAIL. 2962 */ 2963 static int 2964 parse_match( 2965 char_u *lbuf, /* input: matching line */ 2966 tagptrs_T *tagp) /* output: pointers into the line */ 2967 { 2968 int retval; 2969 char_u *p; 2970 char_u *pc, *pt; 2971 2972 tagp->tag_fname = lbuf + 1; 2973 lbuf += STRLEN(tagp->tag_fname) + 2; 2974 #ifdef FEAT_EMACS_TAGS 2975 if (*lbuf) 2976 { 2977 tagp->is_etag = TRUE; 2978 tagp->fname = lbuf; 2979 lbuf += STRLEN(lbuf); 2980 tagp->fname_end = lbuf++; 2981 } 2982 else 2983 { 2984 tagp->is_etag = FALSE; 2985 ++lbuf; 2986 } 2987 #endif 2988 2989 /* Find search pattern and the file name for non-etags. */ 2990 retval = parse_tag_line(lbuf, 2991 #ifdef FEAT_EMACS_TAGS 2992 tagp->is_etag, 2993 #endif 2994 tagp); 2995 2996 tagp->tagkind = NULL; 2997 tagp->command_end = NULL; 2998 2999 if (retval == OK) 3000 { 3001 /* Try to find a kind field: "kind:<kind>" or just "<kind>"*/ 3002 p = tagp->command; 3003 if (find_extra(&p) == OK) 3004 { 3005 tagp->command_end = p; 3006 p += 2; /* skip ";\"" */ 3007 if (*p++ == TAB) 3008 while (ASCII_ISALPHA(*p)) 3009 { 3010 if (STRNCMP(p, "kind:", 5) == 0) 3011 { 3012 tagp->tagkind = p + 5; 3013 break; 3014 } 3015 pc = vim_strchr(p, ':'); 3016 pt = vim_strchr(p, '\t'); 3017 if (pc == NULL || (pt != NULL && pc > pt)) 3018 { 3019 tagp->tagkind = p; 3020 break; 3021 } 3022 if (pt == NULL) 3023 break; 3024 p = pt + 1; 3025 } 3026 } 3027 if (tagp->tagkind != NULL) 3028 { 3029 for (p = tagp->tagkind; 3030 *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p) 3031 ; 3032 tagp->tagkind_end = p; 3033 } 3034 } 3035 return retval; 3036 } 3037 3038 /* 3039 * Find out the actual file name of a tag. Concatenate the tags file name 3040 * with the matching tag file name. 3041 * Returns an allocated string or NULL (out of memory). 3042 */ 3043 static char_u * 3044 tag_full_fname(tagptrs_T *tagp) 3045 { 3046 char_u *fullname; 3047 int c; 3048 3049 #ifdef FEAT_EMACS_TAGS 3050 if (tagp->is_etag) 3051 c = 0; /* to shut up GCC */ 3052 else 3053 #endif 3054 { 3055 c = *tagp->fname_end; 3056 *tagp->fname_end = NUL; 3057 } 3058 fullname = expand_tag_fname(tagp->fname, tagp->tag_fname, FALSE); 3059 3060 #ifdef FEAT_EMACS_TAGS 3061 if (!tagp->is_etag) 3062 #endif 3063 *tagp->fname_end = c; 3064 3065 return fullname; 3066 } 3067 3068 /* 3069 * Jump to a tag that has been found in one of the tag files 3070 * 3071 * returns OK for success, NOTAGFILE when file not found, FAIL otherwise. 3072 */ 3073 static int 3074 jumpto_tag( 3075 char_u *lbuf, /* line from the tags file for this tag */ 3076 int forceit, /* :ta with ! */ 3077 int keep_help) /* keep help flag (FALSE for cscope) */ 3078 { 3079 int save_secure; 3080 int save_magic; 3081 int save_p_ws, save_p_scs, save_p_ic; 3082 linenr_T save_lnum; 3083 int csave = 0; 3084 char_u *str; 3085 char_u *pbuf; /* search pattern buffer */ 3086 char_u *pbuf_end; 3087 char_u *tofree_fname = NULL; 3088 char_u *fname; 3089 tagptrs_T tagp; 3090 int retval = FAIL; 3091 int getfile_result = GETFILE_UNUSED; 3092 int search_options; 3093 #ifdef FEAT_SEARCH_EXTRA 3094 int save_no_hlsearch; 3095 #endif 3096 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 3097 win_T *curwin_save = NULL; 3098 #endif 3099 char_u *full_fname = NULL; 3100 #ifdef FEAT_FOLDING 3101 int old_KeyTyped = KeyTyped; /* getting the file may reset it */ 3102 #endif 3103 3104 pbuf = alloc(LSIZE); 3105 3106 /* parse the match line into the tagp structure */ 3107 if (pbuf == NULL || parse_match(lbuf, &tagp) == FAIL) 3108 { 3109 tagp.fname_end = NULL; 3110 goto erret; 3111 } 3112 3113 /* truncate the file name, so it can be used as a string */ 3114 csave = *tagp.fname_end; 3115 *tagp.fname_end = NUL; 3116 fname = tagp.fname; 3117 3118 /* copy the command to pbuf[], remove trailing CR/NL */ 3119 str = tagp.command; 3120 for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) 3121 { 3122 #ifdef FEAT_EMACS_TAGS 3123 if (tagp.is_etag && *str == ',')/* stop at ',' after line number */ 3124 break; 3125 #endif 3126 *pbuf_end++ = *str++; 3127 } 3128 *pbuf_end = NUL; 3129 3130 #ifdef FEAT_EMACS_TAGS 3131 if (!tagp.is_etag) 3132 #endif 3133 { 3134 /* 3135 * Remove the "<Tab>fieldname:value" stuff; we don't need it here. 3136 */ 3137 str = pbuf; 3138 if (find_extra(&str) == OK) 3139 { 3140 pbuf_end = str; 3141 *pbuf_end = NUL; 3142 } 3143 } 3144 3145 /* 3146 * Expand file name, when needed (for environment variables). 3147 * If 'tagrelative' option set, may change file name. 3148 */ 3149 fname = expand_tag_fname(fname, tagp.tag_fname, TRUE); 3150 if (fname == NULL) 3151 goto erret; 3152 tofree_fname = fname; /* free() it later */ 3153 3154 /* 3155 * Check if the file with the tag exists before abandoning the current 3156 * file. Also accept a file name for which there is a matching BufReadCmd 3157 * autocommand event (e.g., http://sys/file). 3158 */ 3159 if (mch_getperm(fname) < 0 3160 #ifdef FEAT_AUTOCMD 3161 && !has_autocmd(EVENT_BUFREADCMD, fname, NULL) 3162 #endif 3163 ) 3164 { 3165 retval = NOTAGFILE; 3166 vim_free(nofile_fname); 3167 nofile_fname = vim_strsave(fname); 3168 if (nofile_fname == NULL) 3169 nofile_fname = empty_option; 3170 goto erret; 3171 } 3172 3173 ++RedrawingDisabled; 3174 3175 #ifdef FEAT_GUI 3176 need_mouse_correct = TRUE; 3177 #endif 3178 3179 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 3180 if (g_do_tagpreview != 0) 3181 { 3182 postponed_split = 0; /* don't split again below */ 3183 curwin_save = curwin; /* Save current window */ 3184 3185 /* 3186 * If we are reusing a window, we may change dir when 3187 * entering it (autocommands) so turn the tag filename 3188 * into a fullpath 3189 */ 3190 if (!curwin->w_p_pvw) 3191 { 3192 full_fname = FullName_save(fname, FALSE); 3193 fname = full_fname; 3194 3195 /* 3196 * Make the preview window the current window. 3197 * Open a preview window when needed. 3198 */ 3199 prepare_tagpreview(TRUE); 3200 } 3201 } 3202 3203 /* If it was a CTRL-W CTRL-] command split window now. For ":tab tag" 3204 * open a new tab page. */ 3205 if (postponed_split && (swb_flags & (SWB_USEOPEN | SWB_USETAB))) 3206 { 3207 buf_T *existing_buf = buflist_findname_exp(fname); 3208 3209 if (existing_buf != NULL) 3210 { 3211 win_T *wp = NULL; 3212 3213 if (swb_flags & SWB_USEOPEN) 3214 wp = buf_jump_open_win(existing_buf); 3215 3216 /* If 'switchbuf' contains "usetab": jump to first window in any tab 3217 * page containing "existing_buf" if one exists */ 3218 if (wp == NULL && (swb_flags & SWB_USETAB)) 3219 wp = buf_jump_open_tab(existing_buf); 3220 /* We've switched to the buffer, the usual loading of the file must 3221 * be skipped. */ 3222 if (wp != NULL) 3223 getfile_result = GETFILE_SAME_FILE; 3224 } 3225 } 3226 if (getfile_result == GETFILE_UNUSED 3227 && (postponed_split || cmdmod.tab != 0)) 3228 { 3229 if (win_split(postponed_split > 0 ? postponed_split : 0, 3230 postponed_split_flags) == FAIL) 3231 { 3232 --RedrawingDisabled; 3233 goto erret; 3234 } 3235 RESET_BINDING(curwin); 3236 } 3237 #endif 3238 3239 if (keep_help) 3240 { 3241 /* A :ta from a help file will keep the b_help flag set. For ":ptag" 3242 * we need to use the flag from the window where we came from. */ 3243 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 3244 if (g_do_tagpreview != 0) 3245 keep_help_flag = curwin_save->w_buffer->b_help; 3246 else 3247 #endif 3248 keep_help_flag = curbuf->b_help; 3249 } 3250 if (getfile_result == GETFILE_UNUSED) 3251 getfile_result = getfile(0, fname, NULL, TRUE, (linenr_T)0, forceit); 3252 keep_help_flag = FALSE; 3253 3254 if (GETFILE_SUCCESS(getfile_result)) /* got to the right file */ 3255 { 3256 curwin->w_set_curswant = TRUE; 3257 #ifdef FEAT_WINDOWS 3258 postponed_split = 0; 3259 #endif 3260 3261 save_secure = secure; 3262 secure = 1; 3263 #ifdef HAVE_SANDBOX 3264 ++sandbox; 3265 #endif 3266 save_magic = p_magic; 3267 p_magic = FALSE; /* always execute with 'nomagic' */ 3268 #ifdef FEAT_SEARCH_EXTRA 3269 /* Save value of no_hlsearch, jumping to a tag is not a real search */ 3270 save_no_hlsearch = no_hlsearch; 3271 #endif 3272 3273 /* 3274 * If 'cpoptions' contains 't', store the search pattern for the "n" 3275 * command. If 'cpoptions' does not contain 't', the search pattern 3276 * is not stored. 3277 */ 3278 if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) 3279 search_options = 0; 3280 else 3281 search_options = SEARCH_KEEP; 3282 3283 /* 3284 * If the command is a search, try here. 3285 * 3286 * Reset 'smartcase' for the search, since the search pattern was not 3287 * typed by the user. 3288 * Only use do_search() when there is a full search command, without 3289 * anything following. 3290 */ 3291 str = pbuf; 3292 if (pbuf[0] == '/' || pbuf[0] == '?') 3293 str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1; 3294 if (str > pbuf_end - 1) /* search command with nothing following */ 3295 { 3296 save_p_ws = p_ws; 3297 save_p_ic = p_ic; 3298 save_p_scs = p_scs; 3299 p_ws = TRUE; /* need 'wrapscan' for backward searches */ 3300 p_ic = FALSE; /* don't ignore case now */ 3301 p_scs = FALSE; 3302 #if 0 /* disabled for now */ 3303 #ifdef FEAT_CMDHIST 3304 /* put pattern in search history */ 3305 add_to_history(HIST_SEARCH, pbuf + 1, TRUE, pbuf[0]); 3306 #endif 3307 #endif 3308 save_lnum = curwin->w_cursor.lnum; 3309 curwin->w_cursor.lnum = 0; /* start search before first line */ 3310 if (do_search(NULL, pbuf[0], pbuf + 1, (long)1, 3311 search_options, NULL, NULL)) 3312 retval = OK; 3313 else 3314 { 3315 int found = 1; 3316 int cc; 3317 3318 /* 3319 * try again, ignore case now 3320 */ 3321 p_ic = TRUE; 3322 if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1, 3323 search_options, NULL, NULL)) 3324 { 3325 /* 3326 * Failed to find pattern, take a guess: "^func (" 3327 */ 3328 found = 2; 3329 (void)test_for_static(&tagp); 3330 cc = *tagp.tagname_end; 3331 *tagp.tagname_end = NUL; 3332 sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname); 3333 if (!do_search(NULL, '/', pbuf, (long)1, 3334 search_options, NULL, NULL)) 3335 { 3336 /* Guess again: "^char * \<func (" */ 3337 sprintf((char *)pbuf, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(", 3338 tagp.tagname); 3339 if (!do_search(NULL, '/', pbuf, (long)1, 3340 search_options, NULL, NULL)) 3341 found = 0; 3342 } 3343 *tagp.tagname_end = cc; 3344 } 3345 if (found == 0) 3346 { 3347 EMSG(_("E434: Can't find tag pattern")); 3348 curwin->w_cursor.lnum = save_lnum; 3349 } 3350 else 3351 { 3352 /* 3353 * Only give a message when really guessed, not when 'ic' 3354 * is set and match found while ignoring case. 3355 */ 3356 if (found == 2 || !save_p_ic) 3357 { 3358 MSG(_("E435: Couldn't find tag, just guessing!")); 3359 if (!msg_scrolled && msg_silent == 0) 3360 { 3361 out_flush(); 3362 ui_delay(1000L, TRUE); 3363 } 3364 } 3365 retval = OK; 3366 } 3367 } 3368 p_ws = save_p_ws; 3369 p_ic = save_p_ic; 3370 p_scs = save_p_scs; 3371 3372 /* A search command may have positioned the cursor beyond the end 3373 * of the line. May need to correct that here. */ 3374 check_cursor(); 3375 } 3376 else 3377 { 3378 curwin->w_cursor.lnum = 1; /* start command in line 1 */ 3379 do_cmdline_cmd(pbuf); 3380 retval = OK; 3381 } 3382 3383 /* 3384 * When the command has done something that is not allowed make sure 3385 * the error message can be seen. 3386 */ 3387 if (secure == 2) 3388 wait_return(TRUE); 3389 secure = save_secure; 3390 p_magic = save_magic; 3391 #ifdef HAVE_SANDBOX 3392 --sandbox; 3393 #endif 3394 #ifdef FEAT_SEARCH_EXTRA 3395 /* restore no_hlsearch when keeping the old search pattern */ 3396 if (search_options) 3397 { 3398 SET_NO_HLSEARCH(save_no_hlsearch); 3399 } 3400 #endif 3401 3402 /* Return OK if jumped to another file (at least we found the file!). */ 3403 if (getfile_result == GETFILE_OPEN_OTHER) 3404 retval = OK; 3405 3406 if (retval == OK) 3407 { 3408 /* 3409 * For a help buffer: Put the cursor line at the top of the window, 3410 * the help subject will be below it. 3411 */ 3412 if (curbuf->b_help) 3413 set_topline(curwin, curwin->w_cursor.lnum); 3414 #ifdef FEAT_FOLDING 3415 if ((fdo_flags & FDO_TAG) && old_KeyTyped) 3416 foldOpenCursor(); 3417 #endif 3418 } 3419 3420 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 3421 if (g_do_tagpreview != 0 3422 && curwin != curwin_save && win_valid(curwin_save)) 3423 { 3424 /* Return cursor to where we were */ 3425 validate_cursor(); 3426 redraw_later(VALID); 3427 win_enter(curwin_save, TRUE); 3428 } 3429 #endif 3430 3431 --RedrawingDisabled; 3432 } 3433 else 3434 { 3435 --RedrawingDisabled; 3436 #ifdef FEAT_WINDOWS 3437 if (postponed_split) /* close the window */ 3438 { 3439 win_close(curwin, FALSE); 3440 postponed_split = 0; 3441 } 3442 #endif 3443 } 3444 3445 erret: 3446 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 3447 g_do_tagpreview = 0; /* For next time */ 3448 #endif 3449 if (tagp.fname_end != NULL) 3450 *tagp.fname_end = csave; 3451 vim_free(pbuf); 3452 vim_free(tofree_fname); 3453 vim_free(full_fname); 3454 3455 return retval; 3456 } 3457 3458 /* 3459 * If "expand" is TRUE, expand wildcards in fname. 3460 * If 'tagrelative' option set, change fname (name of file containing tag) 3461 * according to tag_fname (name of tag file containing fname). 3462 * Returns a pointer to allocated memory (or NULL when out of memory). 3463 */ 3464 static char_u * 3465 expand_tag_fname(char_u *fname, char_u *tag_fname, int expand) 3466 { 3467 char_u *p; 3468 char_u *retval; 3469 char_u *expanded_fname = NULL; 3470 expand_T xpc; 3471 3472 /* 3473 * Expand file name (for environment variables) when needed. 3474 */ 3475 if (expand && mch_has_wildcard(fname)) 3476 { 3477 ExpandInit(&xpc); 3478 xpc.xp_context = EXPAND_FILES; 3479 expanded_fname = ExpandOne(&xpc, (char_u *)fname, NULL, 3480 WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); 3481 if (expanded_fname != NULL) 3482 fname = expanded_fname; 3483 } 3484 3485 if ((p_tr || curbuf->b_help) 3486 && !vim_isAbsName(fname) 3487 && (p = gettail(tag_fname)) != tag_fname) 3488 { 3489 retval = alloc(MAXPATHL); 3490 if (retval != NULL) 3491 { 3492 STRCPY(retval, tag_fname); 3493 vim_strncpy(retval + (p - tag_fname), fname, 3494 MAXPATHL - (p - tag_fname) - 1); 3495 /* 3496 * Translate names like "src/a/../b/file.c" into "src/b/file.c". 3497 */ 3498 simplify_filename(retval); 3499 } 3500 } 3501 else 3502 retval = vim_strsave(fname); 3503 3504 vim_free(expanded_fname); 3505 3506 return retval; 3507 } 3508 3509 /* 3510 * Converts a file name into a canonical form. It simplifies a file name into 3511 * its simplest form by stripping out unneeded components, if any. The 3512 * resulting file name is simplified in place and will either be the same 3513 * length as that supplied, or shorter. 3514 */ 3515 void 3516 simplify_filename(char_u *filename) 3517 { 3518 #ifndef AMIGA /* Amiga doesn't have "..", it uses "/" */ 3519 int components = 0; 3520 char_u *p, *tail, *start; 3521 int stripping_disabled = FALSE; 3522 int relative = TRUE; 3523 3524 p = filename; 3525 #ifdef BACKSLASH_IN_FILENAME 3526 if (p[1] == ':') /* skip "x:" */ 3527 p += 2; 3528 #endif 3529 3530 if (vim_ispathsep(*p)) 3531 { 3532 relative = FALSE; 3533 do 3534 ++p; 3535 while (vim_ispathsep(*p)); 3536 } 3537 start = p; /* remember start after "c:/" or "/" or "///" */ 3538 3539 do 3540 { 3541 /* At this point "p" is pointing to the char following a single "/" 3542 * or "p" is at the "start" of the (absolute or relative) path name. */ 3543 #ifdef VMS 3544 /* VMS allows device:[path] - don't strip the [ in directory */ 3545 if ((*p == '[' || *p == '<') && p > filename && p[-1] == ':') 3546 { 3547 /* :[ or :< composition: vms directory component */ 3548 ++components; 3549 p = getnextcomp(p + 1); 3550 } 3551 /* allow remote calls as host"user passwd"::device:[path] */ 3552 else if (p[0] == ':' && p[1] == ':' && p > filename && p[-1] == '"' ) 3553 { 3554 /* ":: composition: vms host/passwd component */ 3555 ++components; 3556 p = getnextcomp(p + 2); 3557 } 3558 else 3559 #endif 3560 if (vim_ispathsep(*p)) 3561 STRMOVE(p, p + 1); /* remove duplicate "/" */ 3562 else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL)) 3563 { 3564 if (p == start && relative) 3565 p += 1 + (p[1] != NUL); /* keep single "." or leading "./" */ 3566 else 3567 { 3568 /* Strip "./" or ".///". If we are at the end of the file name 3569 * and there is no trailing path separator, either strip "/." if 3570 * we are after "start", or strip "." if we are at the beginning 3571 * of an absolute path name . */ 3572 tail = p + 1; 3573 if (p[1] != NUL) 3574 while (vim_ispathsep(*tail)) 3575 MB_PTR_ADV(tail); 3576 else if (p > start) 3577 --p; /* strip preceding path separator */ 3578 STRMOVE(p, tail); 3579 } 3580 } 3581 else if (p[0] == '.' && p[1] == '.' && 3582 (vim_ispathsep(p[2]) || p[2] == NUL)) 3583 { 3584 /* Skip to after ".." or "../" or "..///". */ 3585 tail = p + 2; 3586 while (vim_ispathsep(*tail)) 3587 MB_PTR_ADV(tail); 3588 3589 if (components > 0) /* strip one preceding component */ 3590 { 3591 int do_strip = FALSE; 3592 char_u saved_char; 3593 stat_T st; 3594 3595 /* Don't strip for an erroneous file name. */ 3596 if (!stripping_disabled) 3597 { 3598 /* If the preceding component does not exist in the file 3599 * system, we strip it. On Unix, we don't accept a symbolic 3600 * link that refers to a non-existent file. */ 3601 saved_char = p[-1]; 3602 p[-1] = NUL; 3603 #ifdef UNIX 3604 if (mch_lstat((char *)filename, &st) < 0) 3605 #else 3606 if (mch_stat((char *)filename, &st) < 0) 3607 #endif 3608 do_strip = TRUE; 3609 p[-1] = saved_char; 3610 3611 --p; 3612 /* Skip back to after previous '/'. */ 3613 while (p > start && !after_pathsep(start, p)) 3614 MB_PTR_BACK(start, p); 3615 3616 if (!do_strip) 3617 { 3618 /* If the component exists in the file system, check 3619 * that stripping it won't change the meaning of the 3620 * file name. First get information about the 3621 * unstripped file name. This may fail if the component 3622 * to strip is not a searchable directory (but a regular 3623 * file, for instance), since the trailing "/.." cannot 3624 * be applied then. We don't strip it then since we 3625 * don't want to replace an erroneous file name by 3626 * a valid one, and we disable stripping of later 3627 * components. */ 3628 saved_char = *tail; 3629 *tail = NUL; 3630 if (mch_stat((char *)filename, &st) >= 0) 3631 do_strip = TRUE; 3632 else 3633 stripping_disabled = TRUE; 3634 *tail = saved_char; 3635 #ifdef UNIX 3636 if (do_strip) 3637 { 3638 stat_T new_st; 3639 3640 /* On Unix, the check for the unstripped file name 3641 * above works also for a symbolic link pointing to 3642 * a searchable directory. But then the parent of 3643 * the directory pointed to by the link must be the 3644 * same as the stripped file name. (The latter 3645 * exists in the file system since it is the 3646 * component's parent directory.) */ 3647 if (p == start && relative) 3648 (void)mch_stat(".", &new_st); 3649 else 3650 { 3651 saved_char = *p; 3652 *p = NUL; 3653 (void)mch_stat((char *)filename, &new_st); 3654 *p = saved_char; 3655 } 3656 3657 if (new_st.st_ino != st.st_ino || 3658 new_st.st_dev != st.st_dev) 3659 { 3660 do_strip = FALSE; 3661 /* We don't disable stripping of later 3662 * components since the unstripped path name is 3663 * still valid. */ 3664 } 3665 } 3666 #endif 3667 } 3668 } 3669 3670 if (!do_strip) 3671 { 3672 /* Skip the ".." or "../" and reset the counter for the 3673 * components that might be stripped later on. */ 3674 p = tail; 3675 components = 0; 3676 } 3677 else 3678 { 3679 /* Strip previous component. If the result would get empty 3680 * and there is no trailing path separator, leave a single 3681 * "." instead. If we are at the end of the file name and 3682 * there is no trailing path separator and a preceding 3683 * component is left after stripping, strip its trailing 3684 * path separator as well. */ 3685 if (p == start && relative && tail[-1] == '.') 3686 { 3687 *p++ = '.'; 3688 *p = NUL; 3689 } 3690 else 3691 { 3692 if (p > start && tail[-1] == '.') 3693 --p; 3694 STRMOVE(p, tail); /* strip previous component */ 3695 } 3696 3697 --components; 3698 } 3699 } 3700 else if (p == start && !relative) /* leading "/.." or "/../" */ 3701 STRMOVE(p, tail); /* strip ".." or "../" */ 3702 else 3703 { 3704 if (p == start + 2 && p[-2] == '.') /* leading "./../" */ 3705 { 3706 STRMOVE(p - 2, p); /* strip leading "./" */ 3707 tail -= 2; 3708 } 3709 p = tail; /* skip to char after ".." or "../" */ 3710 } 3711 } 3712 else 3713 { 3714 ++components; /* simple path component */ 3715 p = getnextcomp(p); 3716 } 3717 } while (*p != NUL); 3718 #endif /* !AMIGA */ 3719 } 3720 3721 /* 3722 * Check if we have a tag for the buffer with name "buf_ffname". 3723 * This is a bit slow, because of the full path compare in fullpathcmp(). 3724 * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current 3725 * file. 3726 */ 3727 static int 3728 test_for_current( 3729 #ifdef FEAT_EMACS_TAGS 3730 int is_etag, 3731 #endif 3732 char_u *fname, 3733 char_u *fname_end, 3734 char_u *tag_fname, 3735 char_u *buf_ffname) 3736 { 3737 int c; 3738 int retval = FALSE; 3739 char_u *fullname; 3740 3741 if (buf_ffname != NULL) /* if the buffer has a name */ 3742 { 3743 #ifdef FEAT_EMACS_TAGS 3744 if (is_etag) 3745 c = 0; /* to shut up GCC */ 3746 else 3747 #endif 3748 { 3749 c = *fname_end; 3750 *fname_end = NUL; 3751 } 3752 fullname = expand_tag_fname(fname, tag_fname, TRUE); 3753 if (fullname != NULL) 3754 { 3755 retval = (fullpathcmp(fullname, buf_ffname, TRUE) & FPC_SAME); 3756 vim_free(fullname); 3757 } 3758 #ifdef FEAT_EMACS_TAGS 3759 if (!is_etag) 3760 #endif 3761 *fname_end = c; 3762 } 3763 3764 return retval; 3765 } 3766 3767 /* 3768 * Find the end of the tagaddress. 3769 * Return OK if ";\"" is following, FAIL otherwise. 3770 */ 3771 static int 3772 find_extra(char_u **pp) 3773 { 3774 char_u *str = *pp; 3775 3776 /* Repeat for addresses separated with ';' */ 3777 for (;;) 3778 { 3779 if (VIM_ISDIGIT(*str)) 3780 str = skipdigits(str); 3781 else if (*str == '/' || *str == '?') 3782 { 3783 str = skip_regexp(str + 1, *str, FALSE, NULL); 3784 if (*str != **pp) 3785 str = NULL; 3786 else 3787 ++str; 3788 } 3789 else 3790 str = NULL; 3791 if (str == NULL || *str != ';' 3792 || !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?')) 3793 break; 3794 ++str; /* skip ';' */ 3795 } 3796 3797 if (str != NULL && STRNCMP(str, ";\"", 2) == 0) 3798 { 3799 *pp = str; 3800 return OK; 3801 } 3802 return FAIL; 3803 } 3804 3805 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 3806 int 3807 expand_tags( 3808 int tagnames, /* expand tag names */ 3809 char_u *pat, 3810 int *num_file, 3811 char_u ***file) 3812 { 3813 int i; 3814 int c; 3815 int tagnmflag; 3816 char_u tagnm[100]; 3817 tagptrs_T t_p; 3818 int ret; 3819 3820 if (tagnames) 3821 tagnmflag = TAG_NAMES; 3822 else 3823 tagnmflag = 0; 3824 if (pat[0] == '/') 3825 ret = find_tags(pat + 1, num_file, file, 3826 TAG_REGEXP | tagnmflag | TAG_VERBOSE, 3827 TAG_MANY, curbuf->b_ffname); 3828 else 3829 ret = find_tags(pat, num_file, file, 3830 TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NOIC, 3831 TAG_MANY, curbuf->b_ffname); 3832 if (ret == OK && !tagnames) 3833 { 3834 /* Reorganize the tags for display and matching as strings of: 3835 * "<tagname>\0<kind>\0<filename>\0" 3836 */ 3837 for (i = 0; i < *num_file; i++) 3838 { 3839 parse_match((*file)[i], &t_p); 3840 c = (int)(t_p.tagname_end - t_p.tagname); 3841 mch_memmove(tagnm, t_p.tagname, (size_t)c); 3842 tagnm[c++] = 0; 3843 tagnm[c++] = (t_p.tagkind != NULL && *t_p.tagkind) 3844 ? *t_p.tagkind : 'f'; 3845 tagnm[c++] = 0; 3846 mch_memmove((*file)[i] + c, t_p.fname, t_p.fname_end - t_p.fname); 3847 (*file)[i][c + (t_p.fname_end - t_p.fname)] = 0; 3848 mch_memmove((*file)[i], tagnm, (size_t)c); 3849 } 3850 } 3851 return ret; 3852 } 3853 #endif 3854 3855 #if defined(FEAT_EVAL) || defined(PROTO) 3856 static int add_tag_field(dict_T *dict, char *field_name, char_u *start, char_u *end); 3857 3858 /* 3859 * Add a tag field to the dictionary "dict". 3860 * Return OK or FAIL. 3861 */ 3862 static int 3863 add_tag_field( 3864 dict_T *dict, 3865 char *field_name, 3866 char_u *start, /* start of the value */ 3867 char_u *end) /* after the value; can be NULL */ 3868 { 3869 char_u *buf; 3870 int len = 0; 3871 int retval; 3872 3873 /* check that the field name doesn't exist yet */ 3874 if (dict_find(dict, (char_u *)field_name, -1) != NULL) 3875 { 3876 if (p_verbose > 0) 3877 { 3878 verbose_enter(); 3879 smsg((char_u *)_("Duplicate field name: %s"), field_name); 3880 verbose_leave(); 3881 } 3882 return FAIL; 3883 } 3884 buf = alloc(MAXPATHL); 3885 if (buf == NULL) 3886 return FAIL; 3887 if (start != NULL) 3888 { 3889 if (end == NULL) 3890 { 3891 end = start + STRLEN(start); 3892 while (end > start && (end[-1] == '\r' || end[-1] == '\n')) 3893 --end; 3894 } 3895 len = (int)(end - start); 3896 if (len > MAXPATHL - 1) 3897 len = MAXPATHL - 1; 3898 vim_strncpy(buf, start, len); 3899 } 3900 buf[len] = NUL; 3901 retval = dict_add_nr_str(dict, field_name, 0L, buf); 3902 vim_free(buf); 3903 return retval; 3904 } 3905 3906 /* 3907 * Add the tags matching the specified pattern "pat" to the list "list" 3908 * as a dictionary. Use "buf_fname" for priority, unless NULL. 3909 */ 3910 int 3911 get_tags(list_T *list, char_u *pat, char_u *buf_fname) 3912 { 3913 int num_matches, i, ret; 3914 char_u **matches, *p; 3915 char_u *full_fname; 3916 dict_T *dict; 3917 tagptrs_T tp; 3918 long is_static; 3919 3920 ret = find_tags(pat, &num_matches, &matches, 3921 TAG_REGEXP | TAG_NOIC, (int)MAXCOL, buf_fname); 3922 if (ret == OK && num_matches > 0) 3923 { 3924 for (i = 0; i < num_matches; ++i) 3925 { 3926 parse_match(matches[i], &tp); 3927 is_static = test_for_static(&tp); 3928 3929 /* Skip pseudo-tag lines. */ 3930 if (STRNCMP(tp.tagname, "!_TAG_", 6) == 0) 3931 continue; 3932 3933 if ((dict = dict_alloc()) == NULL) 3934 ret = FAIL; 3935 if (list_append_dict(list, dict) == FAIL) 3936 ret = FAIL; 3937 3938 full_fname = tag_full_fname(&tp); 3939 if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL 3940 || add_tag_field(dict, "filename", full_fname, 3941 NULL) == FAIL 3942 || add_tag_field(dict, "cmd", tp.command, 3943 tp.command_end) == FAIL 3944 || add_tag_field(dict, "kind", tp.tagkind, 3945 tp.tagkind_end) == FAIL 3946 || dict_add_nr_str(dict, "static", is_static, NULL) == FAIL) 3947 ret = FAIL; 3948 3949 vim_free(full_fname); 3950 3951 if (tp.command_end != NULL) 3952 { 3953 for (p = tp.command_end + 3; 3954 *p != NUL && *p != '\n' && *p != '\r'; ++p) 3955 { 3956 if (p == tp.tagkind || (p + 5 == tp.tagkind 3957 && STRNCMP(p, "kind:", 5) == 0)) 3958 /* skip "kind:<kind>" and "<kind>" */ 3959 p = tp.tagkind_end - 1; 3960 else if (STRNCMP(p, "file:", 5) == 0) 3961 /* skip "file:" (static tag) */ 3962 p += 4; 3963 else if (!VIM_ISWHITE(*p)) 3964 { 3965 char_u *s, *n; 3966 int len; 3967 3968 /* Add extra field as a dict entry. Fields are 3969 * separated by Tabs. */ 3970 n = p; 3971 while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') 3972 ++p; 3973 len = (int)(p - n); 3974 if (*p == ':' && len > 0) 3975 { 3976 s = ++p; 3977 while (*p != NUL && *p >= ' ') 3978 ++p; 3979 n[len] = NUL; 3980 if (add_tag_field(dict, (char *)n, s, p) == FAIL) 3981 ret = FAIL; 3982 n[len] = ':'; 3983 } 3984 else 3985 /* Skip field without colon. */ 3986 while (*p != NUL && *p >= ' ') 3987 ++p; 3988 if (*p == NUL) 3989 break; 3990 } 3991 } 3992 } 3993 3994 vim_free(matches[i]); 3995 } 3996 vim_free(matches); 3997 } 3998 return ret; 3999 } 4000 #endif 4001