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

📄 tag.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
			++p;
			if (*p == '^')
			    ++p;
		    }
		    /* Remove leading whitespace from pattern */
		    while (p != command_end && vim_isspace(*p))
			++p;

		    while (p != command_end)
		    {
			if (msg_col + (*p == TAB ? 1 : charsize(*p)) > Columns)
			    msg_putchar('\n');
			msg_advance(15);

			/* skip backslash used for escaping command char */
			if (*p == '\\' && *(p + 1) == *tagp.command)
			    ++p;

			if (*p == TAB)
			    msg_putchar(' ');
			else
			    msg_puts(transchar(*p));
			++p;

			/* don't display the "$/;\"" and "$?;\"" */
			if (p == command_end - 2 && *p == '$'
						 && *(p + 1) == *tagp.command)
			    break;
			if (p == command_end - 1 && *p == *tagp.command)
			    break;
		    }
		    if (msg_col)
			msg_putchar('\n');
		    ui_breakcheck();
		    if (got_int)
		    {
			got_int = FALSE;	/* only stop the listing */
			break;
		    }
		}
		ask_for_selection = TRUE;
	    }

	    if (ask_for_selection == TRUE)
	    {
		/*
		 * Ask to select a tag from the list.
		 */
		MSG_PUTS("Enter nr of choice (<CR> to abort): ");
		i = get_number(TRUE);
		if (KeyTyped)		/* don't call wait_return() now */
		{
		    msg_putchar('\n');
		    dont_wait_return = TRUE;
		    need_wait_return = FALSE;
		    msg_didany = FALSE;
		    cmdline_row = msg_row;
		    msg_scrolled = 0;
		    redraw_all_later(NOT_VALID);
		}
		if (i <= 0 || i > num_matches || got_int)
		{
		    /* no valid choice: don't change anything */
		    tagstack[tagstackidx].fmark = saved_fmark;
		    ++tagstackidx;
#ifdef USE_CSCOPE
		    cs_free_tags();
		    jumped_to_tag = TRUE;
#endif
		    break;
		}
		cur_match = i - 1;
	    }

	    if (cur_match >= num_matches)
		cur_match = num_matches - 1;
	    curwin->w_tagstack[tagstackidx].cur_match = cur_match;
	    ++tagstackidx;

	    /*
	     * Only when going to try the next match, report that the previous
	     * file didn't exist.  Otherwise an EMSG() is given below.
	     */
	    if (nofile_fname != NULL && error_cur_match != cur_match)
		smsg((char_u *)"File \"%s\" does not exist", nofile_fname);


	    ic = (matches[cur_match][0] & MT_IC_OFF);
	    if (type != DT_SELECT && type != DT_JUMP
#ifdef USE_CSCOPE
		&& type != DT_CSCOPE
#endif
		&& (num_matches > 1 || ic))
	    {
		/* Give an indication of the number of matching tags */
		sprintf((char *)msg_buf, "tag %d of %d%s",
				cur_match + 1,
				num_matches,
				max_num_matches != MAXCOL ? " or more" : "");
		if (ic)
		    STRCAT(msg_buf, "  Using tag with different case!");
		if ((num_matches > prev_num_matches || new_tag)
							   && num_matches > 1)
		{
		    if (ic)
			msg_attr(msg_buf, hl_attr(HLF_W));
		    else
			msg(msg_buf);
		    msg_scroll = TRUE;	/* don't overwrite this message */
		}
		else
		    give_warning(msg_buf, ic);
		if (ic && !msg_scrolled)
		{
		    out_flush();
		    ui_delay(1000L, TRUE);
		}
	    }

	    /*
	     * Jump to the desired match.
	     */
	    if (jumpto_tag(matches[cur_match], forceit) == NOTAGFILE)
	    {
		/* File not found: try again with another matching tag */
		if ((type == DT_PREV && cur_match > 0)
			|| ((type == DT_TAG || type == DT_NEXT
							  || type == DT_FIRST)
			    && (max_num_matches != MAXCOL
					     || cur_match < num_matches - 1)))
		{
		    error_cur_match = cur_match;
		    --tagstackidx;
		    if (type == DT_PREV)
			--cur_match;
		    else
		    {
			type = DT_NEXT;
			++cur_match;
		    }
		    continue;
		}
		EMSG2("File \"%s\" does not exist", nofile_fname);
	    }
#ifdef USE_CSCOPE
	    else
		jumped_to_tag = TRUE;
#endif
	}
	break;
    }

end_do_tag:
    curwin->w_tagstackidx = tagstackidx;
    curwin->w_tagstacklen = tagstacklen;
    postponed_split = 0;	/* don't split next time */

#ifdef USE_CSCOPE
    return jumped_to_tag;
#else
    return FALSE;
#endif
}

    static void
taglen_advance(l)
    int		l;
{
    if (l == MAXCOL)
    {
	msg_putchar('\n');
	msg_advance(24);
    }
    else
	msg_advance(13 + l);
}

/*
 * Print the tag stack
 */
    void
do_tags()
{
    int		    i;
    char_u	    *name;
    struct taggy    *tagstack = curwin->w_tagstack;
    int		    tagstackidx = curwin->w_tagstackidx;
    int		    tagstacklen = curwin->w_tagstacklen;

    /* Highlight title */
    MSG_PUTS_TITLE("\n  # TO tag         FROM line  in file");
    for (i = 0; i < tagstacklen; ++i)
    {
	if (tagstack[i].tagname != NULL)
	{
	    name = fm_getname(&(tagstack[i].fmark));
	    if (name == NULL)	    /* file name not available */
		continue;

	    msg_putchar('\n');
	    sprintf((char *)IObuff, "%c%2d %2d %-15s %5ld  %s",
		i == tagstackidx ? '>' : ' ',
		i + 1,
		tagstack[i].cur_match + 1,
		tagstack[i].tagname,
		tagstack[i].fmark.mark.lnum,
		name);
	    msg_outtrans(IObuff);
	    vim_free(name);
	}
	out_flush();		    /* show one line at a time */
    }
    if (tagstackidx == tagstacklen)	/* idx at top of stack */
	MSG_PUTS("\n>");
}

/*
 * find_tags() - search for tags in tags files
 *
 * Return FAIL if search completely failed (*num_matches will be 0, *matchesp
 * will be NULL), OK otherwise.
 *
 * There is a priority in which type of tag is recognized.
 *
 *  6.	A static or global tag with a full matching tag for the current file.
 *  5.	A global tag with a full matching tag for another file.
 *  4.	A static tag with a full matching tag for another file.
 *  3.	A static or global tag with an ignore-case matching tag for the
 *	current file.
 *  2.	A global tag with an ignore-case matching tag for another file.
 *  1.	A static tag with an ignore-case matching tag for another file.
 *
 * Tags in an emacs-style tags file are always global.
 *
 * flags:
 * TAG_HELP	only search for help tags
 * TAG_NAMES	only return name of tag
 * TAG_REGEXP	use "pat" as a regexp
 * TAG_NOIC	don't always ignore case
 */

    int
