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