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