find_tags(pat, num_matches, matchesp, flags, mincount)
    char_u	*pat;			/* pattern to search for */
    int		*num_matches;		/* return: number of matches found */
    char_u	***matchesp;		/* return: array of matches found */
    int		flags;
    int		mincount;		/*  MAXCOL: find all matches
					     other: minimal number of matches */
{
    FILE       *fp;
    char_u     *lbuf;			/* line buffer */
    char_u     *tag_fname;		/* name of tag file */
    int		first_file;		/* trying first tag file */
    struct tag_pointers tagp;
    int		did_open = FALSE;	/* did open a tag file */
    int		stop_searching = FALSE;	/* stop when match found or error */
    int		retval = FAIL;		/* return value */
    int		is_static;		/* current tag line is static */
    int		is_current;		/* file name matches */
    int		eof = FALSE;		/* found end-of-file */
    char_u	*p;
    char_u	*s;
    int		i;
    vim_regexp	*prog = NULL;		/* regexp program or NULL */
#ifdef BINARY_TAGS
    struct tag_search_info	/* Binary search file offsets */
    {
	long	low_offset;	/* offset for first char of first line that
				   could match */
	long	high_offset;	/* offset of char after last line that could
				   match */
	long	curr_offset;	/* Current file offset in search range */
	long	match_offset;	/* Where the binary search found a tag */
	int	low_char;	/* first char at low_offset */
	int	high_char;	/* first char at high_offset */
    } search_info;
    off_t	filesize;
    int		tagcmp;
    long	offset;
#endif
    enum
    {
	TS_START,		/* at start of file */
	TS_LINEAR,		/* linear searching forward, till EOF */
#ifdef BINARY_TAGS
	TS_BINARY,		/* binary searching */
	TS_SKIP_BACK,		/* skipping backwards */
	TS_STEP_FORWARD		/* stepping forwards */
#endif
    }	state;			/* Current search state */

    int		cmplen;
    int		match;		/* matches */
    int		match_no_ic = 0;/* matches with reg_ic == FALSE */
    int		match_re;	/* match with regexp */
    int		matchoff = 0;

#ifdef EMACS_TAGS
    /*
     * Stack for included emacs-tags file.
     * It has a fixed size, to truncate cyclic includes. jw
     */
# define INCSTACK_SIZE 42
    struct
    {
	FILE	*fp;
	char_u	*etag_fname;
    } incstack[INCSTACK_SIZE];

    int		incstack_idx = 0;	/* index in incstack */
    char_u     *ebuf;			/* aditional buffer for etag fname */
    int		is_etag;		/* current file is emaces style */
#endif

    struct growarray ga_match[MT_COUNT];
    int		match_count = 0;		/* number of matches found */
    char_u	**matches;
    int		mtt;
    int		len;
    int		help_save;

    int		patlen;				/* length of pat[] */
    char_u	*pathead;			/* start of pattern head */
    int		patheadlen;			/* length of pathead[] */
#ifdef BINARY_TAGS
    int		findall = (mincount == MAXCOL); /* find all matching tags */
    int		sort_error = FALSE;		/* tags file not sorted */
    int		linear;				/* do a linear search */
#endif
    int		has_re = (flags & TAG_REGEXP);	/* regexp used */
    int		help_only = (flags & TAG_HELP);
    int		name_only = (flags & TAG_NAMES);
    int		noic = (flags & TAG_NOIC);
    int		get_it_again = FALSE;
#ifdef USE_CSCOPE
    int		use_cscope = (flags & TAG_CSCOPE);
#endif
    int		verbose = (flags & TAG_VERBOSE);

    help_save = curbuf->b_help;

/*
 * Allocate memory for the buffers that are used
 */
    if (has_re)
	prog = vim_regcomp(pat, p_magic);
    lbuf = alloc(LSIZE);
    tag_fname = alloc(LSIZE + 1);
#ifdef EMACS_TAGS
    ebuf = alloc(LSIZE);
#endif
    for (mtt = 0; mtt < MT_COUNT; ++mtt)
    {
	ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100);
    }

    /* check for out of memory situation */
    if (lbuf == NULL || tag_fname == NULL
#ifdef EMACS_TAGS
					 || ebuf == NULL
#endif
							)
	goto findtag_end;

/*
 * Initialize a few variables
 */
    if (help_only)				/* want tags from help file */
	curbuf->b_help = TRUE;			/* will be restored later */

    patlen = STRLEN(pat);
    if (p_tl != 0 && patlen > p_tl)		/* adjust for 'taglength' */
	patlen = p_tl;

    pathead = pat;
    patheadlen = patlen;
    if (has_re)
    {
	/* When the pattern starts with '^' or "\\<", binary searching can be
	 * used (much faster). */
	if (pat[0] == '^')
	    pathead = pat + 1;
	else if (pat[0] == '\\' && pat[1] == '<')
	    pathead = pat + 2;
	if (pathead == pat)
	    patheadlen = 0;
	else
	    for (patheadlen = 0; pathead[patheadlen] != NUL; ++patheadlen)
		if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"),
						 pathead[patheadlen]) != NULL)
		    break;
	if (p_tl != 0 && patheadlen > p_tl)	/* adjust for 'taglength' */
	    patheadlen = p_tl;
    }

