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

📄 quickfix.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * quickfix.c: functions for quickfix mode, using a file with error messages
 */

#include "vim.h"

#ifdef QUICKFIX

static void qf_msg __ARGS((void));
static void qf_free __ARGS((int idx));
static char_u *qf_types __ARGS((int, int));

/*
 * for each error the next struct is allocated and linked in a list
 */
struct qf_line
{
    struct qf_line  *qf_next;	/* pointer to next error in the list */
    struct qf_line  *qf_prev;	/* pointer to previous error in the list */
    linenr_t	     qf_lnum;	/* line number where the error occurred */
    int		     qf_fnum;	/* file number for the line */
    int		     qf_col;	/* column where the error occurred */
    int		     qf_nr;	/* error number */
    char_u	    *qf_text;	/* description of the error */
    char_u	     qf_cleared;/* set to TRUE if line has been deleted */
    char_u	     qf_type;	/* type of the error (mostly 'E') */
    char_u	     qf_valid;	/* valid error message detected */
};

/*
 * There is a stack of error lists.
 */
#define LISTCOUNT   10

struct qf_list
{
    struct qf_line *qf_start;	/* pointer to the first error */
    struct qf_line *qf_ptr;	/* pointer to the current error */
    int  qf_count;		/* number of errors (0 means no error list) */
    int  qf_index;		/* current index in the error list */
    int  qf_nonevalid;		/* TRUE if not a single valid entry found */
} qf_lists[LISTCOUNT];

static int	qf_curlist = 0;	/* current error list */
static int	qf_listcount = 0;   /* current number of lists */

#define MAX_ADDR    7		/* maximum number of % recognized, also adjust
				    sscanf() below */

/*
 * Structure used to hold the info of one part of 'errorformat'
 */
struct eformat
{
    char_u	    *fmtstr;	    /* pre-formatted part of 'errorformat' */
#ifdef UTS2
    char_u	    *(adr[MAX_ADDR]);	/* addresses used */
#else
    void	    *(adr[MAX_ADDR]);
#endif
    int		    adr_cnt;	    /* number of addresses used */
    struct eformat  *next;	    /* pointer to next (NULL if last) */
};

/*
 * Read the errorfile into memory, line by line, building the error list.
 * Return -1 for error, number of errors for success.
 */
    int
