quickfix.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:19k
源码类别:
编辑器/阅读器
开发平台:
DOS
- /* 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;
- qf_lists[qf_curlist].qf_nonevalid = TRUE;
- }
- else
- qf_lists[qf_curlist].qf_nonevalid = FALSE;
- retval = qf_lists[qf_curlist].qf_count; /* return number of matches */
- goto qf_init_ok;
- }
- emsg(e_readerrf);
- error1:
- vim_free(qfp);
- error2:
- qf_free(qf_curlist);
- qf_listcount--;
- if (qf_curlist > 0)
- --qf_curlist;
- qf_init_ok:
- fclose(fd);
- for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
- {
- fmt_first = fmt_ptr->next;
- vim_free(fmt_ptr->fmtstr);
- vim_free(fmt_ptr);
- }
- qf_init_end:
- vim_free(namebuf);
- vim_free(errmsg);
- return retval;
- }
- /*
- * jump to a quickfix line
- * if dir == FORWARD go "errornr" valid entries forward
- * if dir == BACKWARD go "errornr" valid entries backward
- * else if "errornr" is zero, redisplay the same line
- * else go to entry "errornr"
- */
- void
- qf_jump(dir, errornr, forceit)
- int dir;
- int errornr;
- int forceit;
- {
- struct qf_line *qf_ptr;
- struct qf_line *old_qf_ptr;
- int qf_index;
- int old_qf_index;
- static char_u *e_no_more_items = (char_u *)"No more items";
- char_u *err = e_no_more_items;
- linenr_t i;
- BUF *old_curbuf;
- if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
- {
- emsg(e_quickfix);
- return;
- }
- qf_ptr = qf_lists[qf_curlist].qf_ptr;
- old_qf_ptr = qf_ptr;
- qf_index = qf_lists[qf_curlist].qf_index;
- old_qf_index = qf_index;
- if (dir == FORWARD) /* next valid entry */
- {
- while (errornr--)
- {
- old_qf_ptr = qf_ptr;
- old_qf_index = qf_index;
- do
- {
- if (qf_index == qf_lists[qf_curlist].qf_count
- || qf_ptr->qf_next == NULL)
- {
- qf_ptr = old_qf_ptr;
- qf_index = old_qf_index;
- if (err != NULL)
- {
- emsg(err);
- goto theend;
- }
- errornr = 0;
- break;
- }
- ++qf_index;
- qf_ptr = qf_ptr->qf_next;
- } while (!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid);
- err = NULL;
- }
- }
- else if (dir == BACKWARD) /* previous valid entry */
- {
- while (errornr--)
- {
- old_qf_ptr = qf_ptr;
- old_qf_index = qf_index;
- do
- {
- if (qf_index == 1 || qf_ptr->qf_prev == NULL)
- {
- qf_ptr = old_qf_ptr;
- qf_index = old_qf_index;
- if (err != NULL)
- {
- emsg(err);
- goto theend;
- }
- errornr = 0;
- break;
- }
- --qf_index;
- qf_ptr = qf_ptr->qf_prev;
- } while (!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid);
- err = NULL;
- }
- }
- else if (errornr != 0) /* go to specified number */
- {
- while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL)
- {
- --qf_index;
- qf_ptr = qf_ptr->qf_prev;
- }
- while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count
- && qf_ptr->qf_next != NULL)
- {
- ++qf_index;
- qf_ptr = qf_ptr->qf_next;
- }
- }
- /*
- * If there is a file name,
- * read the wanted file if needed, and check autowrite etc.
- */
- old_curbuf = curbuf;
- if (qf_ptr->qf_fnum == 0 || buflist_getfile(qf_ptr->qf_fnum,
- (linenr_t)1, GETF_SETMARK, forceit) == OK)
- {
- /* When not switched to another buffer, still need to set pc mark */
- if (curbuf == old_curbuf)
- setpcmark();
- /*
- * Go to line with error, unless qf_lnum is 0.
- */
- i = qf_ptr->qf_lnum;
- if (i > 0)
- {
- if (i > curbuf->b_ml.ml_line_count)
- i = curbuf->b_ml.ml_line_count;
- curwin->w_cursor.lnum = i;
- }
- if (qf_ptr->qf_col > 0)
- {
- curwin->w_cursor.col = qf_ptr->qf_col - 1;
- adjust_cursor();
- }
- else
- beginline(BL_WHITE | BL_FIX);
- update_topline_redraw();
- smsg((char_u *)"(%d of %d)%s%s: %s", qf_index,
- qf_lists[qf_curlist].qf_count,
- qf_ptr->qf_cleared ? (char_u *)" (line deleted)" : (char_u *)"",
- qf_types(qf_ptr->qf_type, qf_ptr->qf_nr), qf_ptr->qf_text);
- /*
- * if the message is short, redisplay after redrawing the screen
- */
- if (linetabsize(IObuff) < ((int)p_ch - 1) * Columns + sc_col)
- {
- keep_msg = IObuff;
- keep_msg_attr = 0;
- }
- }
- else if (qf_ptr->qf_fnum != 0)
- {
- /*
- * Couldn't open file, so put index back where it was. This could
- * happen if the file was readonly and we changed something - webb
- */
- qf_ptr = old_qf_ptr;
- qf_index = old_qf_index;
- }
- theend:
- qf_lists[qf_curlist].qf_ptr = qf_ptr;
- qf_lists[qf_curlist].qf_index = qf_index;
- }
- /*
- * list all errors
- */
- void
- qf_list(all)
- int all; /* If not :cl!, only show recognised errors */
- {
- BUF *buf;
- char_u *fname;
- struct qf_line *qfp;
- int i;
- if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
- {
- emsg(e_quickfix);
- return;
- }
- if (qf_lists[qf_curlist].qf_nonevalid)
- all = TRUE;
- qfp = qf_lists[qf_curlist].qf_start;
- for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ++i)
- {
- if (qfp->qf_valid || all)
- {
- msg_putchar('n');
- fname = NULL;
- if (qfp->qf_fnum != 0 &&
- (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
- fname = buf->b_fname;
- if (fname == NULL)
- sprintf((char *)IObuff, "%2d", i);
- else
- sprintf((char *)IObuff, "%2d %s", i, fname);
- msg_outtrans_attr(IObuff, hl_attr(HLF_D));
- if (qfp->qf_lnum == 0)
- IObuff[0] = NUL;
- else if (qfp->qf_col == 0)
- sprintf((char *)IObuff, ":%ld", qfp->qf_lnum);
- else
- sprintf((char *)IObuff, ":%ld, col %d",
- qfp->qf_lnum, qfp->qf_col);
- sprintf((char *)IObuff + STRLEN(IObuff), "%s: ",
- qf_types(qfp->qf_type, qfp->qf_nr));
- msg_puts_attr(IObuff, hl_attr(HLF_N));
- msg_prt_line(qfp->qf_text);
- out_flush(); /* show one line at a time */
- }
- qfp = qfp->qf_next;
- ui_breakcheck();
- }
- }
- /*
- * ":colder [count]": Up in the quickfix stack.
- */
- void
- qf_older(count)
- int count;
- {
- while (count--)
- {
- if (qf_curlist == 0)
- {
- EMSG("At bottom of quickfix stack");
- return;
- }
- --qf_curlist;
- }
- qf_msg();
- }
- /*
- * ":cnewer [count]": Down in the quickfix stack.
- */
- void
- qf_newer(count)
- int count;
- {
- while (count--)
- {
- if (qf_curlist >= qf_listcount - 1)
- {
- EMSG("At top of quickfix stack");
- return;
- }
- ++qf_curlist;
- }
- qf_msg();
- }
- static void
- qf_msg()
- {
- smsg((char_u *)"error list %d of %d; %d errors",
- qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count);
- }
- /*
- * free the error list
- */
- static void
- qf_free(idx)
- int idx;
- {
- struct qf_line *qfp;
- while (qf_lists[idx].qf_count)
- {
- qfp = qf_lists[idx].qf_start->qf_next;
- vim_free(qf_lists[idx].qf_start->qf_text);
- vim_free(qf_lists[idx].qf_start);
- qf_lists[idx].qf_start = qfp;
- --qf_lists[idx].qf_count;
- }
- }
- /*
- * qf_mark_adjust: adjust marks
- */
- void
- qf_mark_adjust(line1, line2, amount, amount_after)
- linenr_t line1;
- linenr_t line2;
- long amount;
- long amount_after;
- {
- int i;
- struct qf_line *qfp;
- int idx;
- for (idx = 0; idx < qf_listcount; ++idx)
- if (qf_lists[idx].qf_count)
- for (i = 0, qfp = qf_lists[idx].qf_start;
- i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
- if (qfp->qf_fnum == curbuf->b_fnum)
- {
- if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
- {
- if (amount == MAXLNUM)
- qfp->qf_cleared = TRUE;
- else
- qfp->qf_lnum += amount;
- }
- if (amount_after && qfp->qf_lnum > line2)
- qfp->qf_lnum += amount_after;
- }
- }
- /*
- * Make a nice message out of the error character and the error number:
- * char number message
- * e or E 0 " error"
- * w or W 0 " warning"
- * 0 0 ""
- * other 0 " c"
- * e or E n " error n"
- * w or W n " warning n"
- * 0 n " error n"
- * other n " c n"
- */
- static char_u *
- qf_types(c, nr)
- int c, nr;
- {
- static char_u buf[20];
- static char_u cc[3];
- char_u *p;
- if (c == 'W' || c == 'w')
- p = (char_u *)" warning";
- else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
- p = (char_u *)" error";
- else if (c == 0)
- p = (char_u *)"";
- else
- {
- cc[0] = ' ';
- cc[1] = c;
- cc[2] = NUL;
- p = cc;
- }
- if (nr <= 0)
- return p;
- sprintf((char *)buf, "%s %3d", p, nr);
- return buf;
- }
- #endif /* QUICKFIX */