/*
 * When finding a specified number of matches, first try with matching case,
 * so binary search can be used, and try ignore-case matches in a second loop.
 * When finding all matches, 'tagbsearch' is off, or there is no fixed string
 * to look for, ignore case right away to avoid going though the tags files
 * twice.
 * Only ignore case when TAG_NOIC not used or 'ignorecase' set.
 */
#ifdef BINARY_TAGS
    reg_ic = ((p_ic || !noic) && (findall || patheadlen == 0 || !p_tbs));
    for (;;)
    {
      linear = (reg_ic || patheadlen == 0 || !p_tbs);
#else
      reg_ic = (p_ic || !noic);
#endif

      /*
       * Try tag file names from tags option one by one.
       */
    for (first_file = TRUE;
#ifdef USE_CSCOPE
	    use_cscope ||
#endif
		get_tagfname(first_file, tag_fname) == OK; first_file = FALSE)
    {
	/*
	 * A file that doesn't exist is silently ignored.  Only when not a
	 * single file is found, an error message is given (further on).
	 */
#ifdef USE_CSCOPE
	if (use_cscope)
	    fp = NULL;	    /* avoid GCC warning */
	else
#endif
	    if ((fp = fopen((char *)tag_fname, "r")) == NULL)
		continue;
	did_open = TRUE;    /* remember that we found at least one file */

	state = TS_START;   /* we're at the start of the file */
#ifdef EMACS_TAGS
	is_etag = 0;	    /* default is: not emacs style */
#endif
	/*
	 * Read and parse the lines in the file one by one
	 */
	while (!got_int)
	{
	    line_breakcheck();	    /* check for CTRL-C typed */
	    if (get_it_again)
		goto line_read_in;
#ifdef BINARY_TAGS
	    /*
	     * For binary search: compute the next offset to use.
	     */
	    if (state == TS_BINARY)
	    {
		offset = search_info.low_offset + ((search_info.high_offset
					       - search_info.low_offset) / 2);
		if (offset == search_info.curr_offset)
		    break;	/* End the binary search without a match. */
		else
		    search_info.curr_offset = offset;
	    }

	    /*
	     * Skipping back (after a match during binary search).
	     */
	    else if (state == TS_SKIP_BACK)
	    {
		search_info.curr_offset -= LSIZE * 2;
		if (search_info.curr_offset < 0)
		{
		    search_info.curr_offset = 0;
		    rewind(fp);
		    state = TS_STEP_FORWARD;
		}
	    }

	    /*
	     * When jumping around in the file, first read a line to find the
	     * start of the next line.
	     */
	    if (state == TS_BINARY || state == TS_SKIP_BACK)
	    {
		/* Adjust the search file offset to the correct position */
		fseek(fp, search_info.curr_offset, SEEK_SET);
		eof = vim_fgets(lbuf, LSIZE, fp);
		if (!eof && search_info.curr_offset)
		{
		    search_info.curr_offset = ftell(fp);
		    if (search_info.curr_offset == search_info.high_offset)
		    {
			/* oops, gone a bit too far; try from low offset */
			fseek(fp, search_info.low_offset, SEEK_SET);
			search_info.curr_offset = search_info.low_offset;
		    }
		    eof = vim_fgets(lbuf, LSIZE, fp);
		}
		/* skip empty and blank lines */
		while (!eof && vim_isblankline(lbuf))
		{
		    search_info.curr_offset = ftell(fp);
		    eof = vim_fgets(lbuf, LSIZE, fp);
		}
		if (eof)
		{
		    /* Hit end of file.  Skip backwards. */
		    state = TS_SKIP_BACK;
		    search_info.match_offset = ftell(fp);
		    continue;
		}
	    }

	    /*

⌨️ 快捷键说明

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