qf_init(efile, errorformat)
    char_u	    *efile;
    char_u	    *errorformat;
{
    char_u	    *namebuf;
    char_u	    *errmsg;
    int		    col;
    int		    type;
    int		    valid;
    long	    lnum;
    int		    enr;
    FILE	    *fd;
    struct qf_line  *qfp = NULL;
    struct qf_line  *qfprev = NULL;	/* init to make SASC shut up */
    char_u	    *efmp;
    struct eformat  *fmt_first = NULL;
    struct eformat  *fmt_last = NULL;
    struct eformat  *fmt_ptr;
    char_u	    *efm;
    int		    maxlen;
    int		    len;
    int		    i, j;
    int		    retval = -1;	/* default: return error flag */

    if (efile == NULL)
	return FAIL;

    namebuf = alloc(CMDBUFFSIZE + 1);
    errmsg = alloc(CMDBUFFSIZE + 1);
    if (namebuf == NULL || errmsg == NULL)
	goto qf_init_end;

    if ((fd = fopen((char *)efile, "r")) == NULL)
    {
	emsg2(e_openerrf, efile);
	goto qf_init_end;
    }

    /*
     * When the stack is full, remove to oldest entry
     * Otherwise, add a new entry.
     */
    if (qf_listcount == LISTCOUNT)
    {
	qf_free(0);
	for (i = 1; i < LISTCOUNT; ++i)
	    qf_lists[i - 1] = qf_lists[i];
	qf_curlist = LISTCOUNT - 1;
    }
    else
	qf_curlist = qf_listcount++;
    qf_lists[qf_curlist].qf_index = 0;
    qf_lists[qf_curlist].qf_count = 0;

/*
 * Each part of the format string is copied and modified from errorformat to
 * fmtstr.  Only a few % characters are allowed.
 */
    efm = errorformat;
    while (efm[0])
    {
	/*
	 * Allocate a new eformat structure and put it at the end of the list
	 */
	fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat));
	if (fmt_ptr == NULL)
	    goto error2;
	if (fmt_first == NULL)	    /* first one */
	    fmt_first = fmt_ptr;
	else
	    fmt_last->next = fmt_ptr;
	fmt_last = fmt_ptr;
	fmt_ptr->next = NULL;
	fmt_ptr->adr_cnt = 0;

	/*
	 * Isolate one part in the 'errorformat' option
	 */
	for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
	    if (efm[len] == '\\' && efm[len + 1] != NUL)
		++len;

	/*
	 * Get some space to modify the format string into.
	 * Must be able to do the largest expansion (x3) MAX_ADDR times.
	 */
	maxlen = len + MAX_ADDR * 3 + 4;
	if ((fmt_ptr->fmtstr = alloc(maxlen)) == NULL)
	    goto error2;

	for (i = 0; i < MAX_ADDR; ++i)
	    fmt_ptr->adr[i] = NULL;

	for (efmp = efm, i = 0; efmp < efm + len; ++efmp, ++i)
	{
	    if (efmp[0] != '%')		    /* copy normal character */
	    {
		if (efmp[0] == '\\' && efmp + 1 < efm + len)
		    ++efmp;
		fmt_ptr->fmtstr[i] = efmp[0];
	    }
	    else
	    {
		fmt_ptr->fmtstr[i++] = '%';
		switch (efmp[1])
		{
		case 'f':	/* file name */
			fmt_ptr->adr[fmt_ptr->adr_cnt++] = namebuf;
			/* FALLTHROUGH */

		case 'm':	/* message */
			if (efmp[1] == 'm')
			    fmt_ptr->adr[fmt_ptr->adr_cnt++] = errmsg;
			fmt_ptr->fmtstr[i++] = '[';
			fmt_ptr->fmtstr[i++] = '^';
#ifdef __EMX__
			/* don't allow spaces in file name. This fixes
			 * the broken sscanf() where an empty message
			 * is accepted as a valid conversion.
			 */
			if (efmp[1] == 'f')
			    fmt_ptr->fmtstr[i++] = ' ';
#endif
			if (efmp[2] == '\\')	    /* could be "%m\," */
			    j = 3;
			else
			    j = 2;
			if (efmp + j < efm + len)
			    fmt_ptr->fmtstr[i++] = efmp[j];
			else
			{
			    /*
			     * The %f or %m is the last one in the format,
			     * stop at the CR of NL at the end of the line.
			     */
#ifdef USE_CRNL
			    fmt_ptr->fmtstr[i++] = '\r';
#endif
			    fmt_ptr->fmtstr[i++] = '\n';
			}
			fmt_ptr->fmtstr[i] = ']';
			break;
		case 'c':	/* column */
			fmt_ptr->adr[fmt_ptr->adr_cnt++] = &col;
			fmt_ptr->fmtstr[i] = 'd';
			break;
		case 'l':	/* line */
			fmt_ptr->adr[fmt_ptr->adr_cnt++] = &lnum;
			fmt_ptr->fmtstr[i++] = 'l';
			fmt_ptr->fmtstr[i] = 'd';
			break;
		case 'n':	/* error number */
			fmt_ptr->adr[fmt_ptr->adr_cnt++] = &enr;
			fmt_ptr->fmtstr[i] = 'd';
			break;
		case 't':	/* error type */
			fmt_ptr->adr[fmt_ptr->adr_cnt++] = &type;
			fmt_ptr->fmtstr[i] = 'c';
			break;
		case '%':	/* %% */
		case '*':	/* %*: no assignment */
			fmt_ptr->fmtstr[i] = efmp[1];
			break;
		default:
			EMSG("invalid % in format string");
			goto error2;
		}
		if (fmt_ptr->adr_cnt == MAX_ADDR)
		{
		    EMSG("too many % in format string");
		    goto error2;
		}
		++efmp;
	    }
	    if (i >= maxlen - 6)
	    {
		EMSG("invalid format string");
		goto error2;
	    }
	}
	fmt_ptr->fmtstr[i] = NUL;

	/*
	 * Advance to next part
	 */
	efm = skip_to_option_part(efm + len);	/* skip comma and spaces */
    }
    if (fmt_first == NULL)	/* nothing found */
    {
	EMSG("'errorformat' contains no pattern");
	goto error2;
    }

    /*
     * got_int is reset here, because it was probably set when killing the
     * ":make" command, but we still want to read the errorfile then.
     */
    got_int = FALSE;

    /*
     * Read the lines in the error file one by one.
     * Try to recognize one of the error formats in each line.
     */
    while (fgets((char *)IObuff, CMDBUFFSIZE, fd) != NULL && !got_int)
    {
	if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line)))
								      == NULL)
	    goto error2;

	IObuff[CMDBUFFSIZE] = NUL;  /* for very long lines */

	/*
	 * Try to match each part of 'errorformat' until we find a complete
	 * match or none matches.
	 */
	valid = TRUE;
	for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
	{
	    namebuf[0] = NUL;
	    errmsg[0] = NUL;
	    lnum = 0;
	    col = 0;
	    enr = -1;
	    type = 0;

	    /*
	     * If first char of the format and message don't match, there is
	     * no need to try sscanf() on it... Somehow I believe there are
	     * very slow implementations of sscanf().
	     * -- Paul Slootman
	     */
	    if (fmt_ptr->fmtstr[0] != '%' && fmt_ptr->fmtstr[0] != IObuff[0])
		continue;

	    if (sscanf((char *)IObuff, (char *)fmt_ptr->fmtstr,
			fmt_ptr->adr[0], fmt_ptr->adr[1], fmt_ptr->adr[2],
			fmt_ptr->adr[3], fmt_ptr->adr[4], fmt_ptr->adr[5],
			fmt_ptr->adr[6]) == fmt_ptr->adr_cnt)
		break;
	}
	if (fmt_ptr == NULL)
	{
	    namebuf[0] = NUL;		/* no match found, remove file name */
	    lnum = 0;			/* don't jump to this line */
	    valid = FALSE;
	    STRCPY(errmsg, IObuff);	/* copy whole line to error message */
	    if ((efmp = vim_strrchr(errmsg, '\n')) != NULL)
		*efmp = NUL;
#ifdef USE_CRNL
	    if ((efmp = vim_strrchr(errmsg, '\r')) != NULL)
		*efmp = NUL;
#endif
	}

	if (namebuf[0] == NUL)		/* no file name */
	    qfp->qf_fnum = 0;
	else
#ifdef RISCOS
	    /* Name is reported as `main.c', but file is `c.main' */
	    qfp->qf_fnum = ro_buflist_add(namebuf);
#else
	    qfp->qf_fnum = buflist_add(namebuf);
#endif
	if ((qfp->qf_text = vim_strsave(errmsg)) == NULL)
	    goto error1;
	if (!vim_isprintc(type))	/* only printable chars allowed */
	    type = 0;
	qfp->qf_lnum = lnum;
	qfp->qf_col = col;
	qfp->qf_nr = enr;
	qfp->qf_type = type;
	qfp->qf_valid = valid;

	if (qf_lists[qf_curlist].qf_count == 0)	/* first element in the list */
	{
	    qf_lists[qf_curlist].qf_start = qfp;
	    qfp->qf_prev = qfp;	/* first element points to itself */
	}
	else
	{
	    qfp->qf_prev = qfprev;
	    qfprev->qf_next = qfp;
	}
	qfp->qf_next = qfp;	/* last element points to itself */
	qfp->qf_cleared = FALSE;
	qfprev = qfp;
	++qf_lists[qf_curlist].qf_count;
	if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid)	/* first valid entry */
	{
	    qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count;
	    qf_lists[qf_curlist].qf_ptr = qfp;
	}
	line_breakcheck();
    }
    if (!ferror(fd))
    {
	if (qf_lists[qf_curlist].qf_index == 0)	/* no valid entry found */
	{
	    qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
	    qf_lists[qf_curlist].qf_index = 1;

⌨️ 快捷键说明

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