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