⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tag.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
			    if (vim_memcmp(
				      ((char_u **)(ga_match[mtt].ga_data))[i],
							 p, (size_t)len) == 0)
				break;
			if (i < 0)
			{
			    ((char_u **)(ga_match[mtt].ga_data))
						 [ga_match[mtt].ga_len++] = p;
			    ga_match[mtt].ga_room--;
			    ++match_count;
			}
			else
			    vim_free(p);
		    }
		}
		else    /* Out of memory! Just forget about the rest. */
		{
		    retval = OK;
		    stop_searching = TRUE;
		    break;
		}
	    }
#ifdef USE_CSCOPE
	    if (use_cscope && eof)
		break;
#endif
	} /* not got_int */

#ifdef USE_CSCOPE
	if (!use_cscope)
#endif
	    fclose(fp);
#ifdef EMACS_TAGS
	while (incstack_idx)
	{
	    --incstack_idx;
	    fclose(incstack[incstack_idx].fp);
	    vim_free(incstack[incstack_idx].etag_fname);
	}
#endif

#ifdef BINARY_TAGS
	if (sort_error)
	{
	    EMSG2("Tags file not sorted: %s", tag_fname);
	    sort_error = FALSE;
	}
#endif

	/*
	 * Stop searching if sufficient tags have been found.
	 */
	if (match_count >= mincount)
	{
	    retval = OK;
	    stop_searching = TRUE;
	}

#ifdef USE_CSCOPE
	if (stop_searching || use_cscope)
#else
	if (stop_searching)
#endif
	    break;

    } /* end of for-each-file loop */

#ifdef BINARY_TAGS
      /* stop searching when already did a linear search, or when
       * TAG_NOIC used, and 'ignorecase' not set */
      if (stop_searching || linear || (!p_ic && noic))
	  break;
# ifdef USE_CSCOPE
      if (use_cscope)
	  break;
# endif
      reg_ic = TRUE;	/* try another time while ignoring case */
    }
#endif

    if (!stop_searching)
    {
	if (!did_open && verbose)	/* never opened any tags file */
	    EMSG("No tags file");
	retval = OK;		/* It's OK even when no tag found */
    }

findtag_end:
    vim_free(lbuf);
    vim_free(prog);
    vim_free(tag_fname);
#ifdef EMACS_TAGS
    vim_free(ebuf);
#endif

    /*
     * Move the matches from the ga_match[] arrays into one list of
     * matches.  When retval == FAIL, free the matches.
     */
    if (retval == FAIL)
	match_count = 0;

    if (match_count > 0)
	matches = (char_u **)lalloc((long_u)(match_count * sizeof(char_u *)),
									TRUE);
    else
	matches = NULL;
    match_count = 0;
    for (mtt = 0; mtt < MT_COUNT; ++mtt)
    {
	for (i = 0; i < ga_match[mtt].ga_len; ++i)
	{
	    p = ((char_u **)(ga_match[mtt].ga_data))[i];
	    if (matches == NULL)
		vim_free(p);
	    else
		matches[match_count++] = p;
	}
	ga_clear(&ga_match[mtt]);
    }

    *matchesp = matches;
    *num_matches = match_count;

    curbuf->b_help = help_save;

    return retval;
}

/*
 * Get the next name of a tag file from the tag file list.
 * For help files, use "tags" file only.
 *
 * Return FAIL if no more tag file names, OK otherwise.
 */
    static int
