📄 tag.c
字号:
* Not jumping around in the file: Read the next line.
*/
else
#endif
{
/* skip empty and blank lines */
do
{
#ifdef USE_CSCOPE
if (use_cscope)
eof = cs_fgets(lbuf, LSIZE);
else
#endif
eof = vim_fgets(lbuf, LSIZE, fp);
} while (!eof && vim_isblankline(lbuf));
if (eof
#ifdef USE_CSCOPE
&& !use_cscope
#endif
)
#ifdef EMACS_TAGS
if (incstack_idx) /* this was an included file */
{
--incstack_idx;
fclose(fp); /* end of this file ... */
fp = incstack[incstack_idx].fp;
STRCPY(tag_fname, incstack[incstack_idx].etag_fname);
vim_free(incstack[incstack_idx].etag_fname);
is_etag = 1; /* (only etags can include) */
continue; /* ... continue with parent file */
}
else
#endif
break; /* end of file */
}
line_read_in:
#ifdef EMACS_TAGS
/*
* Emacs tags line with CTRL-L: New file name on next line.
* The file name is followed by a ','.
*/
if (*lbuf == Ctrl('L')) /* remember etag file name in ebuf */
{
is_etag = 1; /* in case at the start */
state = TS_LINEAR;
if (!vim_fgets(ebuf, LSIZE, fp))
{
for (p = ebuf; *p && *p != ','; p++)
;
*p = NUL;
/*
* atoi(p+1) is the number of bytes before the next ^L
* unless it is an include statement.
*/
if (STRNCMP(p + 1, "include", 7) == 0
&& incstack_idx < INCSTACK_SIZE)
{
if ((incstack[incstack_idx].etag_fname =
vim_strsave(tag_fname)) != NULL)
{
incstack[incstack_idx].fp = fp;
if ((fp = fopen((char *)ebuf, "r")) == NULL)
{
fp = incstack[incstack_idx].fp;
vim_free(incstack[incstack_idx].etag_fname);
}
else
{
STRCPY(tag_fname, ebuf);
++incstack_idx;
}
is_etag = 0; /* we can include anything */
}
}
}
continue;
}
#endif
/*
* When still at the start of the file, check for Emacs tags file
* format, and for "not sorted" flag.
*/
if (state == TS_START)
{
#ifdef BINARY_TAGS
/*
* When there is no tag head, or ignoring case, need to do a
* linear search.
* When no "!_TAG_" is found, default to binary search. If
* the tag file isn't sorted, the second loop will find it.
* When "!_TAG_FILE_SORTED" found: start binary search if
* flag set.
* For cscope, it's always linear.
*/
#ifdef USE_CSCOPE
if (linear || use_cscope)
#else
if (linear)
#endif
state = TS_LINEAR;
else if (STRNCMP(lbuf, "!_TAG_", 6) > 0)
state = TS_BINARY;
else if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0)
{
/* Check sorted flag */
if (lbuf[18] == '1')
state = TS_BINARY;
else
state = TS_LINEAR;
}
#else
state = TS_LINEAR;
#endif
#ifdef BINARY_TAGS
/*
* When starting a binary search, get the size of the file and
* compute the first offset.
*/
if (state == TS_BINARY)
{
/* Get the tag file size (don't use fstat(), it's not
* portable). */
if ((filesize = lseek(fileno(fp),
(off_t)0L, SEEK_END)) <= 0)
state = TS_LINEAR;
else
{
lseek(fileno(fp), (off_t)0L, SEEK_SET);
/* Calculate the first read offset in the file. Start
* the search in the middle of the file.
*/
search_info.low_offset = 0;
search_info.low_char = 0;
search_info.high_offset = filesize;
search_info.high_char = 0xff;
}
continue;
}
#endif
}
/*
* Figure out where the different strings are in this line.
* For "normal" tags: Do a quick check if the tag matches.
* This speeds up tag searching a lot!
*/
if (patheadlen
#ifdef EMACS_TAGS
&& !is_etag
#endif
)
{
tagp.tagname = lbuf;
#ifdef TAG_ANY_WHITE
tagp.tagname_end = skiptowhite(lbuf);
if (*tagp.tagname_end == NUL) /* corrupted tag line */
#else
tagp.tagname_end = vim_strchr(lbuf, TAB);
if (tagp.tagname_end == NULL) /* corrupted tag line */
#endif
{
EMSG2(e_tagformat, tag_fname);
stop_searching = TRUE;
break;
}
#ifdef OLD_STATIC_TAGS
/*
* Check for old style static tag: "file:tag file .."
*/
tagp.fname = NULL;
for (p = lbuf; p < tagp.tagname_end; ++p)
{
if (*p == ':')
{
if (tagp.fname == NULL)
#ifdef TAG_ANY_WHITE
tagp.fname = skipwhite(tagp.tagname_end);
#else
tagp.fname = tagp.tagname_end + 1;
#endif
if ( fnamencmp(lbuf, tagp.fname, p - lbuf) == 0
#ifdef TAG_ANY_WHITE
&& vim_iswhite(tagp.fname[p - lbuf])
#else
&& tagp.fname[p - lbuf] == TAB
#endif
)
{
/* found one */
tagp.tagname = p + 1;
break;
}
}
}
#endif
/*
* Skip this line if the length of the tag is different and
* there is no regexp, or the tag is too short.
*/
cmplen = tagp.tagname_end - tagp.tagname;
if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
cmplen = p_tl;
if (has_re && patheadlen < cmplen)
cmplen = patheadlen;
else if (state == TS_LINEAR && patheadlen != cmplen)
continue;
#ifdef BINARY_TAGS
if (state == TS_BINARY)
{
/*
* Simplistic check for unsorted tags file.
*/
if ((int)tagp.tagname[0] < search_info.low_char
|| (int)tagp.tagname[0] > search_info.high_char)
sort_error = TRUE;
/*
* Compare the current tag with the searched tag.
*/
tagcmp = STRNCMP(tagp.tagname, pathead, cmplen);
/*
* A match with a shorter tag means to search forward.
* A match with a longer tag means to search backward.
*/
if (tagcmp == 0)
{
if (cmplen < patheadlen)
tagcmp = -1;
else if (cmplen > patheadlen)
tagcmp = 1;
}
if (tagcmp == 0)
{
/* We've located the tag, now skip back and search
* forward until the first matching tag is found.
*/
state = TS_SKIP_BACK;
search_info.match_offset = search_info.curr_offset;
continue;
}
if (tagcmp < 0)
{
search_info.curr_offset = ftell(fp);
if (search_info.curr_offset < search_info.high_offset)
{
search_info.low_offset = search_info.curr_offset;
search_info.low_char = tagp.tagname[0];
continue;
}
}
if (tagcmp > 0
&& search_info.curr_offset != search_info.high_offset)
{
search_info.high_offset = search_info.curr_offset;
search_info.high_char = tagp.tagname[0];
continue;
}
/* No match yet and are at the end of the binary search. */
break;
}
else if (state == TS_SKIP_BACK)
{
if (STRNICMP(tagp.tagname, pathead, cmplen) != 0)
state = TS_STEP_FORWARD;
continue;
}
else if (state == TS_STEP_FORWARD)
{
if (STRNICMP(tagp.tagname, pathead, cmplen))
{
if (ftell(fp) > search_info.match_offset)
break; /* past last match */
else
continue; /* before first match */
}
}
else
#endif
/* skip this match if it can't match */
if (STRNICMP(tagp.tagname, pathead, cmplen))
continue;
/*
* Can be a matching tag, isolate the file name and command.
*/
#ifdef OLD_STATIC_TAGS
if (tagp.fname == NULL)
#endif
#ifdef TAG_ANY_WHITE
tagp.fname = skipwhite(tagp.tagname_end);
#else
tagp.fname = tagp.tagname_end + 1;
#endif
#ifdef TAG_ANY_WHITE
tagp.fname_end = skiptowhite(tagp.fname);
tagp.command = skipwhite(tagp.fname_end);
if (*tagp.command == NUL)
#else
tagp.fname_end = vim_strchr(tagp.fname, TAB);
tagp.command = tagp.fname_end + 1;
if (tagp.fname_end == NULL)
#endif
i = FAIL;
else
i = OK;
}
else
i = parse_tag_line(lbuf,
#ifdef EMACS_TAGS
is_etag,
#endif
&tagp);
if (i == FAIL)
{
EMSG2(e_tagformat, tag_fname);
stop_searching = TRUE;
break;
}
#ifdef EMACS_TAGS
if (is_etag)
tagp.fname = ebuf;
#endif
/*
* First try matching with the pattern literally (also when it is
* a regexp).
*/
cmplen = tagp.tagname_end - tagp.tagname;
if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
cmplen = p_tl;
/* if tag length does not match, don't try comparing */
if (patlen != cmplen)
match = FALSE;
else
{
if (reg_ic)
{
match = (STRNICMP(tagp.tagname, pat, cmplen) == 0);
if (match)
match_no_ic = (STRNCMP(tagp.tagname, pat, cmplen) == 0);
}
else
match = (STRNCMP(tagp.tagname, pat, cmplen) == 0);
}
/*
* Has a regexp: Also find tags matching regexp "prog".
*/
match_re = FALSE;
if (!match && prog != NULL)
{
int cc;
cc = *tagp.tagname_end;
*tagp.tagname_end = NUL;
match = vim_regexec(prog, tagp.tagname, TRUE);
matchoff = (int)(prog->startp[0] - tagp.tagname);
if (match && reg_ic)
{
reg_ic = FALSE;
match_no_ic = vim_regexec(prog, tagp.tagname, TRUE);
reg_ic = TRUE;
}
*tagp.tagname_end = cc;
match_re = TRUE;
}
/*
* If a match is found, add it to ga_match[].
*/
if (match)
{
/* Decide in which array to store this match. */
is_current = test_for_current(
#ifdef EMACS_TAGS
is_etag,
#endif
tagp.fname, tagp.fname_end, tag_fname);
#ifdef EMACS_TAGS
is_static = FALSE;
if (!is_etag) /* emacs tags are never static */
#endif
{
#ifdef OLD_STATIC_TAGS
if (tagp.tagname != lbuf) /* detected static tag before */
is_static = TRUE;
else
#endif
is_static = test_for_static(&tagp);
}
/* decide in which of the six table to store this match */
if (is_static)
{
if (is_current)
mtt = MT_ST_CUR;
else
mtt = MT_ST_OTH;
}
else
{
if (is_current)
mtt = MT_GL_CUR;
else
mtt = MT_GL_OTH;
}
if (reg_ic && !match_no_ic)
mtt += MT_IC_OFF;
if (match_re)
mtt += MT_RE_OFF;
if (ga_grow(&ga_match[mtt], 1) == OK)
{
if (help_only)
{
/*
* Append the help-heuristic number after the
* tagname, for sorting it later.
*/
*tagp.tagname_end = NUL;
len = tagp.tagname_end - tagp.tagname;
p = vim_strnsave(tagp.tagname, len + 10);
if (p != NULL)
sprintf((char *)p + len + 1, "%06d",
help_heuristic(tagp.tagname,
match_re ? matchoff : 0, !match_no_ic));
*tagp.tagname_end = TAB;
++len; /* compare one more char */
}
else if (name_only)
{
p = NULL;
len = 0;
if (get_it_again)
{
char_u *temp_end = tagp.command;
if ((*temp_end) == '/')
while ( *temp_end && (*temp_end != '\r')
&& (*temp_end != '\n')
&& (*temp_end != '$'))
temp_end++;
if ((tagp.command + 2) < temp_end)
{
len = temp_end - tagp.command - 2;
p = vim_strnsave(tagp.command + 2, len);
}
get_it_again = FALSE;
}
else
{
len = tagp.tagname_end - tagp.tagname;
p = vim_strnsave(tagp.tagname, len);
/* if wanted, re-read line to get long form too*/
if (State & INSERT)
get_it_again = p_sft;
}
++len; /* compare one more char */
}
else
{
/* Save the tag in a buffer.
* Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf>
* other tag: <mtt><tag_fname><NUL><NUL><lbuf>
* without Emacs tags: <mtt><tag_fname><NUL><lbuf>
*/
len = STRLEN(tag_fname) + STRLEN(lbuf) + 3;
#ifdef EMACS_TAGS
if (is_etag)
len += STRLEN(ebuf) + 1;
else
++len;
#endif
p = alloc(len);
if (p != NULL)
{
p[0] = mtt;
STRCPY(p + 1, tag_fname);
s = p + 1 + STRLEN(tag_fname) + 1;
#ifdef EMACS_TAGS
if (is_etag)
{
STRCPY(s, ebuf);
s += STRLEN(ebuf) + 1;
}
else
*s++ = NUL;
#endif
STRCPY(s, lbuf);
}
}
if (p != NULL)
{
/*
* Don't add identical matches.
*/
for (i = ga_match[mtt].ga_len; --i >= 0; )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -