quickfix.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:19k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8. /*
  9.  * quickfix.c: functions for quickfix mode, using a file with error messages
  10.  */
  11. #include "vim.h"
  12. #ifdef QUICKFIX
  13. static void qf_msg __ARGS((void));
  14. static void qf_free __ARGS((int idx));
  15. static char_u *qf_types __ARGS((int, int));
  16. /*
  17.  * for each error the next struct is allocated and linked in a list
  18.  */
  19. struct qf_line
  20. {
  21.     struct qf_line  *qf_next; /* pointer to next error in the list */
  22.     struct qf_line  *qf_prev; /* pointer to previous error in the list */
  23.     linenr_t      qf_lnum; /* line number where the error occurred */
  24.     int      qf_fnum; /* file number for the line */
  25.     int      qf_col; /* column where the error occurred */
  26.     int      qf_nr; /* error number */
  27.     char_u     *qf_text; /* description of the error */
  28.     char_u      qf_cleared;/* set to TRUE if line has been deleted */
  29.     char_u      qf_type; /* type of the error (mostly 'E') */
  30.     char_u      qf_valid; /* valid error message detected */
  31. };
  32. /*
  33.  * There is a stack of error lists.
  34.  */
  35. #define LISTCOUNT   10
  36. struct qf_list
  37. {
  38.     struct qf_line *qf_start; /* pointer to the first error */
  39.     struct qf_line *qf_ptr; /* pointer to the current error */
  40.     int  qf_count; /* number of errors (0 means no error list) */
  41.     int  qf_index; /* current index in the error list */
  42.     int  qf_nonevalid; /* TRUE if not a single valid entry found */
  43. } qf_lists[LISTCOUNT];
  44. static int qf_curlist = 0; /* current error list */
  45. static int qf_listcount = 0;   /* current number of lists */
  46. #define MAX_ADDR    7 /* maximum number of % recognized, also adjust
  47.     sscanf() below */
  48. /*
  49.  * Structure used to hold the info of one part of 'errorformat'
  50.  */
  51. struct eformat
  52. {
  53.     char_u     *fmtstr;     /* pre-formatted part of 'errorformat' */
  54. #ifdef UTS2
  55.     char_u     *(adr[MAX_ADDR]); /* addresses used */
  56. #else
  57.     void     *(adr[MAX_ADDR]);
  58. #endif
  59.     int     adr_cnt;     /* number of addresses used */
  60.     struct eformat  *next;     /* pointer to next (NULL if last) */
  61. };
  62. /*
  63.  * Read the errorfile into memory, line by line, building the error list.
  64.  * Return -1 for error, number of errors for success.
  65.  */
  66.     int
  67. qf_init(efile, errorformat)
  68.     char_u     *efile;
  69.     char_u     *errorformat;
  70. {
  71.     char_u     *namebuf;
  72.     char_u     *errmsg;
  73.     int     col;
  74.     int     type;
  75.     int     valid;
  76.     long     lnum;
  77.     int     enr;
  78.     FILE     *fd;
  79.     struct qf_line  *qfp = NULL;
  80.     struct qf_line  *qfprev = NULL; /* init to make SASC shut up */
  81.     char_u     *efmp;
  82.     struct eformat  *fmt_first = NULL;
  83.     struct eformat  *fmt_last = NULL;
  84.     struct eformat  *fmt_ptr;
  85.     char_u     *efm;
  86.     int     maxlen;
  87.     int     len;
  88.     int     i, j;
  89.     int     retval = -1; /* default: return error flag */
  90.     if (efile == NULL)
  91. return FAIL;
  92.     namebuf = alloc(CMDBUFFSIZE + 1);
  93.     errmsg = alloc(CMDBUFFSIZE + 1);
  94.     if (namebuf == NULL || errmsg == NULL)
  95. goto qf_init_end;
  96.     if ((fd = fopen((char *)efile, "r")) == NULL)
  97.     {
  98. emsg2(e_openerrf, efile);
  99. goto qf_init_end;
  100.     }
  101.     /*
  102.      * When the stack is full, remove to oldest entry
  103.      * Otherwise, add a new entry.
  104.      */
  105.     if (qf_listcount == LISTCOUNT)
  106.     {
  107. qf_free(0);
  108. for (i = 1; i < LISTCOUNT; ++i)
  109.     qf_lists[i - 1] = qf_lists[i];
  110. qf_curlist = LISTCOUNT - 1;
  111.     }
  112.     else
  113. qf_curlist = qf_listcount++;
  114.     qf_lists[qf_curlist].qf_index = 0;
  115.     qf_lists[qf_curlist].qf_count = 0;
  116. /*
  117.  * Each part of the format string is copied and modified from errorformat to
  118.  * fmtstr.  Only a few % characters are allowed.
  119.  */
  120.     efm = errorformat;
  121.     while (efm[0])
  122.     {
  123. /*
  124.  * Allocate a new eformat structure and put it at the end of the list
  125.  */
  126. fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat));
  127. if (fmt_ptr == NULL)
  128.     goto error2;
  129. if (fmt_first == NULL)     /* first one */
  130.     fmt_first = fmt_ptr;
  131. else
  132.     fmt_last->next = fmt_ptr;
  133. fmt_last = fmt_ptr;
  134. fmt_ptr->next = NULL;
  135. fmt_ptr->adr_cnt = 0;
  136. /*
  137.  * Isolate one part in the 'errorformat' option
  138.  */
  139. for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
  140.     if (efm[len] == '\' && efm[len + 1] != NUL)
  141. ++len;
  142. /*
  143.  * Get some space to modify the format string into.
  144.  * Must be able to do the largest expansion (x3) MAX_ADDR times.
  145.  */
  146. maxlen = len + MAX_ADDR * 3 + 4;
  147. if ((fmt_ptr->fmtstr = alloc(maxlen)) == NULL)
  148.     goto error2;
  149. for (i = 0; i < MAX_ADDR; ++i)
  150.     fmt_ptr->adr[i] = NULL;
  151. for (efmp = efm, i = 0; efmp < efm + len; ++efmp, ++i)
  152. {
  153.     if (efmp[0] != '%')     /* copy normal character */
  154.     {
  155. if (efmp[0] == '\' && efmp + 1 < efm + len)
  156.     ++efmp;
  157. fmt_ptr->fmtstr[i] = efmp[0];
  158.     }
  159.     else
  160.     {
  161. fmt_ptr->fmtstr[i++] = '%';
  162. switch (efmp[1])
  163. {
  164. case 'f': /* file name */
  165. fmt_ptr->adr[fmt_ptr->adr_cnt++] = namebuf;
  166. /* FALLTHROUGH */
  167. case 'm': /* message */
  168. if (efmp[1] == 'm')
  169.     fmt_ptr->adr[fmt_ptr->adr_cnt++] = errmsg;
  170. fmt_ptr->fmtstr[i++] = '[';
  171. fmt_ptr->fmtstr[i++] = '^';
  172. #ifdef __EMX__
  173. /* don't allow spaces in file name. This fixes
  174.  * the broken sscanf() where an empty message
  175.  * is accepted as a valid conversion.
  176.  */
  177. if (efmp[1] == 'f')
  178.     fmt_ptr->fmtstr[i++] = ' ';
  179. #endif
  180. if (efmp[2] == '\')     /* could be "%m," */
  181.     j = 3;
  182. else
  183.     j = 2;
  184. if (efmp + j < efm + len)
  185.     fmt_ptr->fmtstr[i++] = efmp[j];
  186. else
  187. {
  188.     /*
  189.      * The %f or %m is the last one in the format,
  190.      * stop at the CR of NL at the end of the line.
  191.      */
  192. #ifdef USE_CRNL
  193.     fmt_ptr->fmtstr[i++] = 'r';
  194. #endif
  195.     fmt_ptr->fmtstr[i++] = 'n';
  196. }
  197. fmt_ptr->fmtstr[i] = ']';
  198. break;
  199. case 'c': /* column */
  200. fmt_ptr->adr[fmt_ptr->adr_cnt++] = &col;
  201. fmt_ptr->fmtstr[i] = 'd';
  202. break;
  203. case 'l': /* line */
  204. fmt_ptr->adr[fmt_ptr->adr_cnt++] = &lnum;
  205. fmt_ptr->fmtstr[i++] = 'l';
  206. fmt_ptr->fmtstr[i] = 'd';
  207. break;
  208. case 'n': /* error number */
  209. fmt_ptr->adr[fmt_ptr->adr_cnt++] = &enr;
  210. fmt_ptr->fmtstr[i] = 'd';
  211. break;
  212. case 't': /* error type */
  213. fmt_ptr->adr[fmt_ptr->adr_cnt++] = &type;
  214. fmt_ptr->fmtstr[i] = 'c';
  215. break;
  216. case '%': /* %% */
  217. case '*': /* %*: no assignment */
  218. fmt_ptr->fmtstr[i] = efmp[1];
  219. break;
  220. default:
  221. EMSG("invalid % in format string");
  222. goto error2;
  223. }
  224. if (fmt_ptr->adr_cnt == MAX_ADDR)
  225. {
  226.     EMSG("too many % in format string");
  227.     goto error2;
  228. }
  229. ++efmp;
  230.     }
  231.     if (i >= maxlen - 6)
  232.     {
  233. EMSG("invalid format string");
  234. goto error2;
  235.     }
  236. }
  237. fmt_ptr->fmtstr[i] = NUL;
  238. /*
  239.  * Advance to next part
  240.  */
  241. efm = skip_to_option_part(efm + len); /* skip comma and spaces */
  242.     }
  243.     if (fmt_first == NULL) /* nothing found */
  244.     {
  245. EMSG("'errorformat' contains no pattern");
  246. goto error2;
  247.     }
  248.     /*
  249.      * got_int is reset here, because it was probably set when killing the
  250.      * ":make" command, but we still want to read the errorfile then.
  251.      */
  252.     got_int = FALSE;
  253.     /*
  254.      * Read the lines in the error file one by one.
  255.      * Try to recognize one of the error formats in each line.
  256.      */
  257.     while (fgets((char *)IObuff, CMDBUFFSIZE, fd) != NULL && !got_int)
  258.     {
  259. if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line)))
  260.       == NULL)
  261.     goto error2;
  262. IObuff[CMDBUFFSIZE] = NUL;  /* for very long lines */
  263. /*
  264.  * Try to match each part of 'errorformat' until we find a complete
  265.  * match or none matches.
  266.  */
  267. valid = TRUE;
  268. for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
  269. {
  270.     namebuf[0] = NUL;
  271.     errmsg[0] = NUL;
  272.     lnum = 0;
  273.     col = 0;
  274.     enr = -1;
  275.     type = 0;
  276.     /*
  277.      * If first char of the format and message don't match, there is
  278.      * no need to try sscanf() on it... Somehow I believe there are
  279.      * very slow implementations of sscanf().
  280.      * -- Paul Slootman
  281.      */
  282.     if (fmt_ptr->fmtstr[0] != '%' && fmt_ptr->fmtstr[0] != IObuff[0])
  283. continue;
  284.     if (sscanf((char *)IObuff, (char *)fmt_ptr->fmtstr,
  285. fmt_ptr->adr[0], fmt_ptr->adr[1], fmt_ptr->adr[2],
  286. fmt_ptr->adr[3], fmt_ptr->adr[4], fmt_ptr->adr[5],
  287. fmt_ptr->adr[6]) == fmt_ptr->adr_cnt)
  288. break;
  289. }
  290. if (fmt_ptr == NULL)
  291. {
  292.     namebuf[0] = NUL; /* no match found, remove file name */
  293.     lnum = 0; /* don't jump to this line */
  294.     valid = FALSE;
  295.     STRCPY(errmsg, IObuff); /* copy whole line to error message */
  296.     if ((efmp = vim_strrchr(errmsg, 'n')) != NULL)
  297. *efmp = NUL;
  298. #ifdef USE_CRNL
  299.     if ((efmp = vim_strrchr(errmsg, 'r')) != NULL)
  300. *efmp = NUL;
  301. #endif
  302. }
  303. if (namebuf[0] == NUL) /* no file name */
  304.     qfp->qf_fnum = 0;
  305. else
  306. #ifdef RISCOS
  307.     /* Name is reported as `main.c', but file is `c.main' */
  308.     qfp->qf_fnum = ro_buflist_add(namebuf);
  309. #else
  310.     qfp->qf_fnum = buflist_add(namebuf);
  311. #endif
  312. if ((qfp->qf_text = vim_strsave(errmsg)) == NULL)
  313.     goto error1;
  314. if (!vim_isprintc(type)) /* only printable chars allowed */
  315.     type = 0;
  316. qfp->qf_lnum = lnum;
  317. qfp->qf_col = col;
  318. qfp->qf_nr = enr;
  319. qfp->qf_type = type;
  320. qfp->qf_valid = valid;
  321. if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */
  322. {
  323.     qf_lists[qf_curlist].qf_start = qfp;
  324.     qfp->qf_prev = qfp; /* first element points to itself */
  325. }
  326. else
  327. {
  328.     qfp->qf_prev = qfprev;
  329.     qfprev->qf_next = qfp;
  330. }
  331. qfp->qf_next = qfp; /* last element points to itself */
  332. qfp->qf_cleared = FALSE;
  333. qfprev = qfp;
  334. ++qf_lists[qf_curlist].qf_count;
  335. if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid) /* first valid entry */
  336. {
  337.     qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count;
  338.     qf_lists[qf_curlist].qf_ptr = qfp;
  339. }
  340. line_breakcheck();
  341.     }
  342.     if (!ferror(fd))
  343.     {
  344. if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */
  345. {
  346.     qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
  347.     qf_lists[qf_curlist].qf_index = 1;
  348.     qf_lists[qf_curlist].qf_nonevalid = TRUE;
  349. }
  350. else
  351.     qf_lists[qf_curlist].qf_nonevalid = FALSE;
  352. retval = qf_lists[qf_curlist].qf_count; /* return number of matches */
  353. goto qf_init_ok;
  354.     }
  355.     emsg(e_readerrf);
  356. error1:
  357.     vim_free(qfp);
  358. error2:
  359.     qf_free(qf_curlist);
  360.     qf_listcount--;
  361.     if (qf_curlist > 0)
  362. --qf_curlist;
  363. qf_init_ok:
  364.     fclose(fd);
  365.     for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
  366.     {
  367. fmt_first = fmt_ptr->next;
  368. vim_free(fmt_ptr->fmtstr);
  369. vim_free(fmt_ptr);
  370.     }
  371. qf_init_end:
  372.     vim_free(namebuf);
  373.     vim_free(errmsg);
  374.     return retval;
  375. }
  376. /*
  377.  * jump to a quickfix line
  378.  * if dir == FORWARD go "errornr" valid entries forward
  379.  * if dir == BACKWARD go "errornr" valid entries backward
  380.  * else if "errornr" is zero, redisplay the same line
  381.  * else go to entry "errornr"
  382.  */
  383.     void
  384. qf_jump(dir, errornr, forceit)
  385.     int     dir;
  386.     int     errornr;
  387.     int     forceit;
  388. {
  389.     struct qf_line  *qf_ptr;
  390.     struct qf_line  *old_qf_ptr;
  391.     int     qf_index;
  392.     int     old_qf_index;
  393.     static char_u   *e_no_more_items = (char_u *)"No more items";
  394.     char_u     *err = e_no_more_items;
  395.     linenr_t     i;
  396.     BUF     *old_curbuf;
  397.     if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
  398.     {
  399. emsg(e_quickfix);
  400. return;
  401.     }
  402.     qf_ptr = qf_lists[qf_curlist].qf_ptr;
  403.     old_qf_ptr = qf_ptr;
  404.     qf_index = qf_lists[qf_curlist].qf_index;
  405.     old_qf_index = qf_index;
  406.     if (dir == FORWARD)     /* next valid entry */
  407.     {
  408. while (errornr--)
  409. {
  410.     old_qf_ptr = qf_ptr;
  411.     old_qf_index = qf_index;
  412.     do
  413.     {
  414. if (qf_index == qf_lists[qf_curlist].qf_count
  415.    || qf_ptr->qf_next == NULL)
  416. {
  417.     qf_ptr = old_qf_ptr;
  418.     qf_index = old_qf_index;
  419.     if (err != NULL)
  420.     {
  421. emsg(err);
  422. goto theend;
  423.     }
  424.     errornr = 0;
  425.     break;
  426. }
  427. ++qf_index;
  428. qf_ptr = qf_ptr->qf_next;
  429.     } while (!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid);
  430.     err = NULL;
  431. }
  432.     }
  433.     else if (dir == BACKWARD)     /* previous valid entry */
  434.     {
  435. while (errornr--)
  436. {
  437.     old_qf_ptr = qf_ptr;
  438.     old_qf_index = qf_index;
  439.     do
  440.     {
  441. if (qf_index == 1 || qf_ptr->qf_prev == NULL)
  442. {
  443.     qf_ptr = old_qf_ptr;
  444.     qf_index = old_qf_index;
  445.     if (err != NULL)
  446.     {
  447. emsg(err);
  448. goto theend;
  449.     }
  450.     errornr = 0;
  451.     break;
  452. }
  453. --qf_index;
  454. qf_ptr = qf_ptr->qf_prev;
  455.     } while (!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid);
  456.     err = NULL;
  457. }
  458.     }
  459.     else if (errornr != 0) /* go to specified number */
  460.     {
  461. while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL)
  462. {
  463.     --qf_index;
  464.     qf_ptr = qf_ptr->qf_prev;
  465. }
  466. while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count
  467.    && qf_ptr->qf_next != NULL)
  468. {
  469.     ++qf_index;
  470.     qf_ptr = qf_ptr->qf_next;
  471. }
  472.     }
  473.     /*
  474.      * If there is a file name,
  475.      * read the wanted file if needed, and check autowrite etc.
  476.      */
  477.     old_curbuf = curbuf;
  478.     if (qf_ptr->qf_fnum == 0 || buflist_getfile(qf_ptr->qf_fnum,
  479.     (linenr_t)1, GETF_SETMARK, forceit) == OK)
  480.     {
  481. /* When not switched to another buffer, still need to set pc mark */
  482. if (curbuf == old_curbuf)
  483.     setpcmark();
  484. /*
  485.  * Go to line with error, unless qf_lnum is 0.
  486.  */
  487. i = qf_ptr->qf_lnum;
  488. if (i > 0)
  489. {
  490.     if (i > curbuf->b_ml.ml_line_count)
  491. i = curbuf->b_ml.ml_line_count;
  492.     curwin->w_cursor.lnum = i;
  493. }
  494. if (qf_ptr->qf_col > 0)
  495. {
  496.     curwin->w_cursor.col = qf_ptr->qf_col - 1;
  497.     adjust_cursor();
  498. }
  499. else
  500.     beginline(BL_WHITE | BL_FIX);
  501. update_topline_redraw();
  502. smsg((char_u *)"(%d of %d)%s%s: %s", qf_index,
  503. qf_lists[qf_curlist].qf_count,
  504.       qf_ptr->qf_cleared ? (char_u *)" (line deleted)" : (char_u *)"",
  505.     qf_types(qf_ptr->qf_type, qf_ptr->qf_nr), qf_ptr->qf_text);
  506. /*
  507.  * if the message is short, redisplay after redrawing the screen
  508.  */
  509. if (linetabsize(IObuff) < ((int)p_ch - 1) * Columns + sc_col)
  510. {
  511.     keep_msg = IObuff;
  512.     keep_msg_attr = 0;
  513. }
  514.     }
  515.     else if (qf_ptr->qf_fnum != 0)
  516.     {
  517. /*
  518.  * Couldn't open file, so put index back where it was. This could
  519.  * happen if the file was readonly and we changed something - webb
  520.  */
  521. qf_ptr = old_qf_ptr;
  522. qf_index = old_qf_index;
  523.     }
  524. theend:
  525.     qf_lists[qf_curlist].qf_ptr = qf_ptr;
  526.     qf_lists[qf_curlist].qf_index = qf_index;
  527. }
  528. /*
  529.  * list all errors
  530.  */
  531.     void
  532. qf_list(all)
  533.     int all;     /* If not :cl!, only show recognised errors */
  534. {
  535.     BUF     *buf;
  536.     char_u     *fname;
  537.     struct qf_line  *qfp;
  538.     int     i;
  539.     if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
  540.     {
  541. emsg(e_quickfix);
  542. return;
  543.     }
  544.     if (qf_lists[qf_curlist].qf_nonevalid)
  545. all = TRUE;
  546.     qfp = qf_lists[qf_curlist].qf_start;
  547.     for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ++i)
  548.     {
  549. if (qfp->qf_valid || all)
  550. {
  551.     msg_putchar('n');
  552.     fname = NULL;
  553.     if (qfp->qf_fnum != 0 &&
  554.  (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
  555. fname = buf->b_fname;
  556.     if (fname == NULL)
  557. sprintf((char *)IObuff, "%2d", i);
  558.     else
  559. sprintf((char *)IObuff, "%2d %s", i, fname);
  560.     msg_outtrans_attr(IObuff, hl_attr(HLF_D));
  561.     if (qfp->qf_lnum == 0)
  562. IObuff[0] = NUL;
  563.     else if (qfp->qf_col == 0)
  564. sprintf((char *)IObuff, ":%ld", qfp->qf_lnum);
  565.     else
  566. sprintf((char *)IObuff, ":%ld, col %d",
  567.    qfp->qf_lnum, qfp->qf_col);
  568.     sprintf((char *)IObuff + STRLEN(IObuff), "%s: ",
  569. qf_types(qfp->qf_type, qfp->qf_nr));
  570.     msg_puts_attr(IObuff, hl_attr(HLF_N));
  571.     msg_prt_line(qfp->qf_text);
  572.     out_flush(); /* show one line at a time */
  573. }
  574. qfp = qfp->qf_next;
  575. ui_breakcheck();
  576.     }
  577. }
  578. /*
  579.  * ":colder [count]": Up in the quickfix stack.
  580.  */
  581.     void
  582. qf_older(count)
  583.     int count;
  584. {
  585.     while (count--)
  586.     {
  587. if (qf_curlist == 0)
  588. {
  589.     EMSG("At bottom of quickfix stack");
  590.     return;
  591. }
  592. --qf_curlist;
  593.     }
  594.     qf_msg();
  595. }
  596. /*
  597.  * ":cnewer [count]": Down in the quickfix stack.
  598.  */
  599.     void
  600. qf_newer(count)
  601.     int count;
  602. {
  603.     while (count--)
  604.     {
  605. if (qf_curlist >= qf_listcount - 1)
  606. {
  607.     EMSG("At top of quickfix stack");
  608.     return;
  609. }
  610. ++qf_curlist;
  611.     }
  612.     qf_msg();
  613. }
  614.     static void
  615. qf_msg()
  616. {
  617.     smsg((char_u *)"error list %d of %d; %d errors",
  618.     qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count);
  619. }
  620. /*
  621.  * free the error list
  622.  */
  623.     static void
  624. qf_free(idx)
  625.     int idx;
  626. {
  627.     struct qf_line *qfp;
  628.     while (qf_lists[idx].qf_count)
  629.     {
  630. qfp = qf_lists[idx].qf_start->qf_next;
  631. vim_free(qf_lists[idx].qf_start->qf_text);
  632. vim_free(qf_lists[idx].qf_start);
  633. qf_lists[idx].qf_start = qfp;
  634. --qf_lists[idx].qf_count;
  635.     }
  636. }
  637. /*
  638.  * qf_mark_adjust: adjust marks
  639.  */
  640.    void
  641. qf_mark_adjust(line1, line2, amount, amount_after)
  642.     linenr_t line1;
  643.     linenr_t line2;
  644.     long amount;
  645.     long amount_after;
  646. {
  647.     int i;
  648.     struct qf_line *qfp;
  649.     int idx;
  650.     for (idx = 0; idx < qf_listcount; ++idx)
  651. if (qf_lists[idx].qf_count)
  652.     for (i = 0, qfp = qf_lists[idx].qf_start;
  653.        i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
  654. if (qfp->qf_fnum == curbuf->b_fnum)
  655. {
  656.     if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
  657.     {
  658. if (amount == MAXLNUM)
  659.     qfp->qf_cleared = TRUE;
  660. else
  661.     qfp->qf_lnum += amount;
  662.     }
  663.     if (amount_after && qfp->qf_lnum > line2)
  664. qfp->qf_lnum += amount_after;
  665. }
  666. }
  667. /*
  668.  * Make a nice message out of the error character and the error number:
  669.  *  char    number message
  670.  *  e or E    0 "   error"
  671.  *  w or W    0 " warning"
  672.  *  0       0 ""
  673.  *  other     0 " c"
  674.  *  e or E    n "   error n"
  675.  *  w or W    n " warning n"
  676.  *  0       n "   error n"
  677.  *  other     n " c n"
  678.  */
  679.     static char_u *
  680. qf_types(c, nr)
  681.     int c, nr;
  682. {
  683.     static char_u buf[20];
  684.     static char_u cc[3];
  685.     char_u *p;
  686.     if (c == 'W' || c == 'w')
  687. p = (char_u *)" warning";
  688.     else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
  689. p = (char_u *)"   error";
  690.     else if (c == 0)
  691. p = (char_u *)"";
  692.     else
  693.     {
  694. cc[0] = ' ';
  695. cc[1] = c;
  696. cc[2] = NUL;
  697. p = cc;
  698.     }
  699.     if (nr <= 0)
  700. return p;
  701.     sprintf((char *)buf, "%s %3d", p, nr);
  702.     return buf;
  703. }
  704. #endif /* QUICKFIX */