get_tagfname(first, buf)
    int	    first;	    /* TRUE when first file name is wanted */
    char_u  *buf;	    /* pointer to buffer of LSIZE chars */
{
    static char_u   *np = NULL;
    char_u	    *fname;
    size_t	    path_len, fname_len;
    /*
     * A list is kept of the files that have been visited.
     */
    struct visited
    {
	struct visited	*v_next;
#if defined(UNIX)
	struct stat	v_st;
#else
	char_u		v_fname[1];	/* actually longer */
#endif
    };
    static struct visited   *first_visited = NULL;
    struct visited	    *vp;
#ifdef UNIX
    struct stat		    st;
#else
    char_u		    *expand_buf;
#endif

    if (first)
    {
	np = p_tags;
	while (first_visited != NULL)
	{
	    vp = first_visited->v_next;
	    vim_free(first_visited);
	    first_visited = vp;
	}
    }

    if (np == NULL)	    /* tried allready (or bogus call) */
	return FAIL;

    /*
     * For a help window only try the file 'tags' in the same
     * directory as 'helpfile'.
     */
    if (curbuf->b_help)
    {
	path_len = gettail(p_hf) - p_hf;
	if (path_len + 9 >= LSIZE)
	    return FAIL;
	mch_memmove(buf, p_hf, path_len);
	STRCPY(buf + path_len, "tags");

	np = NULL;		/* try only once */
    }

    else
    {
#ifndef UNIX
	expand_buf = alloc(MAXPATHL);
	if (expand_buf == NULL)
	    return FAIL;
#endif

	/*
	 * Loop until we have found a file name that can be used.
	 */
	for (;;)
	{
	    if (*np == NUL)	    /* tried all possibilities */
	    {
#ifndef UNIX
		vim_free(expand_buf);
#endif
		return FAIL;
	    }

	    /*
	     * Copy next file name into buf.
	     */
	    (void)copy_option_part(&np, buf, LSIZE, " ,");

	    /*
	     * Tag file name starting with "./": Replace '.' with path of
	     * current file.
	     * Only do this when 't' flag not included in 'cpo'.
	     */
	    if (buf[0] == '.' && vim_ispathsep(buf[1])
				     && vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
	    {
		if (curbuf->b_fname == NULL)	/* skip if no file name */
		    continue;

		path_len = gettail(curbuf->b_fname) - curbuf->b_fname;
		fname = buf + 1;
		while (vim_ispathsep(*fname))	/* skip '/' and the like */
		    ++fname;
		fname_len = STRLEN(fname);
		if (fname_len + path_len + 1 > LSIZE)
		    continue;
		mch_memmove(buf + path_len, fname, fname_len + 1);
		mch_memmove(buf, curbuf->b_fname, path_len);
	    }

	    /*
	     * Check if this tags file has been used already.
	     * If file doesn't exist, skip it.
	     */
#if defined(UNIX)
	    if (stat((char *)buf, &st) < 0)
#else
	    if (mch_FullName(buf, expand_buf, MAXPATHL, TRUE) == FAIL)
#endif
		continue;

	    for (vp = first_visited; vp != NULL; vp = vp->v_next)
#if defined(UNIX)
		if (vp->v_st.st_dev == st.st_dev &&
						 vp->v_st.st_ino == st.st_ino)
#else
		if (fnamecmp(vp->v_fname, expand_buf) == 0)
#endif
		    break;

	    if (vp != NULL)	    /* already visited, skip it */
		continue;

	    /*
	     * Found the next name.  Add it to the list of visited files.
	     */
#ifdef UNIX
	    vp = (struct visited *)alloc((unsigned)sizeof(struct visited));
#else
	    vp = (struct visited *)alloc((unsigned)(sizeof(struct visited) +
							 STRLEN(expand_buf)));
#endif
	    if (vp != NULL)
	    {
#ifdef UNIX
		vp->v_st = st;
#else
		STRCPY(vp->v_fname, expand_buf);
#endif
		vp->v_next = first_visited;
		first_visited = vp;
	    }
	    break;
	}
#ifndef UNIX
	vim_free(expand_buf);
#endif
    }
    return OK;
}

/*
 * Parse one line from the tags file. Find start/end of tag name, start/end of
 * file name and start of search pattern.
 *
 * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set.
 *
 * Return FAIL if there is a format error in this line, OK otherwise.
 */
    static int
parse_tag_line(lbuf,
#ifdef EMACS_TAGS
		    is_etag,
#endif
			      tagp)
    char_u		*lbuf;		/* line to be parsed */
#ifdef EMACS_TAGS
    int			is_etag;
#endif
    struct tag_pointers *tagp;
{
    char_u	*p;

#ifdef EMACS_TAGS
    char_u	*p_7f;

    if (is_etag)
    {
	/*
	 * There are two formats for an emacs tag line:
	 * 1:  struct EnvBase ^?EnvBase^A139,4627
	 * 2: #define	ARPB_WILD_WORLD ^?153,5194
	 */
	p_7f = vim_strchr(lbuf, 0x7f);
	if (p_7f == NULL)
	    return FAIL;

	/* Find ^A.  If not found the line number is after the 0x7f */
	p = vim_strchr(p_7f, Ctrl('A'));
	if (p == NULL)
	    p = p_7f + 1;
	else
	    ++p;

	if (!isdigit(*p))	    /* check for start of line number */
	    return FAIL;
	tagp->command = p;


	if (p[-1] == Ctrl('A'))	    /* first format: explicit tagname given */
	{
	    tagp->tagname = p_7f + 1;
	    tagp->tagname_end = p - 1;
	}
	else			    /* second format: isolate tagname */
	{
	    /* find end of tagname */
	    for (p = p_7f - 1; !vim_iswordc(*p); --p)
		if (p == lbuf)
		    return FAIL;
	    tagp->tagname_end = p + 1;
	    while (p >= lbuf && vim_iswordc(*p))
		--p;
	    tagp->tagname = p + 1;
	}
    }
    else	/* not an Emacs tag */
    {
#endif
	/* Isolate the tagname, from lbuf up to the first white */
	tagp->tagname = lbuf;
#ifdef TAG_ANY_WHITE
	p = skiptowhite(lbuf);
#else
	p = vim_strchr(lbuf, TAB);
	if (p == NULL)
	    return FAIL;
#endif
	tagp->tagname_end = p;

	/* Isolate file name, from first to second white space */
#ifdef TAG_ANY_WHITE
	p = skipwhite(p);
#else
	if (*p != NUL)
	    ++p;
#endif
	tagp->fname = p;
#ifdef TAG_ANY_WHITE
	p = skiptowhite(p);
#else
	p = vim_strchr(p, TAB);
	if (p == NULL)
	    return FAIL;
#endif
	tagp->fname_end = p;

	/* find start of search command, after second white space */
#ifdef TAG_ANY_WHITE
	p = skipwhite(p);
#else
	if (*p != NUL)
	    ++p;
#endif
	if (*p == NUL)
	    return FAIL;
	tagp->command = p;
#ifdef EMACS_TAGS
    }
#endif

    return OK;
}

/*
 * Check if tagname is a static tag
 *
 * Static tags produced by the older ctags program have the format:
 *	'file:tag  file  /pattern'.
 * This is only recognized when both occurences of 'file' are the same, to
 * avoid recognizing "string::string" or ":exit".
 *
 * Static tags produced by the new ctags program have the format:
 *	'tag  file  /pattern/;"<Tab>file:'	    "
 *
 * Return TRUE if it is a static tag and adjust *tagname to the real tag.
 * Return FALSE if it is not a static tag.
 */
    static int
test_for_static(tagp)
    struct tag_pointers	*tagp;
{
    char_u	*p;

#ifdef OLD_STATIC_TAGS
    int		len;

    /*
     * Check for old style static tag: "file:tag file .."
     */
    len = tagp->fname_end - tagp->fname;
    p = tagp->tagname + len;
    if (       p < tagp->tagname_end
	    && *p == ':'
	    && fnamencmp(tagp->tagname, tagp->fname, len) == 0)
    {
	tagp->tagname = p + 1;
	return TRUE;
    }
#endif

    /*
     * Check for new style static tag ":...<Tab>file:[<Tab>...]"
     */
    p = tagp->command;
    while ((p = vim_strchr(p, '\t')) != NULL)
    {
	++p;
	if (STRNCMP(p, "file:", 5) == 0)
	    return TRUE;
    }

    return FALSE;
}

/*
 * Parse a line from a matching tag.  Does not change the line itself.
 *
 * The line that we get looks like this:
 * 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>
 *
 * Return OK or FAIL.
 */
    static int
parse_match(lbuf, tagp)
    char_u		*lbuf;	    /* input: matching line */
    struct tag_pointers	*tagp;	    /* output: pointers into the line */
{
    int		retval;
    char_u	*p;
    char_u	*pc, *pt;

    tagp->tag_fname = lbuf + 1;
    lbuf += STRLEN(tagp->tag_fname) + 2;
#ifdef EMACS_TAGS
    if (*lbuf)
    {
	tagp->is_etag = TRUE;
	tagp->fname = lbuf;
	lbuf += STRLEN(lbuf);
	tagp->fname_end = lbuf++;
    }
    else
    {
	tagp->is_etag = FALSE;
	++lbuf;
    }
#endif

    /* Find search pattern and the file name for non-etags. */
    retval = parse_tag_line(lbuf,
#ifdef EMACS_TAGS
			tagp->is_etag,
#endif
			tagp);

    tagp->tagkind = NULL;
    tagp->command_end = NULL;

    if (retval == OK)
    {
	/* Try to find a kind field: "kind:<kind>" or just "<kind>"*/
	p = tagp->command;
	if (find_extra(&p) == OK)
	{
	    tagp->command_end = p;
	    p += 3;	/* skip ";\"\t" */
	    while (isalpha(*p))
	    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -