Skip to content

Instantly share code, notes, and snippets.

@brailsmt
Created December 14, 2017 20:29
Show Gist options
  • Save brailsmt/e218b170158d6ac9730027c36daeeded to your computer and use it in GitHub Desktop.
Save brailsmt/e218b170158d6ac9730027c36daeeded to your computer and use it in GitHub Desktop.
diff of the changes in src/nvim/quickfix.c between master (6ff13d78b) and v0.1.7 tag.
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 1fc585f0c..f0d77f9e2 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1,6 +1,3 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
/*
* quickfix.c: functions for quickfix mode, using a file with error messages
*/
@@ -51,6 +48,8 @@ struct dir_stack_T {
char_u *dirname;
};
+static struct dir_stack_T *dir_stack = NULL;
+
/*
* For each error the next struct is allocated and linked in a list.
*/
@@ -77,14 +76,13 @@ struct qfline_S {
#define LISTCOUNT 10
typedef struct qf_list_S {
- qfline_T *qf_start; // pointer to the first error
- qfline_T *qf_last; // pointer to the last error
- qfline_T *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
- char_u *qf_title; // title derived from the command that created
- // the error list
+ qfline_T *qf_start; /* pointer to the first error */
+ qfline_T *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 */
+ char_u *qf_title; /* title derived from the command that created
+ * the error list */
} qf_list_T;
struct qf_info_S {
@@ -98,15 +96,6 @@ struct qf_info_S {
int qf_listcount; /* current number of lists */
int qf_curlist; /* current error list */
qf_list_T qf_lists[LISTCOUNT];
-
- int qf_dir_curlist; ///< error list for qf_dir_stack
- struct dir_stack_T *qf_dir_stack;
- char_u *qf_directory;
- struct dir_stack_T *qf_file_stack;
- char_u *qf_currfile;
- bool qf_multiline;
- bool qf_multiignore;
- bool qf_multiscan;
};
static qf_info_T ql_info; /* global quickfix list */
@@ -140,40 +129,6 @@ struct efm_S {
int conthere; /* %> used */
};
-enum {
- QF_FAIL = 0,
- QF_OK = 1,
- QF_END_OF_INPUT = 2,
- QF_NOMEM = 3,
- QF_IGNORE_LINE = 4
-};
-
-typedef struct {
- char_u *linebuf;
- size_t linelen;
- char_u *growbuf;
- size_t growbufsiz;
- FILE *fd;
- typval_T *tv;
- char_u *p_str;
- listitem_T *p_li;
- buf_T *buf;
- linenr_T buflnum;
- linenr_T lnumlast;
-} qfstate_T;
-
-typedef struct {
- char_u *namebuf;
- char_u *errmsg;
- size_t errmsglen;
- long lnum;
- int col;
- bool use_viscol;
- char_u *pattern;
- int enr;
- char_u type;
- bool valid;
-} qffields_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "quickfix.c.generated.h"
@@ -188,11 +143,6 @@ typedef struct {
*/
#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
-// Looking up a buffer can be slow if there are many. Remember the last one
-// to make this a lot faster if there are multiple matches in the same file.
-static char_u *qf_last_bufname = NULL;
-static bufref_T qf_last_bufref = { NULL, 0, 0 };
-
/*
* Read the errorfile "efile" into memory, line by line, building the error
* list. Set the error list's title to qf_title.
@@ -218,899 +168,586 @@ qf_init (
qf_title);
}
-// Maximum number of bytes allowed per line while reading an errorfile.
-static const size_t LINE_MAXLEN = 4096;
-
-static struct fmtpattern
-{
- char_u convchar;
- char *pattern;
-} fmt_pat[FMT_PATTERNS] =
+/*
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
+ * Alternative: when "efile" is null read errors from buffer "buf".
+ * Always use 'errorformat' from "buf" if there is a local value.
+ * Then "lnumfirst" and "lnumlast" specify the range of lines to use.
+ * Set the title of the list to "qf_title".
+ * Return -1 for error, number of errors for success.
+ */
+static int
+qf_init_ext (
+ qf_info_T *qi,
+ char_u *efile,
+ buf_T *buf,
+ typval_T *tv,
+ char_u *errorformat,
+ int newlist, /* TRUE: start a new error list */
+ linenr_T lnumfirst, /* first line number to use */
+ linenr_T lnumlast, /* last line number to use */
+ char_u *qf_title
+)
{
- { 'f', ".\\+" }, // only used when at end
- { 'n', "\\d\\+" },
- { 'l', "\\d\\+" },
- { 'c', "\\d\\+" },
- { 't', "." },
- { 'm', ".\\+" },
- { 'r', ".*" },
- { 'p', "[- .]*" }, // NOLINT(whitespace/tab)
- { 'v', "\\d\\+" },
- { 's', ".\\+" }
-};
+ char_u *namebuf;
+ char_u *errmsg;
+ char_u *pattern;
+ char_u *fmtstr = NULL;
+ int col = 0;
+ bool use_viscol = false;
+ char_u type = 0;
+ linenr_T buflnum = lnumfirst;
+ long lnum = 0L;
+ int enr = 0;
+ FILE *fd = NULL;
+ qfline_T *qfprev = NULL; /* init to make SASC shut up */
+ char_u *efmp;
+ efm_T *fmt_first = NULL;
+ efm_T *fmt_last = NULL;
+ efm_T *fmt_ptr;
+ efm_T *fmt_start = NULL;
+ char_u *efm;
+ char_u *ptr;
+ char_u *srcptr;
+ int len;
+ int i;
+ int round;
+ int idx = 0;
+ bool multiline = false;
+ bool multiignore = false;
+ bool multiscan = false;
+ int retval = -1; // default: return error flag
+ char_u *directory = NULL;
+ char_u *currfile = NULL;
+ char_u *tail = NULL;
+ char_u *p_str = NULL;
+ listitem_T *p_li = NULL;
+ struct dir_stack_T *file_stack = NULL;
+ regmatch_T regmatch;
+ static struct fmtpattern {
+ char_u convchar;
+ char *pattern;
+ } fmt_pat[FMT_PATTERNS] =
+ {
+ {'f', ".\\+"}, /* only used when at end */
+ {'n', "\\d\\+"},
+ {'l', "\\d\\+"},
+ {'c', "\\d\\+"},
+ {'t', "."},
+ {'m', ".\\+"},
+ {'r', ".*"},
+ {'p', "[- .]*"},
+ {'v', "\\d\\+"},
+ {'s', ".\\+"}
+ };
+
+ namebuf = xmalloc(CMDBUFFSIZE + 1);
+ errmsg = xmalloc(CMDBUFFSIZE + 1);
+ pattern = xmalloc(CMDBUFFSIZE + 1);
+
+ if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) {
+ EMSG2(_(e_openerrf), efile);
+ goto qf_init_end;
+ }
-// Converts a 'errorformat' string to regular expression pattern
-static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
- char_u *regpat, char_u *errmsg)
-{
- // Build regexp pattern from current 'errorformat' option
- char_u *ptr = regpat;
- *ptr++ = '^';
- int round = 0;
- for (char_u *efmp = efm; efmp < efm + len; efmp++) {
- if (*efmp == '%') {
- efmp++;
- int idx;
- for (idx = 0; idx < FMT_PATTERNS; idx++) {
- if (fmt_pat[idx].convchar == *efmp) {
- break;
- }
- }
- if (idx < FMT_PATTERNS) {
- if (fmt_ptr->addr[idx]) {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E372: Too many %%%c in format string"), *efmp);
- EMSG(errmsg);
- return -1;
- }
- if ((idx
- && idx < 6
- && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL)
- || (idx == 6
- && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E373: Unexpected %%%c in format string"), *efmp);
- EMSG(errmsg);
- return -1;
- }
- round++;
- fmt_ptr->addr[idx] = (char_u)round;
- *ptr++ = '\\';
- *ptr++ = '(';
-#ifdef BACKSLASH_IN_FILENAME
- if (*efmp == 'f') {
- // Also match "c:" in the file name, even when
- // checking for a colon next: "%f:".
- // "\%(\a:\)\="
- STRCPY(ptr, "\\%(\\a:\\)\\=");
- ptr += 10;
- }
+ if (newlist || qi->qf_curlist == qi->qf_listcount)
+ /* make place for a new list */
+ qf_new_list(qi, qf_title);
+ else if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
+ /* Adding to existing list, find last entry. */
+ for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start;
+ qfprev->qf_next != qfprev; qfprev = qfprev->qf_next)
+ ;
+
+ /*
+ * Each part of the format string is copied and modified from errorformat to
+ * regex prog. Only a few % characters are allowed.
+ */
+ /* Use the local value of 'errorformat' if it's set. */
+ if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
+ efm = buf->b_p_efm;
+ else
+ efm = errorformat;
+ /*
+ * Get some space to modify the format string into.
+ */
+ size_t fmtstr_size = 3 * FMT_PATTERNS + 4 * STRLEN(efm);
+ for (round = FMT_PATTERNS; round > 0; ) {
+ fmtstr_size += STRLEN(fmt_pat[--round].pattern);
+ }
+#ifdef COLON_IN_FILENAME
+ fmtstr_size += 12; // "%f" can become twelve chars longer
+#else
+ fmtstr_size += 2; // "%f" can become two chars longer
#endif
- if (*efmp == 'f' && efmp[1] != NUL) {
- if (efmp[1] != '\\' && efmp[1] != '%') {
- // A file name may contain spaces, but this isn't
- // in "\f". For "%f:%l:%m" there may be a ":" in
- // the file name. Use ".\{-1,}x" instead (x is
- // the next character), the requirement that :999:
- // follows should work.
- STRCPY(ptr, ".\\{-1,}");
- ptr += 7;
- } else {
- // File name followed by '\\' or '%': include as
- // many file name chars as possible.
- STRCPY(ptr, "\\f\\+");
- ptr += 4;
+ fmtstr = xmalloc(fmtstr_size);
+
+ while (efm[0] != NUL) {
+ /*
+ * Allocate a new eformat structure and put it at the end of the list
+ */
+ fmt_ptr = xcalloc(1, sizeof(efm_T));
+ if (fmt_first == NULL) /* first one */
+ fmt_first = fmt_ptr;
+ else
+ fmt_last->next = fmt_ptr;
+ fmt_last = fmt_ptr;
+
+ /*
+ * Isolate one part in the 'errorformat' option
+ */
+ for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
+ if (efm[len] == '\\' && efm[len + 1] != NUL)
+ ++len;
+
+ /*
+ * Build regexp pattern from current 'errorformat' option
+ */
+ ptr = fmtstr;
+ *ptr++ = '^';
+ round = 0;
+ for (efmp = efm; efmp < efm + len; ++efmp) {
+ if (*efmp == '%') {
+ ++efmp;
+ for (idx = 0; idx < FMT_PATTERNS; ++idx)
+ if (fmt_pat[idx].convchar == *efmp)
+ break;
+ if (idx < FMT_PATTERNS) {
+ if (fmt_ptr->addr[idx]) {
+ sprintf((char *)errmsg,
+ _("E372: Too many %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ goto error2;
}
- } else {
- char_u *srcptr = (char_u *)fmt_pat[idx].pattern;
- while ((*ptr = *srcptr++) != NUL) {
- ptr++;
+ if ((idx
+ && idx < 6
+ && vim_strchr((char_u *)"DXOPQ",
+ fmt_ptr->prefix) != NULL)
+ || (idx == 6
+ && vim_strchr((char_u *)"OPQ",
+ fmt_ptr->prefix) == NULL)) {
+ sprintf((char *)errmsg,
+ _("E373: Unexpected %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ goto error2;
}
- }
- *ptr++ = '\\';
- *ptr++ = ')';
- } else if (*efmp == '*') {
- if (*++efmp == '[' || *efmp == '\\') {
- if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc.
- if (efmp[1] == '^') {
- *ptr++ = *++efmp;
+ fmt_ptr->addr[idx] = (char_u)++ round;
+ *ptr++ = '\\';
+ *ptr++ = '(';
+#ifdef BACKSLASH_IN_FILENAME
+ if (*efmp == 'f') {
+ /* Also match "c:" in the file name, even when
+ * checking for a colon next: "%f:".
+ * "\%(\a:\)\=" */
+ STRCPY(ptr, "\\%(\\a:\\)\\=");
+ ptr += 10;
+ }
+#endif
+ if (*efmp == 'f' && efmp[1] != NUL) {
+ if (efmp[1] != '\\' && efmp[1] != '%') {
+ /* A file name may contain spaces, but this isn't
+ * in "\f". For "%f:%l:%m" there may be a ":" in
+ * the file name. Use ".\{-1,}x" instead (x is
+ * the next character), the requirement that :999:
+ * follows should work. */
+ STRCPY(ptr, ".\\{-1,}");
+ ptr += 7;
+ } else {
+ /* File name followed by '\\' or '%': include as
+ * many file name chars as possible. */
+ STRCPY(ptr, "\\f\\+");
+ ptr += 4;
}
- if (efmp < efm + len) {
- efmp++;
- *ptr++ = *efmp; // could be ']'
- while (efmp < efm + len) {
- efmp++;
- if ((*ptr++ = *efmp) == ']') {
- break;
+ } else {
+ srcptr = (char_u *)fmt_pat[idx].pattern;
+ while ((*ptr = *srcptr++) != NUL)
+ ++ptr;
+ }
+ *ptr++ = '\\';
+ *ptr++ = ')';
+ } else if (*efmp == '*') {
+ if (*++efmp == '[' || *efmp == '\\') {
+ if ((*ptr++ = *efmp) == '[') { /* %*[^a-z0-9] etc. */
+ if (efmp[1] == '^')
+ *ptr++ = *++efmp;
+ if (efmp < efm + len) {
+ *ptr++ = *++efmp; /* could be ']' */
+ while (efmp < efm + len
+ && (*ptr++ = *++efmp) != ']')
+ /* skip */;
+ if (efmp == efm + len) {
+ EMSG(_("E374: Missing ] in format string"));
+ goto error2;
}
}
- if (efmp == efm + len) {
- EMSG(_("E374: Missing ] in format string"));
- return -1;
- }
- }
- } else if (efmp < efm + len) { // %*\D, %*\s etc.
- efmp++;
- *ptr++ = *efmp;
+ } else if (efmp < efm + len) /* %*\D, %*\s etc. */
+ *ptr++ = *++efmp;
+ *ptr++ = '\\';
+ *ptr++ = '+';
+ } else {
+ /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */
+ sprintf((char *)errmsg,
+ _("E375: Unsupported %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ goto error2;
+ }
+ } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
+ *ptr++ = *efmp; /* regexp magic characters */
+ else if (*efmp == '#')
+ *ptr++ = '*';
+ else if (*efmp == '>')
+ fmt_ptr->conthere = TRUE;
+ else if (efmp == efm + 1) { /* analyse prefix */
+ if (vim_strchr((char_u *)"+-", *efmp) != NULL)
+ fmt_ptr->flags = *efmp++;
+ if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL)
+ fmt_ptr->prefix = *efmp;
+ else {
+ sprintf((char *)errmsg,
+ _("E376: Invalid %%%c in format string prefix"), *efmp);
+ EMSG(errmsg);
+ goto error2;
}
- *ptr++ = '\\';
- *ptr++ = '+';
- } else {
- // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ?
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E375: Unsupported %%%c in format string"), *efmp);
- EMSG(errmsg);
- return -1;
- }
- } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) {
- *ptr++ = *efmp; // regexp magic characters
- } else if (*efmp == '#') {
- *ptr++ = '*';
- } else if (*efmp == '>') {
- fmt_ptr->conthere = true;
- } else if (efmp == efm + 1) { // analyse prefix
- if (vim_strchr((char_u *)"+-", *efmp) != NULL) {
- fmt_ptr->flags = *efmp++;
- }
- if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) {
- fmt_ptr->prefix = *efmp;
} else {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E376: Invalid %%%c in format string prefix"), *efmp);
+ sprintf((char *)errmsg,
+ _("E377: Invalid %%%c in format string"), *efmp);
EMSG(errmsg);
- return -1;
+ goto error2;
}
- } else {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E377: Invalid %%%c in format string"), *efmp);
- EMSG(errmsg);
- return -1;
- }
- } else { // copy normal character
- if (*efmp == '\\' && efmp + 1 < efm + len) {
- efmp++;
- } else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) {
- *ptr++ = '\\'; // escape regexp atoms
- }
- if (*efmp) {
- *ptr++ = *efmp;
+ } else { /* copy normal character */
+ if (*efmp == '\\' && efmp + 1 < efm + len)
+ ++efmp;
+ else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL)
+ *ptr++ = '\\'; /* escape regexp atoms */
+ if (*efmp)
+ *ptr++ = *efmp;
}
}
+ *ptr++ = '$';
+ *ptr = NUL;
+ if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
+ goto error2;
+ /*
+ * Advance to next part
+ */
+ efm = skip_to_option_part(efm + len); /* skip comma and spaces */
}
- *ptr++ = '$';
- *ptr = NUL;
-
- return 0;
-}
-
-static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
-
-static void free_efm_list(efm_T **efm_first)
-{
- for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) {
- *efm_first = efm_ptr->next;
- vim_regfree(efm_ptr->prog);
- xfree(efm_ptr);
- }
-
- fmt_start = NULL;
-}
-
-// Parse 'errorformat' option
-static efm_T * parse_efm_option(char_u *efm)
-{
- efm_T *fmt_ptr = NULL;
- efm_T *fmt_first = NULL;
- efm_T *fmt_last = NULL;
- int len;
-
- size_t errmsglen = CMDBUFFSIZE + 1;
- char_u *errmsg = xmalloc(errmsglen);
-
- // Get some space to modify the format string into.
- size_t i = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2);
- for (int round = FMT_PATTERNS - 1; round >= 0; ) {
- i += STRLEN(fmt_pat[round--].pattern);
- }
- i += 2; // "%f" can become two chars longer
- char_u *fmtstr = xmalloc(i);
-
- while (efm[0] != NUL) {
- // Allocate a new eformat structure and put it at the end of the list
- fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T));
- if (fmt_first == NULL) { // first one
- fmt_first = fmt_ptr;
- } else {
- fmt_last->next = fmt_ptr;
- }
- fmt_last = fmt_ptr;
-
- // Isolate one part in the 'errorformat' option
- for (len = 0; efm[len] != NUL && efm[len] != ','; len++) {
- if (efm[len] == '\\' && efm[len + 1] != NUL) {
- len++;
- }
- }
-
- if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) {
- goto parse_efm_error;
- }
- if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) {
- goto parse_efm_error;
- }
- // Advance to next part
- efm = skip_to_option_part(efm + len); // skip comma and spaces
- }
-
- if (fmt_first == NULL) { // nothing found
+ if (fmt_first == NULL) { /* nothing found */
EMSG(_("E378: 'errorformat' contains no pattern"));
+ goto error2;
}
- goto parse_efm_end;
-
-parse_efm_error:
- free_efm_list(&fmt_first);
-
-parse_efm_end:
- xfree(fmtstr);
- xfree(errmsg);
-
- return fmt_first;
-}
-
-static char_u *qf_grow_linebuf(qfstate_T *state, size_t newsz)
-{
- // If the line exceeds LINE_MAXLEN exclude the last
- // byte since it's not a NL character.
- state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
- if (state->growbuf == NULL) {
- state->growbuf = xmalloc(state->linelen + 1);
- state->growbufsiz = state->linelen;
- } else if (state->linelen > state->growbufsiz) {
- state->growbuf = xrealloc(state->growbuf, state->linelen + 1);
- state->growbufsiz = state->linelen;
- }
- return state->growbuf;
-}
-
-/// Get the next string (separated by newline) from state->p_str.
-static int qf_get_next_str_line(qfstate_T *state)
-{
- // Get the next line from the supplied string
- char_u *p_str = state->p_str;
- char_u *p;
- size_t len;
-
- if (*p_str == NUL) { // Reached the end of the string
- return QF_END_OF_INPUT;
- }
-
- p = vim_strchr(p_str, '\n');
- if (p != NULL) {
- len = (size_t)(p - p_str) + 1;
- } else {
- len = STRLEN(p_str);
- }
-
- if (len > IOSIZE - 2) {
- state->linebuf = qf_grow_linebuf(state, len);
- } else {
- state->linebuf = IObuff;
- state->linelen = len;
- }
- STRLCPY(state->linebuf, p_str, state->linelen + 1);
-
- // Increment using len in order to discard the rest of the line if it
- // exceeds LINE_MAXLEN.
- p_str += len;
- state->p_str = p_str;
-
- return QF_OK;
-}
-
-/// Get the next string from state->p_Li.
-static int qf_get_next_list_line(qfstate_T *state)
-{
- listitem_T *p_li = state->p_li;
- size_t len;
-
- // Get the next line from the supplied list
- while (p_li != NULL
- && (p_li->li_tv.v_type != VAR_STRING
- || p_li->li_tv.vval.v_string == NULL)) {
- p_li = p_li->li_next; // Skip non-string items
- }
-
- if (p_li == NULL) { // End of the list
- state->p_li = NULL;
- return QF_END_OF_INPUT;
- }
-
- len = STRLEN(p_li->li_tv.vval.v_string);
- if (len > IOSIZE - 2) {
- state->linebuf = qf_grow_linebuf(state, len);
- } else {
- state->linebuf = IObuff;
- state->linelen = len;
- }
-
- STRLCPY(state->linebuf, p_li->li_tv.vval.v_string, state->linelen + 1);
-
- state->p_li = p_li->li_next; // next item
- return QF_OK;
-}
-
-/// Get the next string from state->buf.
-static int qf_get_next_buf_line(qfstate_T *state)
-{
- char_u *p_buf = NULL;
- size_t len;
+ /*
+ * 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;
- // Get the next line from the supplied buffer
- if (state->buflnum > state->lnumlast) {
- return QF_END_OF_INPUT;
- }
- p_buf = ml_get_buf(state->buf, state->buflnum, false);
- state->buflnum += 1;
+ /* Always ignore case when looking for a matching error. */
+ regmatch.rm_ic = TRUE;
- len = STRLEN(p_buf);
- if (len > IOSIZE - 2) {
- state->linebuf = qf_grow_linebuf(state, len);
- } else {
- state->linebuf = IObuff;
- state->linelen = len;
+ if (tv != NULL) {
+ if (tv->v_type == VAR_STRING)
+ p_str = tv->vval.v_string;
+ else if (tv->v_type == VAR_LIST)
+ p_li = tv->vval.v_list->lv_first;
}
- STRLCPY(state->linebuf, p_buf, state->linelen + 1);
-
- return QF_OK;
-}
-/// Get the next string from file state->fd.
-static int qf_get_next_file_line(qfstate_T *state)
-{
- size_t growbuflen;
+ /*
+ * Read the lines in the error file one by one.
+ * Try to recognize one of the error formats in each line.
+ */
+ while (!got_int) {
+ /* Get the next line. */
+ if (fd == NULL) {
+ if (tv != NULL) {
+ if (tv->v_type == VAR_STRING) {
+ /* Get the next line from the supplied string */
+ char_u *p;
+
+ if (!*p_str) /* Reached the end of the string */
+ break;
-retry:
- errno = 0;
- if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
- if (errno == EINTR) {
- goto retry;
- }
- return QF_END_OF_INPUT;
- }
+ p = vim_strchr(p_str, '\n');
+ if (p)
+ len = (int)(p - p_str + 1);
+ else
+ len = (int)STRLEN(p_str);
- bool discard = false;
- state->linelen = STRLEN(IObuff);
- if (state->linelen == IOSIZE - 1
- && !(IObuff[state->linelen - 1] == '\n')) {
- // The current line exceeds IObuff, continue reading using growbuf
- // until EOL or LINE_MAXLEN bytes is read.
- if (state->growbuf == NULL) {
- state->growbufsiz = 2 * (IOSIZE - 1);
- state->growbuf = xmalloc(state->growbufsiz);
- }
+ if (len > CMDBUFFSIZE - 2)
+ STRLCPY(IObuff, p_str, CMDBUFFSIZE - 1);
+ else
+ STRLCPY(IObuff, p_str, len + 1);
+
+ p_str += len;
+ } else if (tv->v_type == VAR_LIST) {
+ // Get the next line from the supplied list
+ while (p_li && (p_li->li_tv.v_type != VAR_STRING
+ || p_li->li_tv.vval.v_string == NULL)) {
+ p_li = p_li->li_next; // Skip non-string items
+ }
- // Copy the read part of the line, excluding null-terminator
- memcpy(state->growbuf, IObuff, IOSIZE - 1);
- growbuflen = state->linelen;
+ if (!p_li) /* End of the list */
+ break;
- for (;;) {
- errno = 0;
- if (fgets((char *)state->growbuf + growbuflen,
- (int)(state->growbufsiz - growbuflen), state->fd) == NULL) {
- if (errno == EINTR) {
- continue;
- }
- break;
- }
- state->linelen = STRLEN(state->growbuf + growbuflen);
- growbuflen += state->linelen;
- if (state->growbuf[growbuflen - 1] == '\n') {
- break;
- }
- if (state->growbufsiz == LINE_MAXLEN) {
- discard = true;
- break;
- }
+ len = (int)STRLEN(p_li->li_tv.vval.v_string);
+ if (len > CMDBUFFSIZE - 2)
+ len = CMDBUFFSIZE - 2;
- state->growbufsiz = (2 * state->growbufsiz < LINE_MAXLEN)
- ? 2 * state->growbufsiz : LINE_MAXLEN;
- state->growbuf = xrealloc(state->growbuf, state->growbufsiz);
- }
+ STRLCPY(IObuff, p_li->li_tv.vval.v_string, len + 1);
- while (discard) {
- // The current line is longer than LINE_MAXLEN, continue reading but
- // discard everything until EOL or EOF is reached.
- errno = 0;
- if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
- if (errno == EINTR) {
- continue;
+ p_li = p_li->li_next; /* next item */
}
- break;
- }
- if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') {
- break;
- }
- }
-
- state->linebuf = state->growbuf;
- state->linelen = growbuflen;
- } else {
- state->linebuf = IObuff;
- }
- return QF_OK;
-}
-
-/// Get the next string from a file/buffer/list/string.
-static int qf_get_nextline(qfstate_T *state)
-{
- int status = QF_FAIL;
-
- if (state->fd == NULL) {
- if (state->tv != NULL) {
- if (state->tv->v_type == VAR_STRING) {
- // Get the next line from the supplied string
- status = qf_get_next_str_line(state);
- } else if (state->tv->v_type == VAR_LIST) {
- // Get the next line from the supplied list
- status = qf_get_next_list_line(state);
+ } else {
+ /* Get the next line from the supplied buffer */
+ if (buflnum > lnumlast)
+ break;
+ STRLCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE),
+ CMDBUFFSIZE - 1);
}
- } else {
- // Get the next line from the supplied buffer
- status = qf_get_next_buf_line(state);
- }
- } else {
- // Get the next line from the supplied file
- status = qf_get_next_file_line(state);
- }
+ } else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
+ break;
- if (status != QF_OK) {
- return status;
- }
+ IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */
+ remove_bom(IObuff);
- if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n') {
- state->linebuf[state->linelen - 1] = NUL;
+ if ((efmp = vim_strrchr(IObuff, '\n')) != NULL)
+ *efmp = NUL;
#ifdef USE_CRNL
- if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r') {
- state->linebuf[state->linelen - 2] = NUL;
- }
+ if ((efmp = vim_strrchr(IObuff, '\r')) != NULL)
+ *efmp = NUL;
#endif
- }
-
- remove_bom(state->linebuf);
-
- return QF_OK;
-}
-
-
-/// Parse a line and get the quickfix fields.
-/// Return the QF_ status.
-static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen,
- efm_T *fmt_first, qffields_T *fields)
-{
- efm_T *fmt_ptr;
- size_t len;
- int i;
- int idx = 0;
- char_u *tail = NULL;
- regmatch_T regmatch;
-
- // Always ignore case when looking for a matching error.
- regmatch.rm_ic = true;
-
- // If there was no %> item start at the first pattern
- if (fmt_start == NULL) {
- fmt_ptr = fmt_first;
- } else {
- fmt_ptr = fmt_start;
- fmt_start = NULL;
- }
+ /* If there was no %> item start at the first pattern */
+ if (fmt_start == NULL)
+ fmt_ptr = fmt_first;
+ else {
+ fmt_ptr = fmt_start;
+ fmt_start = NULL;
+ }
- // Try to match each part of 'errorformat' until we find a complete
- // match or no match.
- fields->valid = true;
+ // Try to match each part of 'errorformat' until we find a complete
+ // match or no match.
+ bool valid = true;
restofline:
- for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) {
- idx = fmt_ptr->prefix;
- if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) {
- continue;
- }
- fields->namebuf[0] = NUL;
- fields->pattern[0] = NUL;
- if (!qi->qf_multiscan) {
- fields->errmsg[0] = NUL;
- }
- fields->lnum = 0;
- fields->col = 0;
- fields->use_viscol = false;
- fields->enr = -1;
- fields->type = 0;
- tail = NULL;
-
- regmatch.regprog = fmt_ptr->prog;
- int r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
- fmt_ptr->prog = regmatch.regprog;
- if (r) {
- if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) {
+ for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) {
+ idx = fmt_ptr->prefix;
+ if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL)
continue;
- }
- if (vim_strchr((char_u *)"EWI", idx) != NULL) {
- fields->type = (char_u)idx;
- } else {
- fields->type = 0;
- }
- // Extract error message data from matched line.
- // We check for an actual submatch, because "\[" and "\]" in
- // the 'errorformat' may cause the wrong submatch to be used.
- if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
- continue;
- }
- // Expand ~/file and $HOME/file to full path.
- char_u c = *regmatch.endp[i];
- *regmatch.endp[i] = NUL;
- expand_env(regmatch.startp[i], fields->namebuf, CMDBUFFSIZE);
- *regmatch.endp[i] = c;
-
- if (vim_strchr((char_u *)"OPQ", idx) != NULL
- && !os_path_exists(fields->namebuf)) {
+ namebuf[0] = NUL;
+ pattern[0] = NUL;
+ if (!multiscan)
+ errmsg[0] = NUL;
+ lnum = 0;
+ col = 0;
+ use_viscol = false;
+ enr = -1;
+ type = 0;
+ tail = NULL;
+
+ regmatch.regprog = fmt_ptr->prog;
+ int r = vim_regexec(&regmatch, IObuff, (colnr_T)0);
+ fmt_ptr->prog = regmatch.regprog;
+ if (r) {
+ if ((idx == 'C' || idx == 'Z') && !multiline) {
continue;
}
- }
- if ((i = (int)fmt_ptr->addr[1]) > 0) { // %n
- if (regmatch.startp[i] == NULL) {
- continue;
+ if (vim_strchr((char_u *)"EWI", idx) != NULL) {
+ type = (char_u)idx;
+ } else {
+ type = 0;
}
- fields->enr = (int)atol((char *)regmatch.startp[i]);
- }
- if ((i = (int)fmt_ptr->addr[2]) > 0) { // %l
- if (regmatch.startp[i] == NULL) {
- continue;
+ // Extract error message data from matched line.
+ // We check for an actual submatch, because "\[" and "\]" in
+ // the 'errorformat' may cause the wrong submatch to be used.
+ if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
+ continue;
+ }
+ // Expand ~/file and $HOME/file to full path.
+ char_u c = *regmatch.endp[i];
+ *regmatch.endp[i] = NUL;
+ expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE);
+ *regmatch.endp[i] = c;
+
+ if (vim_strchr((char_u *)"OPQ", idx) != NULL
+ && !os_path_exists(namebuf)) {
+ continue;
+ }
}
- fields->lnum = atol((char *)regmatch.startp[i]);
- }
- if ((i = (int)fmt_ptr->addr[3]) > 0) { // %c
- if (regmatch.startp[i] == NULL) {
- continue;
+ if ((i = (int)fmt_ptr->addr[1]) > 0) { /* %n */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ enr = (int)atol((char *)regmatch.startp[i]);
}
- fields->col = (int)atol((char *)regmatch.startp[i]);
- }
- if ((i = (int)fmt_ptr->addr[4]) > 0) { // %t
- if (regmatch.startp[i] == NULL) {
- continue;
+ if ((i = (int)fmt_ptr->addr[2]) > 0) { /* %l */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ lnum = atol((char *)regmatch.startp[i]);
}
- fields->type = *regmatch.startp[i];
- }
- if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+
- if (linelen > fields->errmsglen) {
- // linelen + null terminator
- fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
- fields->errmsglen = linelen + 1;
+ if ((i = (int)fmt_ptr->addr[3]) > 0) { /* %c */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ col = (int)atol((char *)regmatch.startp[i]);
}
- STRLCPY(fields->errmsg, linebuf, linelen + 1);
- } else if ((i = (int)fmt_ptr->addr[5]) > 0) { // %m
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
- continue;
+ if ((i = (int)fmt_ptr->addr[4]) > 0) { /* %t */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ type = *regmatch.startp[i];
}
- len = (size_t)(regmatch.endp[i] - regmatch.startp[i]);
- if (len > fields->errmsglen) {
- // len + null terminator
- fields->errmsg = xrealloc(fields->errmsg, len + 1);
- fields->errmsglen = len + 1;
+ if (fmt_ptr->flags == '+' && !multiscan) /* %+ */
+ STRCPY(errmsg, IObuff);
+ else if ((i = (int)fmt_ptr->addr[5]) > 0) { /* %m */
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
+ continue;
+ len = (int)(regmatch.endp[i] - regmatch.startp[i]);
+ STRLCPY(errmsg, regmatch.startp[i], len + 1);
}
- STRLCPY(fields->errmsg, regmatch.startp[i], len + 1);
- }
- if ((i = (int)fmt_ptr->addr[6]) > 0) { // %r
- if (regmatch.startp[i] == NULL) {
- continue;
+ if ((i = (int)fmt_ptr->addr[6]) > 0) { /* %r */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ tail = regmatch.startp[i];
}
- tail = regmatch.startp[i];
- }
- if ((i = (int)fmt_ptr->addr[7]) > 0) { // %p
- char_u *match_ptr;
+ if ((i = (int)fmt_ptr->addr[7]) > 0) { /* %p */
+ char_u *match_ptr;
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
- continue;
- }
- fields->col = 0;
- for (match_ptr = regmatch.startp[i];
- match_ptr != regmatch.endp[i]; match_ptr++) {
- fields->col++;
- if (*match_ptr == TAB) {
- fields->col += 7;
- fields->col -= fields->col % 8;
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
+ continue;
+ col = 0;
+ for (match_ptr = regmatch.startp[i];
+ match_ptr != regmatch.endp[i]; ++match_ptr) {
+ ++col;
+ if (*match_ptr == TAB) {
+ col += 7;
+ col -= col % 8;
+ }
}
+ col++;
+ use_viscol = true;
}
- fields->col++;
- fields->use_viscol = true;
- }
- if ((i = (int)fmt_ptr->addr[8]) > 0) { // %v
- if (regmatch.startp[i] == NULL) {
- continue;
- }
- fields->col = (int)atol((char *)regmatch.startp[i]);
- fields->use_viscol = true;
- }
- if ((i = (int)fmt_ptr->addr[9]) > 0) { // %s
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
- continue;
- }
- len = (size_t)(regmatch.endp[i] - regmatch.startp[i]);
- if (len > CMDBUFFSIZE - 5) {
- len = CMDBUFFSIZE - 5;
- }
- STRCPY(fields->pattern, "^\\V");
- xstrlcat((char *)fields->pattern, (char *)regmatch.startp[i],
- CMDBUFFSIZE+1);
- fields->pattern[len + 3] = '\\';
- fields->pattern[len + 4] = '$';
- fields->pattern[len + 5] = NUL;
- }
- break;
- }
- }
- qi->qf_multiscan = false;
-
- if (fmt_ptr == NULL || idx == 'D' || idx == 'X') {
- if (fmt_ptr != NULL) {
- if (idx == 'D') { // enter directory
- if (*fields->namebuf == NUL) {
- EMSG(_("E379: Missing or empty directory name"));
- return QF_FAIL;
+ if ((i = (int)fmt_ptr->addr[8]) > 0) { /* %v */
+ if (regmatch.startp[i] == NULL)
+ continue;
+ col = (int)atol((char *)regmatch.startp[i]);
+ use_viscol = true;
}
- qi->qf_directory = qf_push_dir(fields->namebuf, &qi->qf_dir_stack,
- false);
- if (qi->qf_directory == NULL) {
- return QF_FAIL;
+ if ((i = (int)fmt_ptr->addr[9]) > 0) { /* %s */
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
+ continue;
+ len = (int)(regmatch.endp[i] - regmatch.startp[i]);
+ if (len > CMDBUFFSIZE - 5)
+ len = CMDBUFFSIZE - 5;
+ STRCPY(pattern, "^\\V");
+ STRNCAT(pattern, regmatch.startp[i], len);
+ pattern[len + 3] = '\\';
+ pattern[len + 4] = '$';
+ pattern[len + 5] = NUL;
}
- } else if (idx == 'X') { // leave directory
- qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack);
+ break;
}
}
- fields->namebuf[0] = NUL; // no match found, remove file name
- fields->lnum = 0; // don't jump to this line
- fields->valid = false;
- if (linelen > fields->errmsglen) {
- // linelen + null terminator
- fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
- fields->errmsglen = linelen + 1;
- }
- // copy whole line to error message
- STRLCPY(fields->errmsg, linebuf, linelen + 1);
- if (fmt_ptr == NULL) {
- qi->qf_multiline = qi->qf_multiignore = false;
- }
- } else {
- // honor %> item
- if (fmt_ptr->conthere) {
- fmt_start = fmt_ptr;
- }
+ multiscan = false;
- if (vim_strchr((char_u *)"AEWI", idx) != NULL) {
- qi->qf_multiline = true; // start of a multi-line message
- qi->qf_multiignore = false; // reset continuation
- } else if (vim_strchr((char_u *)"CZ", idx)
- != NULL) { // continuation of multi-line msg
- if (!qi->qf_multiignore) {
- qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last;
- if (qfprev == NULL) {
- return QF_FAIL;
- }
- if (*fields->errmsg && !qi->qf_multiignore) {
+ if (fmt_ptr == NULL || idx == 'D' || idx == 'X') {
+ if (fmt_ptr != NULL) {
+ if (idx == 'D') { /* enter directory */
+ if (*namebuf == NUL) {
+ EMSG(_("E379: Missing or empty directory name"));
+ goto error2;
+ }
+ if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL)
+ goto error2;
+ } else if (idx == 'X') /* leave directory */
+ directory = qf_pop_dir(&dir_stack);
+ }
+ 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 (fmt_ptr == NULL) {
+ multiline = multiignore = false;
+ }
+ } else if (fmt_ptr != NULL) {
+ /* honor %> item */
+ if (fmt_ptr->conthere)
+ fmt_start = fmt_ptr;
+
+ if (vim_strchr((char_u *)"AEWI", idx) != NULL) {
+ multiline = true; // start of a multi-line message
+ multiignore = false; // reset continuation
+ } else if (vim_strchr((char_u *)"CZ", idx)
+ != NULL) { /* continuation of multi-line msg */
+ if (qfprev == NULL)
+ goto error2;
+ if (*errmsg && !multiignore) {
size_t len = STRLEN(qfprev->qf_text);
- qfprev->qf_text = xrealloc(qfprev->qf_text,
- len + STRLEN(fields->errmsg) + 2);
+ qfprev->qf_text = xrealloc(qfprev->qf_text, len + STRLEN(errmsg) + 2);
qfprev->qf_text[len] = '\n';
- STRCPY(qfprev->qf_text + len + 1, fields->errmsg);
- }
- if (qfprev->qf_nr == -1) {
- qfprev->qf_nr = fields->enr;
- }
- if (vim_isprintc(fields->type) && !qfprev->qf_type) {
- qfprev->qf_type = fields->type; // only printable chars allowed
- }
- if (!qfprev->qf_lnum) {
- qfprev->qf_lnum = fields->lnum;
- }
- if (!qfprev->qf_col) {
- qfprev->qf_col = fields->col;
+ STRCPY(qfprev->qf_text + len + 1, errmsg);
+ }
+ if (qfprev->qf_nr == -1)
+ qfprev->qf_nr = enr;
+ if (vim_isprintc(type) && !qfprev->qf_type)
+ qfprev->qf_type = type; /* only printable chars allowed */
+ if (!qfprev->qf_lnum)
+ qfprev->qf_lnum = lnum;
+ if (!qfprev->qf_col)
+ qfprev->qf_col = col;
+ qfprev->qf_viscol = use_viscol;
+ if (!qfprev->qf_fnum)
+ qfprev->qf_fnum = qf_get_fnum(directory,
+ *namebuf
+ || directory ? namebuf : currfile
+ && valid ? currfile : 0);
+ if (idx == 'Z') {
+ multiline = multiignore = false;
}
- qfprev->qf_viscol = fields->use_viscol;
- if (!qfprev->qf_fnum) {
- qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory,
- *fields->namebuf || qi->qf_directory
- ? fields->namebuf
- : qi->qf_currfile && fields->valid
- ? qi->qf_currfile : 0);
+ line_breakcheck();
+ continue;
+ } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) {
+ // global file names
+ valid = false;
+ if (*namebuf == NUL || os_path_exists(namebuf)) {
+ if (*namebuf && idx == 'P') {
+ currfile = qf_push_dir(namebuf, &file_stack);
+ } else if (idx == 'Q') {
+ currfile = qf_pop_dir(&file_stack);
+ }
+ *namebuf = NUL;
+ if (tail && *tail) {
+ STRMOVE(IObuff, skipwhite(tail));
+ multiscan = true;
+ goto restofline;
+ }
}
}
- if (idx == 'Z') {
- qi->qf_multiline = qi->qf_multiignore = false;
- }
-
- line_breakcheck();
- return QF_IGNORE_LINE;
- } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) {
- // global file names
- fields->valid = false;
- if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) {
- if (*fields->namebuf && idx == 'P') {
- qi->qf_currfile = qf_push_dir(fields->namebuf, &qi->qf_file_stack,
- true);
- } else if (idx == 'Q') {
- qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack);
+ if (fmt_ptr->flags == '-') { // generally exclude this line
+ if (multiline) {
+ multiignore = true; // also exclude continuation lines
}
- *fields->namebuf = NUL;
- if (tail && *tail) {
- STRMOVE(IObuff, skipwhite(tail));
- qi->qf_multiscan = true;
- goto restofline;
- }
- }
- }
- if (fmt_ptr->flags == '-') { // generally exclude this line
- if (qi->qf_multiline) {
- // also exclude continuation lines
- qi->qf_multiignore = true;
+ continue;
}
- return QF_IGNORE_LINE;
- }
- }
-
- return QF_OK;
-}
-
-// Read the errorfile "efile" into memory, line by line, building the error
-// list.
-// Alternative: when "efile" is NULL read errors from buffer "buf".
-// Alternative: when "tv" is not NULL get errors from the string or list.
-// Always use 'errorformat' from "buf" if there is a local value.
-// Then "lnumfirst" and "lnumlast" specify the range of lines to use.
-// Set the title of the list to "qf_title".
-// Return -1 for error, number of errors for success.
-static int
-qf_init_ext(
- qf_info_T *qi,
- char_u *efile,
- buf_T *buf,
- typval_T *tv,
- char_u *errorformat,
- int newlist, /* TRUE: start a new error list */
- linenr_T lnumfirst, /* first line number to use */
- linenr_T lnumlast, /* last line number to use */
- char_u *qf_title
-)
-{
- qfstate_T state = { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL,
- NULL, 0, 0 };
- qffields_T fields = { NULL, NULL, 0, 0L, 0, false, NULL, 0, 0, 0 };
- qfline_T *old_last = NULL;
- bool adding = false;
- static efm_T *fmt_first = NULL;
- char_u *efm;
- static char_u *last_efm = NULL;
- int retval = -1; // default: return error flag
- int status;
-
- // Do not used the cached buffer, it may have been wiped out.
- xfree(qf_last_bufname);
- qf_last_bufname = NULL;
-
- fields.namebuf = xmalloc(CMDBUFFSIZE + 1);
- fields.errmsglen = CMDBUFFSIZE + 1;
- fields.errmsg = xmalloc(fields.errmsglen);
- fields.pattern = xmalloc(CMDBUFFSIZE + 1);
-
- if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) {
- EMSG2(_(e_openerrf), efile);
- goto qf_init_end;
- }
-
- if (newlist || qi->qf_curlist == qi->qf_listcount) {
- // make place for a new list
- qf_new_list(qi, qf_title);
- } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
- // Adding to existing list, use last entry.
- adding = true;
- old_last = qi->qf_lists[qi->qf_curlist].qf_last;
- }
-
- // Use the local value of 'errorformat' if it's set.
- if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
- efm = buf->b_p_efm;
- } else {
- efm = errorformat;
- }
-
- // If we are not adding or adding to another list: clear the state.
- if (newlist || qi->qf_curlist != qi->qf_dir_curlist) {
- qi->qf_dir_curlist = qi->qf_curlist;
- qf_clean_dir_stack(&qi->qf_dir_stack);
- qi->qf_directory = NULL;
- qf_clean_dir_stack(&qi->qf_file_stack);
- qi->qf_currfile = NULL;
- qi->qf_multiline = false;
- qi->qf_multiignore = false;
- qi->qf_multiscan = false;
- }
-
- // If the errorformat didn't change between calls, then reuse the previously
- // parsed values.
- if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) {
- // free the previously parsed data
- xfree(last_efm);
- last_efm = NULL;
- free_efm_list(&fmt_first);
-
- // parse the current 'efm'
- fmt_first = parse_efm_option(efm);
- if (fmt_first != NULL) {
- last_efm = vim_strsave(efm);
- }
- }
-
- if (fmt_first == NULL) { // nothing found
- 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;
-
- if (tv != NULL) {
- if (tv->v_type == VAR_STRING) {
- state.p_str = tv->vval.v_string;
- } else if (tv->v_type == VAR_LIST) {
- state.p_li = tv->vval.v_list->lv_first;
- }
- state.tv = tv;
- }
- state.buf = buf;
- state.buflnum = lnumfirst;
- state.lnumlast = lnumlast;
-
- /*
- * Read the lines in the error file one by one.
- * Try to recognize one of the error formats in each line.
- */
- while (!got_int) {
- // Get the next line from a file/buffer/list/string
- status = qf_get_nextline(&state);
- if (status == QF_END_OF_INPUT) { // end of input
- break;
}
- status = qf_parse_line(qi, state.linebuf, state.linelen, fmt_first,
- &fields);
- if (status == QF_FAIL) {
+ if (qf_add_entry(qi, &qfprev,
+ directory,
+ (*namebuf || directory)
+ ? namebuf
+ : ((currfile && valid) ? currfile : (char_u *)NULL),
+ 0,
+ errmsg,
+ lnum,
+ col,
+ use_viscol,
+ pattern,
+ enr,
+ type,
+ valid) == FAIL)
goto error2;
- }
- if (status == QF_IGNORE_LINE) {
- continue;
- }
-
- if (qf_add_entry(qi,
- qi->qf_directory,
- (*fields.namebuf || qi->qf_directory)
- ? fields.namebuf : ((qi->qf_currfile && fields.valid)
- ? qi->qf_currfile : (char_u *)NULL),
- 0,
- fields.errmsg,
- fields.lnum,
- fields.col,
- fields.use_viscol,
- fields.pattern,
- fields.enr,
- fields.type,
- fields.valid) == FAIL) {
- goto error2;
- }
line_breakcheck();
}
- if (state.fd == NULL || !ferror(state.fd)) {
+ if (fd == NULL || !ferror(fd)) {
if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
/* no valid entry found */
qi->qf_lists[qi->qf_curlist].qf_ptr =
@@ -1125,27 +762,31 @@ qf_init_ext(
}
/* return number of matches */
retval = qi->qf_lists[qi->qf_curlist].qf_count;
- goto qf_init_end;
+ goto qf_init_ok;
}
EMSG(_(e_readerrf));
error2:
- if (!adding) {
- qf_free(qi, qi->qf_curlist);
- qi->qf_listcount--;
- if (qi->qf_curlist > 0) {
- qi->qf_curlist--;
- }
- }
+ qf_free(qi, qi->qf_curlist);
+ qi->qf_listcount--;
+ if (qi->qf_curlist > 0)
+ --qi->qf_curlist;
+qf_init_ok:
+ if (fd != NULL)
+ fclose(fd);
+ for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) {
+ fmt_first = fmt_ptr->next;
+ vim_regfree(fmt_ptr->prog);
+ xfree(fmt_ptr);
+ }
+ qf_clean_dir_stack(&dir_stack);
+ qf_clean_dir_stack(&file_stack);
qf_init_end:
- if (state.fd != NULL) {
- fclose(state.fd);
- }
- xfree(fields.namebuf);
- xfree(fields.errmsg);
- xfree(fields.pattern);
- xfree(state.growbuf);
+ xfree(namebuf);
+ xfree(errmsg);
+ xfree(pattern);
+ xfree(fmtstr);
- qf_update_buffer(qi, old_last);
+ qf_update_buffer(qi);
return retval;
}
@@ -1228,6 +869,7 @@ void qf_free_all(win_T *wp)
/// Add an entry to the end of the list of errors.
///
/// @param qi quickfix list
+/// @param prevp nonnull pointer (to previously added entry or NULL)
/// @param dir optional directory name
/// @param fname file name or NULL
/// @param bufnum buffer number or zero
@@ -1241,24 +883,17 @@ void qf_free_all(win_T *wp)
/// @param valid valid entry
///
/// @returns OK or FAIL.
-static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
- char_u *mesg, long lnum, int col, char_u vis_col,
- char_u *pattern, int nr, char_u type, char_u valid)
+static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir,
+ char_u *fname, int bufnum, char_u *mesg, long lnum,
+ int col, char_u vis_col, char_u *pattern, int nr,
+ char_u type, char_u valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
- qfline_T **lastp; // pointer to qf_last or NULL
-
- if (bufnum != 0) {
- buf_T *buf = buflist_findnr(bufnum);
+ if (bufnum != 0)
qfp->qf_fnum = bufnum;
- if (buf != NULL) {
- buf->b_has_qf_entry |=
- (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
- }
- } else {
- qfp->qf_fnum = qf_get_fnum(qi, dir, fname);
- }
+ else
+ qfp->qf_fnum = qf_get_fnum(dir, fname);
qfp->qf_text = vim_strsave(mesg);
qfp->qf_lnum = lnum;
qfp->qf_col = col;
@@ -1271,25 +906,24 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
qfp->qf_nr = nr;
if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */
type = 0;
- qfp->qf_type = (char_u)type;
+ qfp->qf_type = type;
qfp->qf_valid = valid;
- lastp = &qi->qf_lists[qi->qf_curlist].qf_last;
if (qi->qf_lists[qi->qf_curlist].qf_count == 0) {
/* first element in the list */
qi->qf_lists[qi->qf_curlist].qf_start = qfp;
qi->qf_lists[qi->qf_curlist].qf_ptr = qfp;
qi->qf_lists[qi->qf_curlist].qf_index = 0;
- qfp->qf_prev = NULL;
+ qfp->qf_prev = qfp; // first element points to itself
} else {
- assert(*lastp);
- qfp->qf_prev = *lastp;
- (*lastp)->qf_next = qfp;
- }
- qfp->qf_next = NULL;
- qfp->qf_cleared = false;
- *lastp = qfp;
- qi->qf_lists[qi->qf_curlist].qf_count++;
+ assert(*prevp);
+ qfp->qf_prev = *prevp;
+ (*prevp)->qf_next = qfp;
+ }
+ qfp->qf_next = qfp; /* last element points to itself */
+ qfp->qf_cleared = FALSE;
+ *prevp = qfp;
+ ++qi->qf_lists[qi->qf_curlist].qf_count;
if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) {
/* first valid entry */
qi->qf_lists[qi->qf_curlist].qf_index =
@@ -1374,7 +1008,6 @@ void copy_loclist(win_T *from, win_T *to)
to_qfl->qf_count = 0;
to_qfl->qf_index = 0;
to_qfl->qf_start = NULL;
- to_qfl->qf_last = NULL;
to_qfl->qf_ptr = NULL;
if (from_qfl->qf_title != NULL)
to_qfl->qf_title = vim_strsave(from_qfl->qf_title);
@@ -1383,24 +1016,23 @@ void copy_loclist(win_T *from, win_T *to)
if (from_qfl->qf_count) {
qfline_T *from_qfp;
- qfline_T *prevp;
-
- // copy all the location entries in this list
- for (i = 0, from_qfp = from_qfl->qf_start;
- i < from_qfl->qf_count && from_qfp != NULL;
- i++, from_qfp = from_qfp->qf_next) {
- if (qf_add_entry(to->w_llist,
- NULL,
- NULL,
- 0,
- from_qfp->qf_text,
- from_qfp->qf_lnum,
- from_qfp->qf_col,
- from_qfp->qf_viscol,
- from_qfp->qf_pattern,
- from_qfp->qf_nr,
- 0,
- from_qfp->qf_valid) == FAIL) {
+ qfline_T *prevp = NULL;
+
+ /* copy all the location entries in this list */
+ for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count;
+ ++i, from_qfp = from_qfp->qf_next) {
+ if (qf_add_entry(to->w_llist, &prevp,
+ NULL,
+ NULL,
+ 0,
+ from_qfp->qf_text,
+ from_qfp->qf_lnum,
+ from_qfp->qf_col,
+ from_qfp->qf_viscol,
+ from_qfp->qf_pattern,
+ from_qfp->qf_nr,
+ 0,
+ from_qfp->qf_valid) == FAIL) {
qf_free_all(to);
return;
}
@@ -1409,12 +1041,10 @@ void copy_loclist(win_T *from, win_T *to)
* directory and file names are not supplied. So the qf_fnum
* field is copied here.
*/
- prevp = to->w_llist->qf_lists[to->w_llist->qf_curlist].qf_last;
- prevp->qf_fnum = from_qfp->qf_fnum; // file number
- prevp->qf_type = from_qfp->qf_type; // error type
- if (from_qfl->qf_ptr == from_qfp) {
- to_qfl->qf_ptr = prevp; // current location
- }
+ prevp->qf_fnum = from_qfp->qf_fnum; /* file number */
+ prevp->qf_type = from_qfp->qf_type; /* error type */
+ if (from_qfl->qf_ptr == from_qfp)
+ to_qfl->qf_ptr = prevp; /* current location */
}
}
@@ -1431,67 +1061,52 @@ void copy_loclist(win_T *from, win_T *to)
to->w_llist->qf_curlist = qi->qf_curlist; /* current list */
}
-// Get buffer number for file "directory/fname".
-// Also sets the b_has_qf_entry flag.
-static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
+/*
+ * get buffer number for file "dir.name"
+ */
+static int qf_get_fnum(char_u *directory, char_u *fname)
{
- char_u *ptr = NULL;
- char_u *bufname;
- buf_T *buf;
- if (fname == NULL || *fname == NUL) { // no file name
- return 0;
- }
-
-#ifdef BACKSLASH_IN_FILENAME
- if (directory != NULL) {
- slash_adjust(directory);
- }
- slash_adjust(fname);
-#endif
- if (directory != NULL && !vim_isAbsName(fname)) {
- ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true);
- // Here we check if the file really exists.
- // This should normally be true, but if make works without
- // "leaving directory"-messages we might have missed a
- // directory change.
- if (!os_path_exists(ptr)) {
- xfree(ptr);
- directory = qf_guess_filepath(qi, fname);
- if (directory) {
- ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true);
- } else {
- ptr = vim_strsave(fname);
- }
- }
- // Use concatenated directory name and file name.
- bufname = ptr;
- } else {
- bufname = fname;
- }
-
- if (qf_last_bufname != NULL
- && STRCMP(bufname, qf_last_bufname) == 0
- && bufref_valid(&qf_last_bufref)) {
- buf = qf_last_bufref.br_buf;
- xfree(ptr);
- } else {
- xfree(qf_last_bufname);
- buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
- qf_last_bufname = (bufname == ptr) ? bufname : vim_strsave(bufname);
- set_bufref(&qf_last_bufref, buf);
- }
- if (buf == NULL) {
+ if (fname == NULL || *fname == NUL) /* no file name */
return 0;
+ {
+ char_u *ptr;
+ int fnum;
+
+#ifdef BACKSLASH_IN_FILENAME
+ if (directory != NULL)
+ slash_adjust(directory);
+ slash_adjust(fname);
+#endif
+ if (directory != NULL && !vim_isAbsName(fname)) {
+ ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE);
+ /*
+ * Here we check if the file really exists.
+ * This should normally be true, but if make works without
+ * "leaving directory"-messages we might have missed a
+ * directory change.
+ */
+ if (!os_path_exists(ptr)) {
+ xfree(ptr);
+ directory = qf_guess_filepath(fname);
+ if (directory)
+ ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE);
+ else
+ ptr = vim_strsave(fname);
+ }
+ /* Use concatenated directory name and file name */
+ fnum = buflist_add(ptr, 0);
+ xfree(ptr);
+ return fnum;
+ }
+ return buflist_add(fname, 0);
}
- buf->b_has_qf_entry =
- (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
- return buf->b_fnum;
}
-// Push dirbuf onto the directory stack and return pointer to actual dir or
-// NULL on error.
-static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
- bool is_file_stack)
+/*
+ * push dirbuf onto the directory stack and return pointer to actual dir or
+ * NULL on error
+ */
+static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr)
{
struct dir_stack_T *ds_ptr;
@@ -1504,7 +1119,7 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
/* store directory on the stack */
if (vim_isAbsName(dirbuf)
|| (*stackptr)->next == NULL
- || (*stackptr && is_file_stack))
+ || (*stackptr && dir_stack != *stackptr))
(*stackptr)->dirname = vim_strsave(dirbuf);
else {
/* Okay we don't have an absolute path.
@@ -1606,18 +1221,17 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
* Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
* qf_guess_filepath will return NULL.
*/
-static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename)
+static char_u *qf_guess_filepath(char_u *filename)
{
struct dir_stack_T *ds_ptr;
struct dir_stack_T *ds_tmp;
char_u *fullname;
- // no dirs on the stack - there's nothing we can do
- if (qi->qf_dir_stack == NULL) {
+ /* no dirs on the stack - there's nothing we can do */
+ if (dir_stack == NULL)
return NULL;
- }
- ds_ptr = qi->qf_dir_stack->next;
+ ds_ptr = dir_stack->next;
fullname = NULL;
while (ds_ptr) {
xfree(fullname);
@@ -1632,15 +1246,16 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename)
xfree(fullname);
- // clean up all dirs we already left
- while (qi->qf_dir_stack->next != ds_ptr) {
- ds_tmp = qi->qf_dir_stack->next;
- qi->qf_dir_stack->next = qi->qf_dir_stack->next->next;
+ /* clean up all dirs we already left */
+ while (dir_stack->next != ds_ptr) {
+ ds_tmp = dir_stack->next;
+ dir_stack->next = dir_stack->next->next;
xfree(ds_tmp->dirname);
xfree(ds_tmp);
}
- return ds_ptr == NULL ? NULL : ds_ptr->dirname;
+ return ds_ptr==NULL ? NULL : ds_ptr->dirname;
+
}
/// When loading a file from the quickfix, the auto commands may modify it.
@@ -1657,7 +1272,7 @@ static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr)
// Search for the entry in the current list
for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; i++, qfp = qfp->qf_next) {
- if (qfp == NULL || qfp == qf_ptr) {
+ if (qfp == qf_ptr) {
break;
}
}
@@ -1892,7 +1507,7 @@ win_found:
* If there is only one window and it is the quickfix window, create a
* new one above the quickfix window.
*/
- if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) {
+ if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win) {
flags = WSP_ABOVE;
if (ll_ref != NULL)
flags |= WSP_NEWLOC;
@@ -2005,7 +1620,7 @@ win_found:
ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
GETF_SETMARK | GETF_SWITCH, forceit);
- if (qi != &ql_info && !win_valid_any_tab(oldwin)) {
+ if (qi != &ql_info && !win_valid(oldwin)) {
EMSG(_("E924: Current window was closed"));
is_abort = true;
opened_window = false;
@@ -2211,20 +1826,21 @@ void qf_list(exarg_T *eap)
if (qfp->qf_lnum == 0) {
IObuff[0] = NUL;
} else if (qfp->qf_col == 0) {
- vim_snprintf((char *)IObuff, IOSIZE, ":%" PRIdLINENR, qfp->qf_lnum);
+ vim_snprintf((char *)IObuff, IOSIZE, ":%" PRId64,
+ (int64_t)qfp->qf_lnum);
} else {
- vim_snprintf((char *)IObuff, IOSIZE, ":%" PRIdLINENR " col %d",
- qfp->qf_lnum, qfp->qf_col);
+ vim_snprintf((char *)IObuff, IOSIZE, ":%" PRId64 " col %d",
+ (int64_t)qfp->qf_lnum, qfp->qf_col);
}
vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s:",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
- msg_puts_attr((const char *)IObuff, hl_attr(HLF_N));
+ msg_puts_attr(IObuff, hl_attr(HLF_N));
if (qfp->qf_pattern != NULL) {
qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
- xstrlcat((char *)IObuff, ":", IOSIZE);
- msg_puts((const char *)IObuff);
+ STRCAT(IObuff, ":");
+ msg_puts(IObuff);
}
- msg_puts(" ");
+ msg_puts((char_u *)" ");
/* Remove newlines and leading whitespace from the text. For an
* unrecognized line keep the indent, the compiler may mark a word
@@ -2237,10 +1853,7 @@ void qf_list(exarg_T *eap)
}
qfp = qfp->qf_next;
- if (qfp == NULL) {
- break;
- }
- i++;
+ ++i;
os_breakcheck();
}
}
@@ -2266,31 +1879,6 @@ static void qf_fmt_text(char_u *text, char_u *buf, int bufsize)
buf[i] = NUL;
}
-static void qf_msg(qf_info_T *qi, int which, char *lead)
-{
- char *title = (char *)qi->qf_lists[which].qf_title;
- int count = qi->qf_lists[which].qf_count;
- char_u buf[IOSIZE];
-
- vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
- lead,
- which + 1,
- qi->qf_listcount,
- count);
-
- if (title != NULL) {
- size_t len = STRLEN(buf);
-
- if (len < 34) {
- memset(buf + len, ' ', 34 - len);
- buf[34] = NUL;
- }
- xstrlcat((char *)buf, title, IOSIZE);
- }
- trunc_string(buf, buf, (int)Columns - 1, IOSIZE);
- msg(buf);
-}
-
/*
* ":colder [count]": Up in the quickfix stack.
* ":cnewer [count]": Down in the quickfix stack.
@@ -2331,95 +1919,69 @@ void qf_age(exarg_T *eap)
++qi->qf_curlist;
}
}
- qf_msg(qi, qi->qf_curlist, "");
- qf_update_buffer(qi, NULL);
+ qf_msg(qi);
}
-void qf_history(exarg_T *eap)
+static void qf_msg(qf_info_T *qi)
{
- qf_info_T *qi = &ql_info;
- int i;
-
- if (eap->cmdidx == CMD_lhistory) {
- qi = GET_LOC_LIST(curwin);
- }
- if (qi == NULL || (qi->qf_listcount == 0
- && qi->qf_lists[qi->qf_curlist].qf_count == 0)) {
- MSG(_("No entries"));
- } else {
- for (i = 0; i < qi->qf_listcount; i++) {
- qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
- }
- }
+ smsg(_("error list %d of %d; %d errors"),
+ qi->qf_curlist + 1, qi->qf_listcount,
+ qi->qf_lists[qi->qf_curlist].qf_count);
+ qf_update_buffer(qi);
}
-/// Free all the entries in the error list "idx".
+/*
+ * Free error list "idx".
+ */
static void qf_free(qf_info_T *qi, int idx)
{
qfline_T *qfp;
- qfline_T *qfpnext;
- bool stop = false;
+ int stop = FALSE;
- while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) {
- qfp = qi->qf_lists[idx].qf_start;
- qfpnext = qfp->qf_next;
+ while (qi->qf_lists[idx].qf_count) {
+ qfp = qi->qf_lists[idx].qf_start->qf_next;
if (qi->qf_lists[idx].qf_title != NULL && !stop) {
- xfree(qfp->qf_text);
- stop = (qfp == qfpnext);
- xfree(qfp->qf_pattern);
- xfree(qfp);
- if (stop) {
- // Somehow qf_count may have an incorrect value, set it to 1
- // to avoid crashing when it's wrong.
- // TODO(vim): Avoid qf_count being incorrect.
+ xfree(qi->qf_lists[idx].qf_start->qf_text);
+ stop = (qi->qf_lists[idx].qf_start == qfp);
+ xfree(qi->qf_lists[idx].qf_start->qf_pattern);
+ xfree(qi->qf_lists[idx].qf_start);
+ if (stop)
+ /* Somehow qf_count may have an incorrect value, set it to 1
+ * to avoid crashing when it's wrong.
+ * TODO: Avoid qf_count being incorrect. */
qi->qf_lists[idx].qf_count = 1;
- }
}
- qi->qf_lists[idx].qf_start = qfpnext;
- qi->qf_lists[idx].qf_count--;
+ qi->qf_lists[idx].qf_start = qfp;
+ --qi->qf_lists[idx].qf_count;
}
xfree(qi->qf_lists[idx].qf_title);
qi->qf_lists[idx].qf_start = NULL;
qi->qf_lists[idx].qf_ptr = NULL;
qi->qf_lists[idx].qf_title = NULL;
qi->qf_lists[idx].qf_index = 0;
-
- qf_clean_dir_stack(&qi->qf_dir_stack);
- qi->qf_directory = NULL;
- qf_clean_dir_stack(&qi->qf_file_stack);
- qi->qf_currfile = NULL;
}
/*
* qf_mark_adjust: adjust marks
*/
-bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount,
- long amount_after)
+void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after)
{
int i;
qfline_T *qfp;
int idx;
qf_info_T *qi = &ql_info;
- bool found_one = false;
- int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
- if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
- return false;
- }
if (wp != NULL) {
- if (wp->w_llist == NULL) {
- return false;
- }
+ if (wp->w_llist == NULL)
+ return;
qi = wp->w_llist;
}
for (idx = 0; idx < qi->qf_listcount; ++idx)
if (qi->qf_lists[idx].qf_count)
for (i = 0, qfp = qi->qf_lists[idx].qf_start;
- i < qi->qf_lists[idx].qf_count && qfp != NULL;
- i++, qfp = qfp->qf_next) {
+ i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
if (qfp->qf_fnum == curbuf->b_fnum) {
- found_one = true;
if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) {
if (amount == MAXLNUM)
qfp->qf_cleared = TRUE;
@@ -2428,9 +1990,6 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount,
} else if (amount_after && qfp->qf_lnum > line2)
qfp->qf_lnum += amount_after;
}
- }
-
- return found_one;
}
/*
@@ -2611,13 +2170,15 @@ void ex_copen(exarg_T *eap)
else {
/* Create a new quickfix buffer */
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
- // Switch off 'swapfile'.
- set_option_value("swf", 0L, NULL, OPT_LOCAL);
- set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
- set_option_value("bh", 0L, "wipe", OPT_LOCAL);
+ /* switch off 'swapfile' */
+ set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
+ set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
+ OPT_LOCAL);
+ set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
RESET_BINDING(curwin);
- curwin->w_p_diff = false;
- set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+ curwin->w_p_diff = FALSE;
+ set_option_value((char_u *)"fdm", 0L, (char_u *)"manual",
+ OPT_LOCAL);
}
/* Only set the height when still in the same tab page and there is no
@@ -2634,7 +2195,7 @@ void ex_copen(exarg_T *eap)
qf_set_title_var(qi);
// Fill the buffer with the quickfix list.
- qf_fill_buffer(qi, curbuf, NULL);
+ qf_fill_buffer(qi);
curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index;
curwin->w_cursor.col = 0;
@@ -2642,44 +2203,6 @@ void ex_copen(exarg_T *eap)
update_topline(); /* scroll to show the line */
}
-// Move the cursor in the quickfix window to "lnum".
-static void qf_win_goto(win_T *win, linenr_T lnum)
-{
- win_T *old_curwin = curwin;
-
- curwin = win;
- curbuf = win->w_buffer;
- curwin->w_cursor.lnum = lnum;
- curwin->w_cursor.col = 0;
- curwin->w_cursor.coladd = 0;
- curwin->w_curswant = 0;
- update_topline(); // scroll to show the line
- redraw_later(VALID);
- curwin->w_redr_status = true; // update ruler
- curwin = old_curwin;
- curbuf = curwin->w_buffer;
-}
-
-// :cbottom/:lbottom command.
-void ex_cbottom(exarg_T *eap)
-{
- qf_info_T *qi = &ql_info;
-
- if (eap->cmdidx == CMD_lbottom) {
- qi = GET_LOC_LIST(curwin);
- if (qi == NULL) {
- EMSG(_(e_loclist));
- return;
- }
- }
-
- win_T *win = qf_find_win(qi);
-
- if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count) {
- qf_win_goto(win, win->w_buffer->b_ml.ml_line_count);
- }
-}
-
/*
* Return the number of the current entry (line number in the quickfix
* window).
@@ -2716,14 +2239,24 @@ qf_win_pos_update (
if (win != NULL
&& qf_index <= win->w_buffer->b_ml.ml_line_count
&& old_qf_index != qf_index) {
+ win_T *old_curwin = curwin;
+
+ curwin = win;
+ curbuf = win->w_buffer;
if (qf_index > old_qf_index) {
- win->w_redraw_top = old_qf_index;
- win->w_redraw_bot = qf_index;
+ curwin->w_redraw_top = old_qf_index;
+ curwin->w_redraw_bot = qf_index;
} else {
- win->w_redraw_top = qf_index;
- win->w_redraw_bot = old_qf_index;
+ curwin->w_redraw_top = qf_index;
+ curwin->w_redraw_bot = old_qf_index;
}
- qf_win_goto(win, qf_index);
+ curwin->w_cursor.lnum = qf_index;
+ curwin->w_cursor.col = 0;
+ update_topline(); /* scroll to show the line */
+ redraw_later(VALID);
+ curwin->w_redr_status = TRUE; /* update ruler */
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
}
return win != NULL;
}
@@ -2778,54 +2311,34 @@ static buf_T *qf_find_buf(qf_info_T *qi)
return NULL;
}
-/// Update the w:quickfix_title variable in the quickfix/location list window
-static void qf_update_win_titlevar(qf_info_T *qi)
-{
- win_T *win;
-
- if ((win = qf_find_win(qi)) != NULL) {
- win_T *curwin_save = curwin;
- curwin = win;
- qf_set_title_var(qi);
- curwin = curwin_save;
- }
-}
-
/*
* Find the quickfix buffer. If it exists, update the contents.
*/
-static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
+static void qf_update_buffer(qf_info_T *qi)
{
buf_T *buf;
win_T *win;
+ win_T *curwin_save;
aco_save_T aco;
/* Check if a buffer for the quickfix list exists. Update it. */
buf = qf_find_buf(qi);
if (buf != NULL) {
- linenr_T old_line_count = buf->b_ml.ml_line_count;
+ /* set curwin/curbuf to buf and save a few things */
+ aucmd_prepbuf(&aco, buf);
- if (old_last == NULL) {
- // set curwin/curbuf to buf and save a few things
- aucmd_prepbuf(&aco, buf);
+ if ((win = qf_find_win(qi)) != NULL) {
+ curwin_save = curwin;
+ curwin = win;
+ qf_set_title_var(qi);
+ curwin = curwin_save;
}
+ qf_fill_buffer(qi);
- qf_update_win_titlevar(qi);
-
- qf_fill_buffer(qi, buf, old_last);
-
- if (old_last == NULL) {
- (void)qf_win_pos_update(qi, 0);
-
- // restore curwin/curbuf and a few other things
- aucmd_restbuf(&aco);
- }
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
- // Only redraw when added lines are visible. This avoids flickering when
- // the added lines are not visible.
- if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) {
- redraw_buf_later(buf, NOT_VALID);
- }
+ (void)qf_win_pos_update(qi, 0);
}
}
@@ -2838,12 +2351,11 @@ static void qf_set_title_var(qf_info_T *qi)
}
}
-// Fill current buffer with quickfix errors, replacing any previous contents.
-// curbuf must be the quickfix buffer!
-// If "old_last" is not NULL append the items after this one.
-// When "old_last" is NULL then "buf" must equal "curbuf"! Because ml_delete()
-// is used and autocommands will be triggered.
-static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
+/*
+ * Fill current buffer with quickfix errors, replacing any previous contents.
+ * curbuf must be the quickfix buffer!
+ */
+static void qf_fill_buffer(qf_info_T *qi)
{
linenr_T lnum;
qfline_T *qfp;
@@ -2851,29 +2363,15 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
int len;
int old_KeyTyped = KeyTyped;
- if (old_last == NULL) {
- if (buf != curbuf) {
- EMSG2(_(e_intern2), "qf_fill_buffer()");
- return;
- }
-
- // delete all existing lines
- while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) {
- (void)ml_delete((linenr_T)1, false);
- }
- }
+ /* delete all existing lines */
+ while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
+ (void)ml_delete((linenr_T)1, FALSE);
/* Check if there is anything to display */
if (qi->qf_curlist < qi->qf_listcount) {
- // Add one line for each error
- if (old_last == NULL) {
- qfp = qi->qf_lists[qi->qf_curlist].qf_start;
- lnum = 0;
- } else {
- qfp = old_last->qf_next;
- lnum = buf->b_ml.ml_line_count;
- }
- while (lnum < qi->qf_lists[qi->qf_curlist].qf_count) {
+ /* Add one line for each error */
+ qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+ for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum) {
if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
@@ -2913,42 +2411,33 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
IObuff + len, IOSIZE - len);
- if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, false)
- == FAIL) {
+ if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE)
+ == FAIL)
break;
- }
- lnum++;
qfp = qfp->qf_next;
- if (qfp == NULL) {
- break;
- }
- }
- if (old_last == NULL) {
- // Delete the empty line which is now at the end
- (void)ml_delete(lnum + 1, false);
}
+ /* Delete the empty line which is now at the end */
+ (void)ml_delete(lnum + 1, FALSE);
}
- // Correct cursor position.
- check_lnums(true);
-
- if (old_last == NULL) {
- // Set the 'filetype' to "qf" each time after filling the buffer. This
- // resembles reading a file into a buffer, it's more logical when using
- // autocommands.
- set_option_value("ft", 0L, "qf", OPT_LOCAL);
- curbuf->b_p_ma = false;
-
- keep_filetype = true; // don't detect 'filetype'
- apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
- false, curbuf);
- apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
- false, curbuf);
- keep_filetype = false;
-
- // make sure it will be redrawn
- redraw_curbuf_later(NOT_VALID);
- }
+ /* correct cursor position */
+ check_lnums(TRUE);
+
+ /* Set the 'filetype' to "qf" each time after filling the buffer. This
+ * resembles reading a file into a buffer, it's more logical when using
+ * autocommands. */
+ set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
+ curbuf->b_p_ma = FALSE;
+
+ keep_filetype = TRUE; /* don't detect 'filetype' */
+ apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
+ FALSE, curbuf);
+ apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
+ FALSE, curbuf);
+ keep_filetype = FALSE;
+
+ /* make sure it will be redrawn */
+ redraw_curbuf_later(NOT_VALID);
/* Restore KeyTyped, setting 'filetype' may reset it. */
KeyTyped = old_KeyTyped;
@@ -3040,11 +2529,11 @@ void ex_make(exarg_T *eap)
case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break;
default: break;
}
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
- curbuf->b_fname, true, curbuf)) {
- if (aborting()) {
+ if (au_name != NULL) {
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (did_throw || force_abort)
return;
- }
}
if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep
@@ -3141,7 +2630,7 @@ static char_u *get_mef_name(void)
STRCPY(name, p_mef);
sprintf((char *)name + (p - p_mef), "%d%d", start, off);
STRCAT(name, p + 2);
- // Don't accept a symbolic link, it's a security risk.
+ // Don't accept a symbolic link, its a security risk.
FileInfo file_info;
bool file_or_link_found = os_fileinfo_link((char *)name, &file_info);
if (!file_or_link_found) {
@@ -3314,6 +2803,7 @@ void ex_cc(exarg_T *eap)
|| eap->cmdidx == CMD_lrewind
|| eap->cmdidx == CMD_lfirst
|| eap->cmdidx == CMD_llast
+ || eap->cmdidx == CMD_llast
|| eap->cmdidx == CMD_ldo
|| eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
@@ -3370,6 +2860,7 @@ void ex_cnext(exarg_T *eap)
|| eap->cmdidx == CMD_lnfile
|| eap->cmdidx == CMD_lNfile
|| eap->cmdidx == CMD_lpfile
+ || eap->cmdidx == CMD_lpfile
|| eap->cmdidx == CMD_ldo
|| eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
@@ -3472,6 +2963,7 @@ void ex_vimgrep(exarg_T *eap)
int fi;
qf_info_T *qi = &ql_info;
qfline_T *cur_qf_start;
+ qfline_T *prevp = NULL;
long lnum;
buf_T *buf;
int duplicate_name = FALSE;
@@ -3502,11 +2994,11 @@ void ex_vimgrep(exarg_T *eap)
case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break;
default: break;
}
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
- curbuf->b_fname, true, curbuf)) {
- if (aborting()) {
+ if (au_name != NULL) {
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (did_throw || force_abort)
return;
- }
}
if (eap->cmdidx == CMD_lgrep
@@ -3556,6 +3048,12 @@ void ex_vimgrep(exarg_T *eap)
|| qi->qf_curlist == qi->qf_listcount) {
// make place for a new list
qf_new_list(qi, title != NULL ? title : *eap->cmdlinep);
+ } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
+ // Adding to existing list, find last entry.
+ for (prevp = qi->qf_lists[qi->qf_curlist].qf_start;
+ prevp->qf_next != prevp;
+ prevp = prevp->qf_next) {
+ }
}
/* parse the list of arguments */
@@ -3651,25 +3149,23 @@ void ex_vimgrep(exarg_T *eap)
++lnum) {
col = 0;
while (vim_regexec_multi(&regmatch, curwin, buf, lnum,
- col, NULL) > 0) {
- // Pass the buffer number so that it gets used even for a
- // dummy buffer, unless duplicate_name is set, then the
- // buffer will be wiped out below.
- if (qf_add_entry(qi,
- NULL, // dir
- fname,
- duplicate_name ? 0 : buf->b_fnum,
- ml_get_buf(buf,
- regmatch.startpos[0].lnum + lnum, false),
- regmatch.startpos[0].lnum + lnum,
- regmatch.startpos[0].col + 1,
- false, // vis_col
- NULL, // search pattern
- 0, // nr
- 0, // type
- true) // valid
- == FAIL) {
- got_int = true;
+ col, NULL) > 0) {
+ ;
+ if (qf_add_entry(qi, &prevp,
+ NULL, /* dir */
+ fname,
+ 0,
+ ml_get_buf(buf,
+ regmatch.startpos[0].lnum + lnum, FALSE),
+ regmatch.startpos[0].lnum + lnum,
+ regmatch.startpos[0].col + 1,
+ FALSE, /* vis_col */
+ NULL, /* search pattern */
+ 0, /* nr */
+ 0, /* type */
+ TRUE /* valid */
+ ) == FAIL) {
+ got_int = TRUE;
break;
}
found_match = TRUE;
@@ -3712,23 +3208,17 @@ void ex_vimgrep(exarg_T *eap)
buf = NULL;
} else if (buf != first_match_buf || (flags & VGR_NOJUMP)) {
unload_dummy_buffer(buf, dirname_start);
- // Keeping the buffer, remove the dummy flag.
- buf->b_flags &= ~BF_DUMMY;
buf = NULL;
}
}
if (buf != NULL) {
- // Keeping the buffer, remove the dummy flag.
- buf->b_flags &= ~BF_DUMMY;
-
- // If the buffer is still loaded we need to use the
- // directory we jumped to below.
+ /* If the buffer is still loaded we need to use the
+ * directory we jumped to below. */
if (buf == first_match_buf
&& target_dir == NULL
- && STRCMP(dirname_start, dirname_now) != 0) {
+ && STRCMP(dirname_start, dirname_now) != 0)
target_dir = vim_strsave(dirname_now);
- }
/* The buffer is still loaded, the Filetype autocommands
* need to be done now, in that buffer. And the modelines
@@ -3750,7 +3240,7 @@ void ex_vimgrep(exarg_T *eap)
qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
qi->qf_lists[qi->qf_curlist].qf_index = 1;
- qf_update_buffer(qi, NULL);
+ qf_update_buffer(qi);
if (au_name != NULL)
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
@@ -3792,6 +3282,52 @@ theend:
vim_regfree(regmatch.regprog);
}
+/*
+ * Skip over the pattern argument of ":vimgrep /pat/[g][j]".
+ * Put the start of the pattern in "*s", unless "s" is NULL.
+ * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
+ * If "s" is not NULL terminate the pattern with a NUL.
+ * Return a pointer to the char just past the pattern plus flags.
+ */
+char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
+{
+ int c;
+
+ if (vim_isIDc(*p)) {
+ /* ":vimgrep pattern fname" */
+ if (s != NULL)
+ *s = p;
+ p = skiptowhite(p);
+ if (s != NULL && *p != NUL)
+ *p++ = NUL;
+ } else {
+ /* ":vimgrep /pattern/[g][j] fname" */
+ if (s != NULL)
+ *s = p + 1;
+ c = *p;
+ p = skip_regexp(p + 1, c, TRUE, NULL);
+ if (*p != c)
+ return NULL;
+
+ /* Truncate the pattern. */
+ if (s != NULL)
+ *p = NUL;
+ ++p;
+
+ /* Find the flags */
+ while (*p == 'g' || *p == 'j') {
+ if (flags != NULL) {
+ if (*p == 'g')
+ *flags |= VGR_GLOBAL;
+ else
+ *flags |= VGR_NOJUMP;
+ }
+ ++p;
+ }
+ }
+ return p;
+}
+
/*
* Restore current working directory to "dirname_start" if they differ, taking
* into account whether it is set locally or globally.
@@ -3833,9 +3369,8 @@ load_dummy_buffer (
)
{
buf_T *newbuf;
- bufref_T newbufref;
- bufref_T newbuf_to_wipe;
- int failed = true;
+ buf_T *newbuf_to_wipe = NULL;
+ int failed = TRUE;
aco_save_T aco;
// Allocate a buffer without putting it in the buffer list.
@@ -3843,7 +3378,6 @@ load_dummy_buffer (
if (newbuf == NULL) {
return NULL;
}
- set_bufref(&newbufref, newbuf);
/* Init the options. */
buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP);
@@ -3863,7 +3397,6 @@ load_dummy_buffer (
* work. */
curbuf->b_flags &= ~BF_DUMMY;
- newbuf_to_wipe.br_buf = NULL;
if (readfile(fname, NULL,
(linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
NULL, READ_NEW | READ_DUMMY) == OK
@@ -3871,24 +3404,19 @@ load_dummy_buffer (
&& !(curbuf->b_flags & BF_NEW)) {
failed = FALSE;
if (curbuf != newbuf) {
- // Bloody autocommands changed the buffer! Can happen when
- // using netrw and editing a remote file. Use the current
- // buffer instead, delete the dummy one after restoring the
- // window stuff.
- set_bufref(&newbuf_to_wipe, newbuf);
+ /* Bloody autocommands changed the buffer! Can happen when
+ * using netrw and editing a remote file. Use the current
+ * buffer instead, delete the dummy one after restoring the
+ * window stuff. */
+ newbuf_to_wipe = newbuf;
newbuf = curbuf;
}
}
- // Restore curwin/curbuf and a few other things.
+ /* restore curwin/curbuf and a few other things */
aucmd_restbuf(&aco);
- if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) {
- wipe_buffer(newbuf_to_wipe.br_buf, false);
- }
-
- // Add back the "dummy" flag, otherwise buflist_findname_file_id()
- // won't skip it.
- newbuf->b_flags |= BF_DUMMY;
+ if (newbuf_to_wipe != NULL && buf_valid(newbuf_to_wipe))
+ wipe_buffer(newbuf_to_wipe, FALSE);
}
/*
@@ -3899,9 +3427,8 @@ load_dummy_buffer (
os_dirname(resulting_dir, MAXPATHL);
restore_start_dir(dirname_start);
- if (!bufref_valid(&newbufref)) {
+ if (!buf_valid(newbuf))
return NULL;
- }
if (failed) {
wipe_dummy_buffer(newbuf, dirname_start);
return NULL;
@@ -3949,11 +3476,13 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
}
}
-/// Add each quickfix error to list "list" as a dictionary.
-/// If qf_idx is -1, use the current list. Otherwise, use the specified list.
-int get_errorlist(win_T *wp, int qf_idx, list_T *list)
+/*
+ * Add each quickfix error to list "list" as a dictionary.
+ */
+int get_errorlist(win_T *wp, list_T *list)
{
qf_info_T *qi = &ql_info;
+ dict_T *dict;
char_u buf[2];
qfline_T *qfp;
int i;
@@ -3965,154 +3494,66 @@ int get_errorlist(win_T *wp, int qf_idx, list_T *list)
return FAIL;
}
- if (qf_idx == -1) {
- qf_idx = qi->qf_curlist;
- }
-
- if (qf_idx >= qi->qf_listcount
- || qi->qf_lists[qf_idx].qf_count == 0) {
+ if (qi->qf_curlist >= qi->qf_listcount
+ || qi->qf_lists[qi->qf_curlist].qf_count == 0)
return FAIL;
- }
- qfp = qi->qf_lists[qf_idx].qf_start;
- for (i = 1; !got_int && i <= qi->qf_lists[qf_idx].qf_count; i++) {
- // Handle entries with a non-existing buffer number.
+ qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+ for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ++i) {
+ /* Handle entries with a non-existing buffer number. */
bufnum = qfp->qf_fnum;
if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
bufnum = 0;
- dict_T *const dict = tv_dict_alloc();
- tv_list_append_dict(list, dict);
+ dict = dict_alloc();
+ list_append_dict(list, dict);
buf[0] = qfp->qf_type;
buf[1] = NUL;
- if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
- || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum)
- == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col)
- == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol)
- == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL)
- || tv_dict_add_str(dict, S_LEN("pattern"),
- (qfp->qf_pattern == NULL
- ? ""
- : (const char *)qfp->qf_pattern)) == FAIL
- || tv_dict_add_str(dict, S_LEN("text"),
- (qfp->qf_text == NULL
- ? ""
- : (const char *)qfp->qf_text)) == FAIL
- || tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL
- || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid)
- == FAIL)) {
- // tv_dict_add* fail only if key already exist, but this is a newly
- // allocated dictionary which is thus guaranteed to have no existing keys.
- assert(false);
- }
+ if ( dict_add_nr_str(dict, "bufnr", (long)bufnum, NULL) == FAIL
+ || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL
+ || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL
+ || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL
+ || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL
+ || dict_add_nr_str(dict, "pattern", 0L,
+ qfp->qf_pattern == NULL ? (char_u *)"" : qfp->qf_pattern) == FAIL
+ || dict_add_nr_str(dict, "text", 0L,
+ qfp->qf_text == NULL ? (char_u *)"" : qfp->qf_text) == FAIL
+ || dict_add_nr_str(dict, "type", 0L, buf) == FAIL
+ || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL)
+ return FAIL;
qfp = qfp->qf_next;
- if (qfp == NULL) {
- break;
- }
}
return OK;
}
-/// Flags used by getqflist()/getloclist() to determine which fields to return.
-enum {
- QF_GETLIST_NONE = 0x0,
- QF_GETLIST_TITLE = 0x1,
- QF_GETLIST_ITEMS = 0x2,
- QF_GETLIST_NR = 0x4,
- QF_GETLIST_WINID = 0x8,
- QF_GETLIST_ALL = 0xFF
-};
-
-/// Return quickfix/location list details (title) as a
-/// dictionary. 'what' contains the details to return. If 'list_idx' is -1,
-/// then current list is used. Otherwise the specified list is used.
-int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
-{
- qf_info_T *qi = &ql_info;
-
- if (wp != NULL) {
- qi = GET_LOC_LIST(wp);
- if (qi == NULL) {
- return FAIL;
- }
- }
-
- int status = OK;
- dictitem_T *di;
- int flags = QF_GETLIST_NONE;
-
- int qf_idx = qi->qf_curlist; // default is the current list
- if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
- // Use the specified quickfix/location list
- if (di->di_tv.v_type == VAR_NUMBER) {
- // for zero use the current list
- if (di->di_tv.vval.v_number != 0) {
- qf_idx = (int)di->di_tv.vval.v_number - 1;
- if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
- return FAIL;
- }
- }
- flags |= QF_GETLIST_NR;
- } else {
- return FAIL;
- }
- }
-
- if (tv_dict_find(what, S_LEN("all")) != NULL) {
- flags |= QF_GETLIST_ALL;
- }
-
- if (tv_dict_find(what, S_LEN("title")) != NULL) {
- flags |= QF_GETLIST_TITLE;
- }
-
- if (tv_dict_find(what, S_LEN("winid")) != NULL) {
- flags |= QF_GETLIST_WINID;
- }
-
- if (flags & QF_GETLIST_TITLE) {
- char_u *t = qi->qf_lists[qf_idx].qf_title;
- if (t == NULL) {
- t = (char_u *)"";
- }
- status = tv_dict_add_str(retdict, S_LEN("title"), (const char *)t);
- }
- if ((status == OK) && (flags & QF_GETLIST_NR)) {
- status = tv_dict_add_nr(retdict, S_LEN("nr"), qf_idx + 1);
- }
- if ((status == OK) && (flags & QF_GETLIST_WINID)) {
- win_T *win = qf_find_win(qi);
- if (win != NULL) {
- status = tv_dict_add_nr(retdict, S_LEN("winid"), win->handle);
- }
- }
-
- return status;
-}
-
-/// Add list of entries to quickfix/location list. Each list entry is
-/// a dictionary with item information.
-static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
- int action)
+/*
+ * Populate the quickfix list with the items supplied in the list
+ * of dictionaries. "title" will be copied to w:quickfix_title
+ */
+int set_errorlist(win_T *wp, list_T *list, int action, char_u *title)
{
listitem_T *li;
dict_T *d;
- qfline_T *old_last = NULL;
+ qfline_T *prevp = NULL;
int retval = OK;
+ qf_info_T *qi = &ql_info;
bool did_bufnr_emsg = false;
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
- // make place for a new list
+ if (wp != NULL) {
+ qi = ll_get_or_alloc_list(wp);
+ }
+
+ if (action == ' ' || qi->qf_curlist == qi->qf_listcount)
+ /* make place for a new list */
qf_new_list(qi, title);
- } else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) {
- // Adding to existing list, use last entry.
- old_last = qi->qf_lists[qi->qf_curlist].qf_last;
- } else if (action == 'r') {
+ else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0)
+ /* Adding to existing list, find last entry. */
+ for (prevp = qi->qf_lists[qi->qf_curlist].qf_start;
+ prevp->qf_next != prevp; prevp = prevp->qf_next)
+ ;
+ else if (action == 'r') {
qf_free(qi, qi->qf_curlist);
qf_store_title(qi, title);
}
@@ -4125,18 +3566,17 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
if (d == NULL)
continue;
- char *const filename = tv_dict_get_string(d, "filename", true);
- int bufnum = (int)tv_dict_get_number(d, "bufnr");
- long lnum = (long)tv_dict_get_number(d, "lnum");
- int col = (int)tv_dict_get_number(d, "col");
- char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
- int nr = (int)tv_dict_get_number(d, "nr");
- const char *type_str = tv_dict_get_string(d, "type", false);
- const char_u type = (char_u)(uint8_t)(type_str == NULL ? NUL : *type_str);
- char *const pattern = tv_dict_get_string(d, "pattern", true);
- char *text = tv_dict_get_string(d, "text", true);
+ char_u *filename = get_dict_string(d, "filename", true);
+ int bufnum = (int)get_dict_number(d, "bufnr");
+ long lnum = get_dict_number(d, "lnum");
+ int col = (int)get_dict_number(d, "col");
+ char_u vcol = (char_u)get_dict_number(d, "vcol");
+ int nr = (int)get_dict_number(d, "nr");
+ char_u *type = get_dict_string(d, "type", true);
+ char_u *pattern = get_dict_string(d, "pattern", true);
+ char_u *text = get_dict_string(d, "text", true);
if (text == NULL) {
- text = xcalloc(1, 1);
+ text = vim_strsave((char_u *)"");
}
bool valid = true;
if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) {
@@ -4155,21 +3595,23 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
}
int status = qf_add_entry(qi,
+ &prevp,
NULL, // dir
- (char_u *)filename,
+ filename,
bufnum,
- (char_u *)text,
+ text,
lnum,
col,
vcol, // vis_col
- (char_u *)pattern, // search pattern
+ pattern, // search pattern
nr,
- type,
+ (char_u)(type == NULL ? NUL : *type),
valid);
xfree(filename);
xfree(pattern);
xfree(text);
+ xfree(type);
if (status == FAIL) {
retval = FAIL;
@@ -4177,86 +3619,17 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
}
}
- if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
- // no valid entry
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = true;
- } else {
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = false;
- }
- if (action != 'a') {
- qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
- if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
- qi->qf_lists[qi->qf_curlist].qf_index = 1;
- }
- }
-
- // Don't update the cursor in quickfix window when appending entries
- qf_update_buffer(qi, old_last);
-
- return retval;
-}
-
-static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
-{
- dictitem_T *di;
- int retval = FAIL;
- int newlist = false;
-
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
- newlist = true;
- }
- int qf_idx = qi->qf_curlist; // default is the current list
- if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
- // Use the specified quickfix/location list
- if (di->di_tv.v_type == VAR_NUMBER) {
- qf_idx = (int)di->di_tv.vval.v_number - 1;
- if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
- return FAIL;
- }
- } else {
- return FAIL;
- }
- newlist = false; // use the specified list
- }
-
- if (newlist) {
- qf_new_list(qi, NULL);
- qf_idx = qi->qf_curlist;
- }
-
- if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) {
- if (di->di_tv.v_type == VAR_STRING) {
- xfree(qi->qf_lists[qf_idx].qf_title);
- qi->qf_lists[qf_idx].qf_title = (char_u *)tv_dict_get_string(
- what, "title", true);
- if (qf_idx == qi->qf_curlist) {
- qf_update_win_titlevar(qi);
- }
- retval = OK;
- }
- }
-
- return retval;
-}
-
-// Populate the quickfix list with the items supplied in the list
-// of dictionaries. "title" will be copied to w:quickfix_title
-// "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
-int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
- dict_T *what)
-{
- qf_info_T *qi = &ql_info;
- int retval = OK;
-
- if (wp != NULL) {
- qi = ll_get_or_alloc_list(wp);
+ if (qi->qf_lists[qi->qf_curlist].qf_index == 0)
+ /* no valid entry */
+ qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE;
+ else
+ qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
+ qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
+ if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
+ qi->qf_lists[qi->qf_curlist].qf_index = 1;
}
- if (what != NULL) {
- retval = qf_set_properties(qi, what, action);
- } else {
- retval = qf_add_entries(qi, list, title, action);
- }
+ qf_update_buffer(qi);
return retval;
}
@@ -4271,45 +3644,14 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
*/
void ex_cbuffer(exarg_T *eap)
{
- buf_T *buf = NULL;
- qf_info_T *qi = &ql_info;
- const char *au_name = NULL;
+ buf_T *buf = NULL;
+ qf_info_T *qi = &ql_info;
if (eap->cmdidx == CMD_lbuffer || eap->cmdidx == CMD_lgetbuffer
|| eap->cmdidx == CMD_laddbuffer) {
qi = ll_get_or_alloc_list(curwin);
}
- switch (eap->cmdidx) {
- case CMD_cbuffer:
- au_name = "cbuffer";
- break;
- case CMD_cgetbuffer:
- au_name = "cgetbuffer";
- break;
- case CMD_caddbuffer:
- au_name = "caddbuffer";
- break;
- case CMD_lbuffer:
- au_name = "lbuffer";
- break;
- case CMD_lgetbuffer:
- au_name = "lgetbuffer";
- break;
- case CMD_laddbuffer:
- au_name = "laddbuffer";
- break;
- default:
- break;
- }
-
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name,
- curbuf->b_fname, true, curbuf)) {
- if (aborting()) {
- return;
- }
- }
-
if (*eap->arg == NUL)
buf = curbuf;
else if (*skipwhite(skipdigits(eap->arg)) == NUL)
@@ -4336,17 +3678,13 @@ void ex_cbuffer(exarg_T *eap)
}
if (qf_init_ext(qi, NULL, buf, NULL, p_efm,
- (eap->cmdidx != CMD_caddbuffer
- && eap->cmdidx != CMD_laddbuffer),
- eap->line1, eap->line2, qf_title) > 0) {
- if (au_name != NULL) {
- apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name,
- curbuf->b_fname, true, curbuf);
- }
- if (eap->cmdidx == CMD_cbuffer || eap->cmdidx == CMD_lbuffer) {
- qf_jump(qi, 0, 0, eap->forceit); // display first error
- }
- }
+ (eap->cmdidx != CMD_caddbuffer
+ && eap->cmdidx != CMD_laddbuffer),
+ eap->line1, eap->line2,
+ qf_title) > 0
+ && (eap->cmdidx == CMD_cbuffer
+ || eap->cmdidx == CMD_lbuffer))
+ qf_jump(qi, 0, 0, eap->forceit); /* display first error */
}
}
}
@@ -4357,65 +3695,30 @@ void ex_cbuffer(exarg_T *eap)
*/
void ex_cexpr(exarg_T *eap)
{
- qf_info_T *qi = &ql_info;
- const char *au_name = NULL;
+ typval_T *tv;
+ qf_info_T *qi = &ql_info;
if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_lgetexpr
|| eap->cmdidx == CMD_laddexpr) {
qi = ll_get_or_alloc_list(curwin);
}
- switch (eap->cmdidx) {
- case CMD_cexpr:
- au_name = "cexpr";
- break;
- case CMD_cgetexpr:
- au_name = "cgetexpr";
- break;
- case CMD_caddexpr:
- au_name = "caddexpr";
- break;
- case CMD_lexpr:
- au_name = "lexpr";
- break;
- case CMD_lgetexpr:
- au_name = "lgetexpr";
- break;
- case CMD_laddexpr:
- au_name = "laddexpr";
- break;
- default:
- break;
- }
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name,
- curbuf->b_fname, true, curbuf)) {
- if (aborting()) {
- return;
- }
- }
-
/* Evaluate the expression. When the result is a string or a list we can
* use it to fill the errorlist. */
- typval_T tv;
- if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
- if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
- || (tv.v_type == VAR_LIST && tv.vval.v_list != NULL)) {
- if (qf_init_ext(qi, NULL, NULL, &tv, p_efm,
- (eap->cmdidx != CMD_caddexpr
- && eap->cmdidx != CMD_laddexpr),
- (linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0) {
- if (au_name != NULL) {
- apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name,
- curbuf->b_fname, true, curbuf);
- }
- if (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) {
- qf_jump(qi, 0, 0, eap->forceit); // display first error
- }
- }
- } else {
+ tv = eval_expr(eap->arg, NULL);
+ if (tv != NULL) {
+ if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
+ || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL)) {
+ if (qf_init_ext(qi, NULL, NULL, tv, p_efm,
+ (eap->cmdidx != CMD_caddexpr
+ && eap->cmdidx != CMD_laddexpr),
+ (linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0
+ && (eap->cmdidx == CMD_cexpr
+ || eap->cmdidx == CMD_lexpr))
+ qf_jump(qi, 0, 0, eap->forceit); /* display first error */
+ } else
EMSG(_("E777: String or List expected"));
- }
- tv_clear(&tv);
+ free_tv(tv);
}
}
@@ -4431,6 +3734,7 @@ void ex_helpgrep(exarg_T *eap)
char_u **fnames;
FILE *fd;
int fi;
+ qfline_T *prevp = NULL;
long lnum;
char_u *lang;
qf_info_T *qi = &ql_info;
@@ -4445,11 +3749,11 @@ void ex_helpgrep(exarg_T *eap)
case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
default: break;
}
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
- curbuf->b_fname, true, curbuf)) {
- if (aborting()) {
+ if (au_name != NULL) {
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (did_throw || force_abort)
return;
- }
}
/* Make 'cpoptions' empty, the 'l' flag should not be used here. */
@@ -4533,24 +3837,23 @@ void ex_helpgrep(exarg_T *eap)
while (l > 0 && line[l - 1] <= ' ')
line[--l] = NUL;
- if (qf_add_entry(qi,
- NULL, // dir
- fnames[fi],
- 0,
- line,
- lnum,
- (int)(regmatch.startp[0] - line)
- + 1, // col
- false, // vis_col
- NULL, // search pattern
- 0, // nr
- 1, // type
- true) // valid
- == FAIL) {
- got_int = true;
- if (line != IObuff) {
+ if (qf_add_entry(qi, &prevp,
+ NULL, /* dir */
+ fnames[fi],
+ 0,
+ line,
+ lnum,
+ (int)(regmatch.startp[0] - line)
+ + 1, /* col */
+ FALSE, /* vis_col */
+ NULL, /* search pattern */
+ 0, /* nr */
+ 1, /* type */
+ TRUE /* valid */
+ ) == FAIL) {
+ got_int = TRUE;
+ if (line != IObuff)
xfree(line);
- }
break;
}
}
@@ -4582,7 +3885,7 @@ void ex_helpgrep(exarg_T *eap)
/* Darn, some plugin changed the value. */
free_string_option(save_cpo);
- qf_update_buffer(qi, NULL);
+ qf_update_buffer(qi);
if (au_name != NULL) {
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment