summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.0252
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.0252')
-rw-r--r--data/vim/patches/8.1.02521540
1 files changed, 1540 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0252 b/data/vim/patches/8.1.0252
new file mode 100644
index 000000000..f72f55a0d
--- /dev/null
+++ b/data/vim/patches/8.1.0252
@@ -0,0 +1,1540 @@
+To: vim_dev@googlegroups.com
+Subject: Patch 8.1.0252
+Fcc: outbox
+From: Bram Moolenaar <Bram@moolenaar.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+------------
+
+Patch 8.1.0252
+Problem: Quickfix functions are too long.
+Solution: Refactor. (Yegappan Lakshmanan, closes #2950)
+Files: src/quickfix.c
+
+
+*** ../vim-8.1.0251/src/quickfix.c 2018-08-07 19:47:46.746434541 +0200
+--- src/quickfix.c 2018-08-07 21:52:51.654369210 +0200
+***************
+*** 201,306 ****
+
+ /*
+ * Convert an errorformat pattern to a regular expression pattern.
+! * See fmt_pat definition above for the list of supported patterns.
+ */
+ static char_u *
+! fmtpat_to_regpat(
+! char_u *efmp,
+! efm_T *fmt_ptr,
+ int idx,
+ int round,
+- char_u *ptr,
+ char_u *errmsg)
+ {
+ char_u *srcptr;
+
+! if (fmt_ptr->addr[idx])
+ {
+ /* Each errorformat pattern can occur only once */
+ sprintf((char *)errmsg,
+! _("E372: Too many %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ return NULL;
+ }
+ 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);
+ return NULL;
+ }
+! 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;
+ }
+ }
+ else
+ {
+ srcptr = (char_u *)fmt_pat[idx].pattern;
+! while ((*ptr = *srcptr++) != NUL)
+! ++ptr;
+ }
+! *ptr++ = '\\';
+! *ptr++ = ')';
+
+! return ptr;
+ }
+
+ /*
+ * Convert a scanf like format in 'errorformat' to a regular expression.
+ */
+ static char_u *
+ scanf_fmt_to_regpat(
+ char_u *efm,
+ int len,
+! char_u **pefmp,
+! char_u *ptr,
+ char_u *errmsg)
+ {
+ char_u *efmp = *pefmp;
+
+! 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)
+ {
+--- 201,309 ----
+
+ /*
+ * Convert an errorformat pattern to a regular expression pattern.
+! * See fmt_pat definition above for the list of supported patterns. The
+! * pattern specifier is supplied in "efmpat". The converted pattern is stored
+! * in "regpat". Returns a pointer to the location after the pattern.
+ */
+ static char_u *
+! efmpat_to_regpat(
+! char_u *efmpat,
+! char_u *regpat,
+! efm_T *efminfo,
+ int idx,
+ int round,
+ char_u *errmsg)
+ {
+ char_u *srcptr;
+
+! if (efminfo->addr[idx])
+ {
+ /* Each errorformat pattern can occur only once */
+ sprintf((char *)errmsg,
+! _("E372: Too many %%%c in format string"), *efmpat);
+ EMSG(errmsg);
+ return NULL;
+ }
+ if ((idx && idx < 6
+! && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
+ || (idx == 6
+! && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL))
+ {
+ sprintf((char *)errmsg,
+! _("E373: Unexpected %%%c in format string"), *efmpat);
+ EMSG(errmsg);
+ return NULL;
+ }
+! efminfo->addr[idx] = (char_u)++round;
+! *regpat++ = '\\';
+! *regpat++ = '(';
+ #ifdef BACKSLASH_IN_FILENAME
+! if (*efmpat == 'f')
+ {
+ /* Also match "c:" in the file name, even when
+ * checking for a colon next: "%f:".
+ * "\%(\a:\)\=" */
+! STRCPY(regpat, "\\%(\\a:\\)\\=");
+! regpat += 10;
+ }
+ #endif
+! if (*efmpat == 'f' && efmpat[1] != NUL)
+ {
+! if (efmpat[1] != '\\' && efmpat[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(regpat, ".\\{-1,}");
+! regpat += 7;
+ }
+ else
+ {
+ /* File name followed by '\\' or '%': include as
+ * many file name chars as possible. */
+! STRCPY(regpat, "\\f\\+");
+! regpat += 4;
+ }
+ }
+ else
+ {
+ srcptr = (char_u *)fmt_pat[idx].pattern;
+! while ((*regpat = *srcptr++) != NUL)
+! ++regpat;
+ }
+! *regpat++ = '\\';
+! *regpat++ = ')';
+
+! return regpat;
+ }
+
+ /*
+ * Convert a scanf like format in 'errorformat' to a regular expression.
++ * Returns a pointer to the location after the pattern.
+ */
+ static char_u *
+ scanf_fmt_to_regpat(
++ char_u **pefmp,
+ char_u *efm,
+ int len,
+! char_u *regpat,
+ char_u *errmsg)
+ {
+ char_u *efmp = *pefmp;
+
+! if (*efmp == '[' || *efmp == '\\')
+ {
+! if ((*regpat++ = *efmp) == '[') /* %*[^a-z0-9] etc. */
+ {
+ if (efmp[1] == '^')
+! *regpat++ = *++efmp;
+ if (efmp < efm + len)
+ {
+! *regpat++ = *++efmp; /* could be ']' */
+ while (efmp < efm + len
+! && (*regpat++ = *++efmp) != ']')
+ /* skip */;
+ if (efmp == efm + len)
+ {
+***************
+*** 310,318 ****
+ }
+ }
+ else if (efmp < efm + len) /* %*\D, %*\s etc. */
+! *ptr++ = *++efmp;
+! *ptr++ = '\\';
+! *ptr++ = '+';
+ }
+ else
+ {
+--- 313,321 ----
+ }
+ }
+ else if (efmp < efm + len) /* %*\D, %*\s etc. */
+! *regpat++ = *++efmp;
+! *regpat++ = '\\';
+! *regpat++ = '+';
+ }
+ else
+ {
+***************
+*** 325,360 ****
+
+ *pefmp = efmp;
+
+! return ptr;
+ }
+
+ /*
+ * Analyze/parse an errorformat prefix.
+ */
+! static int
+! efm_analyze_prefix(char_u **pefmp, efm_T *fmt_ptr, char_u *errmsg)
+ {
+- char_u *efmp = *pefmp;
+-
+ 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);
+! return FAIL;
+ }
+
+! *pefmp = efmp;
+!
+! return OK;
+ }
+
+ /*
+! * Converts a 'errorformat' string to regular expression pattern
+ */
+ static int
+ efm_to_regpat(
+--- 328,362 ----
+
+ *pefmp = efmp;
+
+! return regpat;
+ }
+
+ /*
+ * Analyze/parse an errorformat prefix.
+ */
+! static char_u *
+! efm_analyze_prefix(char_u *efmp, efm_T *efminfo, char_u *errmsg)
+ {
+ if (vim_strchr((char_u *)"+-", *efmp) != NULL)
+! efminfo->flags = *efmp++;
+ if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL)
+! efminfo->prefix = *efmp;
+ else
+ {
+ sprintf((char *)errmsg,
+ _("E376: Invalid %%%c in format string prefix"), *efmp);
+ EMSG(errmsg);
+! return NULL;
+ }
+
+! return efmp;
+ }
+
+ /*
+! * Converts a 'errorformat' string part in 'efm' to a regular expression
+! * pattern. The resulting regex pattern is returned in "regpat". Additional
+! * information about the 'erroformat' pattern is returned in "fmt_ptr".
+! * Returns OK or FAIL.
+ */
+ static int
+ efm_to_regpat(
+***************
+*** 370,376 ****
+ int idx = 0;
+
+ /*
+! * Build regexp pattern from current 'errorformat' option
+ */
+ ptr = regpat;
+ *ptr++ = '^';
+--- 372,378 ----
+ int idx = 0;
+
+ /*
+! * Build a regexp pattern for a 'errorformat' option part
+ */
+ ptr = regpat;
+ *ptr++ = '^';
+***************
+*** 385,401 ****
+ break;
+ if (idx < FMT_PATTERNS)
+ {
+! ptr = fmtpat_to_regpat(efmp, fmt_ptr, idx, round, ptr,
+ errmsg);
+ if (ptr == NULL)
+! return -1;
+ round++;
+ }
+ else if (*efmp == '*')
+ {
+! ptr = scanf_fmt_to_regpat(efm, len, &efmp, ptr, errmsg);
+ if (ptr == NULL)
+! return -1;
+ }
+ else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
+ *ptr++ = *efmp; /* regexp magic characters */
+--- 387,404 ----
+ break;
+ if (idx < FMT_PATTERNS)
+ {
+! ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round,
+ errmsg);
+ if (ptr == NULL)
+! return FAIL;
+ round++;
+ }
+ else if (*efmp == '*')
+ {
+! ++efmp;
+! ptr = scanf_fmt_to_regpat(&efmp, efm, len, ptr, errmsg);
+ if (ptr == NULL)
+! return FAIL;
+ }
+ else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
+ *ptr++ = *efmp; /* regexp magic characters */
+***************
+*** 405,419 ****
+ fmt_ptr->conthere = TRUE;
+ else if (efmp == efm + 1) /* analyse prefix */
+ {
+! if (efm_analyze_prefix(&efmp, fmt_ptr, errmsg) == FAIL)
+! return -1;
+ }
+ else
+ {
+ sprintf((char *)errmsg,
+ _("E377: Invalid %%%c in format string"), *efmp);
+ EMSG(errmsg);
+! return -1;
+ }
+ }
+ else /* copy normal character */
+--- 408,427 ----
+ fmt_ptr->conthere = TRUE;
+ else if (efmp == efm + 1) /* analyse prefix */
+ {
+! /*
+! * prefix is allowed only at the beginning of the errorformat
+! * option part
+! */
+! efmp = efm_analyze_prefix(efmp, fmt_ptr, errmsg);
+! if (efmp == NULL)
+! return FAIL;
+ }
+ else
+ {
+ sprintf((char *)errmsg,
+ _("E377: Invalid %%%c in format string"), *efmp);
+ EMSG(errmsg);
+! return FAIL;
+ }
+ }
+ else /* copy normal character */
+***************
+*** 429,437 ****
+ *ptr++ = '$';
+ *ptr = NUL;
+
+! return 0;
+ }
+
+ static void
+ free_efm_list(efm_T **efm_first)
+ {
+--- 437,448 ----
+ *ptr++ = '$';
+ *ptr = NUL;
+
+! return OK;
+ }
+
++ /*
++ * Free the 'errorformat' information list
++ */
+ static void
+ free_efm_list(efm_T **efm_first)
+ {
+***************
+*** 446,452 ****
+ fmt_start = NULL;
+ }
+
+! /* Parse 'errorformat' option */
+ static efm_T *
+ parse_efm_option(char_u *efm)
+ {
+--- 457,504 ----
+ fmt_start = NULL;
+ }
+
+! /*
+! * Compute the size of the buffer used to convert a 'errorformat' pattern into
+! * a regular expression pattern.
+! */
+! static int
+! efm_regpat_bufsz(char_u *efm)
+! {
+! int sz;
+! int i;
+!
+! sz = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
+! for (i = FMT_PATTERNS; i > 0; )
+! sz += (int)STRLEN(fmt_pat[--i].pattern);
+! #ifdef BACKSLASH_IN_FILENAME
+! sz += 12; /* "%f" can become twelve chars longer (see efm_to_regpat) */
+! #else
+! sz += 2; /* "%f" can become two chars longer */
+! #endif
+!
+! return sz;
+! }
+!
+! /*
+! * Return the length of a 'errorformat' option part (separated by ",").
+! */
+! static int
+! efm_option_part_len(char_u *efm)
+! {
+! int len;
+!
+! for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
+! if (efm[len] == '\\' && efm[len + 1] != NUL)
+! ++len;
+!
+! return len;
+! }
+!
+! /*
+! * Parse the 'errorformat' option. Multiple parts in the 'errorformat' option
+! * are parsed and converted to regular expressions. Returns information about
+! * the parsed 'errorformat' option.
+! */
+ static efm_T *
+ parse_efm_option(char_u *efm)
+ {
+***************
+*** 457,464 ****
+ efm_T *fmt_last = NULL;
+ char_u *fmtstr = NULL;
+ int len;
+! int i;
+! int round;
+
+ errmsglen = CMDBUFFSIZE + 1;
+ errmsg = alloc_id(errmsglen, aid_qf_errmsg);
+--- 509,515 ----
+ efm_T *fmt_last = NULL;
+ char_u *fmtstr = NULL;
+ int len;
+! int sz;
+
+ errmsglen = CMDBUFFSIZE + 1;
+ errmsg = alloc_id(errmsglen, aid_qf_errmsg);
+***************
+*** 473,487 ****
+ /*
+ * Get some space to modify the format string into.
+ */
+! i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
+! for (round = FMT_PATTERNS; round > 0; )
+! i += (int)STRLEN(fmt_pat[--round].pattern);
+! #ifdef BACKSLASH_IN_FILENAME
+! i += 12; /* "%f" can become twelve chars longer (see efm_to_regpat) */
+! #else
+! i += 2; /* "%f" can become two chars longer */
+! #endif
+! if ((fmtstr = alloc(i)) == NULL)
+ goto parse_efm_error;
+
+ while (efm[0] != NUL)
+--- 524,531 ----
+ /*
+ * Get some space to modify the format string into.
+ */
+! sz = efm_regpat_bufsz(efm);
+! if ((fmtstr = alloc(sz)) == NULL)
+ goto parse_efm_error;
+
+ while (efm[0] != NUL)
+***************
+*** 501,511 ****
+ /*
+ * 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;
+--- 545,553 ----
+ /*
+ * Isolate one part in the 'errorformat' option
+ */
+! len = efm_option_part_len(efm);
+
+! if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == FAIL)
+ goto parse_efm_error;
+ if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
+ goto parse_efm_error;
+***************
+*** 539,544 ****
+--- 581,590 ----
+ QF_MULTISCAN = 5,
+ };
+
++ /*
++ * State information used to parse lines and add entries to a quickfix/location
++ * list.
++ */
+ typedef struct {
+ char_u *linebuf;
+ int linelen;
+***************
+*** 554,559 ****
+--- 600,608 ----
+ vimconv_T vc;
+ } qfstate_T;
+
++ /*
++ * Allocate more memory for the line buffer used for parsing lines.
++ */
+ static char_u *
+ qf_grow_linebuf(qfstate_T *state, int newsz)
+ {
+***************
+*** 861,870 ****
+ } qffields_T;
+
+ /*
+! * Parse the error format matches in 'regmatch' and set the values in 'fields'.
+! * fmt_ptr contains the 'efm' format specifiers/prefixes that have a match.
+! * Returns QF_OK if all the matches are successfully parsed. On failure,
+! * returns QF_FAIL or QF_NOMEM.
+ */
+ static int
+ qf_parse_match(
+--- 910,1160 ----
+ } qffields_T;
+
+ /*
+! * Parse the match for filename ('%f') pattern in regmatch.
+! * Return the matched value in "fields->namebuf".
+! */
+! static int
+! qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
+! {
+! int c;
+!
+! if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+! return QF_FAIL;
+!
+! /* Expand ~/file and $HOME/file to full path. */
+! c = *rmp->endp[midx];
+! *rmp->endp[midx] = NUL;
+! expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE);
+! *rmp->endp[midx] = c;
+!
+! /*
+! * For separate filename patterns (%O, %P and %Q), the specified file
+! * should exist.
+! */
+! if (vim_strchr((char_u *)"OPQ", prefix) != NULL
+! && mch_getperm(fields->namebuf) == -1)
+! return QF_FAIL;
+!
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for error number ('%n') pattern in regmatch.
+! * Return the matched value in "fields->enr".
+! */
+! static int
+! qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! fields->enr = (int)atol((char *)rmp->startp[midx]);
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for line number (%l') pattern in regmatch.
+! * Return the matched value in "fields->lnum".
+! */
+! static int
+! qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! fields->lnum = atol((char *)rmp->startp[midx]);
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for column number ('%c') pattern in regmatch.
+! * Return the matched value in "fields->col".
+! */
+! static int
+! qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! fields->col = (int)atol((char *)rmp->startp[midx]);
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for error type ('%t') pattern in regmatch.
+! * Return the matched value in "fields->type".
+! */
+! static int
+! qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! fields->type = *rmp->startp[midx];
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for '%+' format pattern. The whole matching line is included
+! * in the error string. Return the matched line in "fields->errmsg".
+! */
+! static int
+! qf_parse_fmt_plus(char_u *linebuf, int linelen, qffields_T *fields)
+! {
+! char_u *p;
+!
+! if (linelen >= fields->errmsglen)
+! {
+! /* linelen + null terminator */
+! if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
+! return QF_NOMEM;
+! fields->errmsg = p;
+! fields->errmsglen = linelen + 1;
+! }
+! vim_strncpy(fields->errmsg, linebuf, linelen);
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for error message ('%m') pattern in regmatch.
+! * Return the matched value in "fields->errmsg".
+! */
+! static int
+! qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! char_u *p;
+! int len;
+!
+! if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+! return QF_FAIL;
+! len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+! if (len >= fields->errmsglen)
+! {
+! /* len + null terminator */
+! if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
+! return QF_NOMEM;
+! fields->errmsg = p;
+! fields->errmsglen = len + 1;
+! }
+! vim_strncpy(fields->errmsg, rmp->startp[midx], len);
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for rest of a single-line file message ('%r') pattern.
+! * Return the matched value in "tail".
+! */
+! static int
+! qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! *tail = rmp->startp[midx];
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for the pointer line ('%p') pattern in regmatch.
+! * Return the matched value in "fields->col".
+! */
+! static int
+! qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! char_u *match_ptr;
+!
+! if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+! return QF_FAIL;
+! fields->col = 0;
+! for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx];
+! ++match_ptr)
+! {
+! ++fields->col;
+! if (*match_ptr == TAB)
+! {
+! fields->col += 7;
+! fields->col -= fields->col % 8;
+! }
+! }
+! ++fields->col;
+! fields->use_viscol = TRUE;
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for the virtual column number ('%v') pattern in regmatch.
+! * Return the matched value in "fields->col".
+! */
+! static int
+! qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! if (rmp->startp[midx] == NULL)
+! return QF_FAIL;
+! fields->col = (int)atol((char *)rmp->startp[midx]);
+! fields->use_viscol = TRUE;
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for the search text ('%s') pattern in regmatch.
+! * Return the matched value in "fields->pattern".
+! */
+! static int
+! qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! int len;
+!
+! if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+! return QF_FAIL;
+! len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+! if (len > CMDBUFFSIZE - 5)
+! len = CMDBUFFSIZE - 5;
+! STRCPY(fields->pattern, "^\\V");
+! STRNCAT(fields->pattern, rmp->startp[midx], len);
+! fields->pattern[len + 3] = '\\';
+! fields->pattern[len + 4] = '$';
+! fields->pattern[len + 5] = NUL;
+! return QF_OK;
+! }
+!
+! /*
+! * Parse the match for the module ('%o') pattern in regmatch.
+! * Return the matched value in "fields->module".
+! */
+! static int
+! qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
+! {
+! int len;
+!
+! if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+! return QF_FAIL;
+! len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+! if (len > CMDBUFFSIZE)
+! len = CMDBUFFSIZE;
+! STRNCAT(fields->module, rmp->startp[midx], len);
+! return QF_OK;
+! }
+!
+! /*
+! * 'errorformat' format pattern parser functions.
+! * The '%f' and '%r' formats are parsed differently from other formats.
+! * See qf_parse_match() for details.
+! */
+! static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) =
+! {
+! NULL,
+! qf_parse_fmt_n,
+! qf_parse_fmt_l,
+! qf_parse_fmt_c,
+! qf_parse_fmt_t,
+! qf_parse_fmt_m,
+! NULL,
+! qf_parse_fmt_p,
+! qf_parse_fmt_v,
+! qf_parse_fmt_s,
+! qf_parse_fmt_o
+! };
+!
+! /*
+! * Parse the error format pattern matches in "regmatch" and set the values in
+! * "fields". fmt_ptr contains the 'efm' format specifiers/prefixes that have a
+! * match. Returns QF_OK if all the matches are successfully parsed. On
+! * failure, returns QF_FAIL or QF_NOMEM.
+ */
+ static int
+ qf_parse_match(
+***************
+*** 877,886 ****
+ int qf_multiscan,
+ char_u **tail)
+ {
+- char_u *p;
+ int idx = fmt_ptr->prefix;
+ int i;
+! int len;
+
+ if ((idx == 'C' || idx == 'Z') && !qf_multiline)
+ return QF_FAIL;
+--- 1167,1176 ----
+ int qf_multiscan,
+ char_u **tail)
+ {
+ int idx = fmt_ptr->prefix;
+ int i;
+! int midx;
+! int status;
+
+ if ((idx == 'C' || idx == 'Z') && !qf_multiline)
+ return QF_FAIL;
+***************
+*** 893,1020 ****
+ * 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 */
+ {
+! int c;
+
+! if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
+! return QF_FAIL;
+!
+! /* Expand ~/file and $HOME/file to full path. */
+! 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
+! && mch_getperm(fields->namebuf) == -1)
+! return QF_FAIL;
+! }
+! if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! fields->enr = (int)atol((char *)regmatch->startp[i]);
+! }
+! if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! fields->lnum = atol((char *)regmatch->startp[i]);
+! }
+! if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! fields->col = (int)atol((char *)regmatch->startp[i]);
+! }
+! if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! fields->type = *regmatch->startp[i];
+! }
+! if (fmt_ptr->flags == '+' && !qf_multiscan) /* %+ */
+! {
+! if (linelen >= fields->errmsglen)
+! {
+! /* linelen + null terminator */
+! if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
+! return QF_NOMEM;
+! fields->errmsg = p;
+! fields->errmsglen = linelen + 1;
+! }
+! vim_strncpy(fields->errmsg, linebuf, linelen);
+! }
+! else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */
+! {
+! if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
+! return QF_FAIL;
+! len = (int)(regmatch->endp[i] - regmatch->startp[i]);
+! if (len >= fields->errmsglen)
+! {
+! /* len + null terminator */
+! if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
+! return QF_NOMEM;
+! fields->errmsg = p;
+! fields->errmsglen = len + 1;
+! }
+! vim_strncpy(fields->errmsg, regmatch->startp[i], len);
+! }
+! if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! *tail = regmatch->startp[i];
+! }
+! if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */
+! {
+! char_u *match_ptr;
+!
+! if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
+! return QF_FAIL;
+! 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;
+! }
+! }
+! ++fields->col;
+! fields->use_viscol = TRUE;
+! }
+! if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */
+! {
+! if (regmatch->startp[i] == NULL)
+! return QF_FAIL;
+! 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)
+! return QF_FAIL;
+! len = (int)(regmatch->endp[i] - regmatch->startp[i]);
+! if (len > CMDBUFFSIZE - 5)
+! len = CMDBUFFSIZE - 5;
+! STRCPY(fields->pattern, "^\\V");
+! STRNCAT(fields->pattern, regmatch->startp[i], len);
+! fields->pattern[len + 3] = '\\';
+! fields->pattern[len + 4] = '$';
+! fields->pattern[len + 5] = NUL;
+! }
+! if ((i = (int)fmt_ptr->addr[10]) > 0) /* %o */
+! {
+! if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
+! return QF_FAIL;
+! len = (int)(regmatch->endp[i] - regmatch->startp[i]);
+! if (len > CMDBUFFSIZE)
+! len = CMDBUFFSIZE;
+! STRNCAT(fields->module, regmatch->startp[i], len);
+ }
+
+ return QF_OK;
+--- 1183,1208 ----
+ * We check for an actual submatch, because "\[" and "\]" in
+ * the 'errorformat' may cause the wrong submatch to be used.
+ */
+! for (i = 0; i < FMT_PATTERNS; i++)
+ {
+! status = QF_OK;
+! midx = (int)fmt_ptr->addr[i];
+! if (i == 0 && midx > 0) /* %f */
+! status = qf_parse_fmt_f(regmatch, midx, fields, idx);
+! else if (i == 5)
+! {
+! if (fmt_ptr->flags == '+' && !qf_multiscan) /* %+ */
+! status = qf_parse_fmt_plus(linebuf, linelen, fields);
+! else if (midx > 0) /* %m */
+! status = qf_parse_fmt_m(regmatch, midx, fields);
+! }
+! else if (i == 6 && midx > 0) /* %r */
+! status = qf_parse_fmt_r(regmatch, midx, tail);
+! else if (midx > 0) /* others */
+! status = (qf_parse_fmt[i])(regmatch, midx, fields);
+
+! if (status != QF_OK)
+! return status;
+ }
+
+ return QF_OK;
+***************
+*** 1308,1313 ****
+--- 1496,1513 ----
+ }
+
+ /*
++ * Returns TRUE if the specified quickfix/location list is empty.
++ */
++ static int
++ qf_list_empty(qf_info_T *qi, int qf_idx)
++ {
++ if (qi == NULL || qf_idx < 0 || qf_idx >= LISTCOUNT)
++ return TRUE;
++ return qi->qf_lists[qf_idx].qf_count <= 0;
++ }
++
++
++ /*
+ * Allocate the fields used for parsing lines and populating a quickfix list.
+ */
+ static int
+***************
+*** 1450,1456 ****
+ {
+ /* Adding to existing list, use last entry. */
+ adding = TRUE;
+! if (qi->qf_lists[qf_idx].qf_count > 0)
+ old_last = qi->qf_lists[qf_idx].qf_last;
+ }
+
+--- 1650,1656 ----
+ {
+ /* Adding to existing list, use last entry. */
+ adding = TRUE;
+! if (!qf_list_empty(qi, qf_idx))
+ old_last = qi->qf_lists[qf_idx].qf_last;
+ }
+
+***************
+*** 1777,1784 ****
+ qfp->qf_valid = valid;
+
+ lastp = &qi->qf_lists[qf_idx].qf_last;
+! if (qi->qf_lists[qf_idx].qf_count == 0)
+! /* first element in the list */
+ {
+ qi->qf_lists[qf_idx].qf_start = qfp;
+ qi->qf_lists[qf_idx].qf_ptr = qfp;
+--- 1977,1983 ----
+ qfp->qf_valid = valid;
+
+ lastp = &qi->qf_lists[qf_idx].qf_last;
+! if (qf_list_empty(qi, qf_idx)) /* first element in the list */
+ {
+ qi->qf_lists[qf_idx].qf_start = qfp;
+ qi->qf_lists[qf_idx].qf_ptr = qfp;
+***************
+*** 1875,1881 ****
+ to->w_llist->qf_listcount = qi->qf_listcount;
+
+ /* Copy the location lists one at a time */
+! for (idx = 0; idx < qi->qf_listcount; idx++)
+ {
+ qf_list_T *from_qfl;
+ qf_list_T *to_qfl;
+--- 2074,2080 ----
+ to->w_llist->qf_listcount = qi->qf_listcount;
+
+ /* Copy the location lists one at a time */
+! for (idx = 0; idx < qi->qf_listcount; ++idx)
+ {
+ qf_list_T *from_qfl;
+ qf_list_T *to_qfl;
+***************
+*** 2907,2913 ****
+ qi = &ql_info;
+
+ if (qi->qf_curlist >= qi->qf_listcount
+! || qi->qf_lists[qi->qf_curlist].qf_count == 0)
+ {
+ EMSG(_(e_quickfix));
+ return;
+--- 3106,3112 ----
+ qi = &ql_info;
+
+ if (qi->qf_curlist >= qi->qf_listcount
+! || qf_list_empty(qi, qi->qf_curlist))
+ {
+ EMSG(_(e_quickfix));
+ return;
+***************
+*** 3033,3056 ****
+ }
+
+ /*
+ * ":clist": list all errors
+ * ":llist": list all locations
+ */
+ void
+ qf_list(exarg_T *eap)
+ {
+- buf_T *buf;
+- char_u *fname;
+ qfline_T *qfp;
+ int i;
+ int idx1 = 1;
+ int idx2 = -1;
+ char_u *arg = eap->arg;
+ int plus = FALSE;
+- int qfFileAttr;
+- int qfSepAttr;
+- int qfLineAttr;
+- int filter_entry;
+ int all = eap->forceit; /* if not :cl!, only show
+ recognised errors */
+ qf_info_T *qi = &ql_info;
+--- 3232,3336 ----
+ }
+
+ /*
++ * Highlight attributes used for displaying entries from the quickfix list.
++ */
++ static int qfFileAttr;
++ static int qfSepAttr;
++ static int qfLineAttr;
++
++ /*
++ * Display information about a single entry from the quickfix/location list.
++ * Used by ":clist/:llist" commands.
++ */
++ static void
++ qf_list_entry(qf_info_T *qi, qfline_T *qfp, int qf_idx)
++ {
++ char_u *fname;
++ buf_T *buf;
++ int filter_entry;
++
++ fname = NULL;
++ if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
++ vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
++ (char *)qfp->qf_module);
++ else {
++ if (qfp->qf_fnum != 0
++ && (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
++ {
++ fname = buf->b_fname;
++ if (qfp->qf_type == 1) /* :helpgrep */
++ fname = gettail(fname);
++ }
++ if (fname == NULL)
++ sprintf((char *)IObuff, "%2d", qf_idx);
++ else
++ vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
++ qf_idx, (char *)fname);
++ }
++
++ // Support for filtering entries using :filter /pat/ clist
++ // Match against the module name, file name, search pattern and
++ // text of the entry.
++ filter_entry = TRUE;
++ if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
++ filter_entry &= message_filtered(qfp->qf_module);
++ if (filter_entry && fname != NULL)
++ filter_entry &= message_filtered(fname);
++ if (filter_entry && qfp->qf_pattern != NULL)
++ filter_entry &= message_filtered(qfp->qf_pattern);
++ if (filter_entry)
++ filter_entry &= message_filtered(qfp->qf_text);
++ if (filter_entry)
++ return;
++
++ msg_putchar('\n');
++ msg_outtrans_attr(IObuff, qf_idx == qi->qf_lists[qi->qf_curlist].qf_index
++ ? HL_ATTR(HLF_QFL) : qfFileAttr);
++
++ if (qfp->qf_lnum != 0)
++ msg_puts_attr((char_u *)":", qfSepAttr);
++ if (qfp->qf_lnum == 0)
++ IObuff[0] = NUL;
++ else if (qfp->qf_col == 0)
++ sprintf((char *)IObuff, "%ld", qfp->qf_lnum);
++ else
++ sprintf((char *)IObuff, "%ld col %d",
++ qfp->qf_lnum, qfp->qf_col);
++ sprintf((char *)IObuff + STRLEN(IObuff), "%s",
++ (char *)qf_types(qfp->qf_type, qfp->qf_nr));
++ msg_puts_attr(IObuff, qfLineAttr);
++ msg_puts_attr((char_u *)":", qfSepAttr);
++ if (qfp->qf_pattern != NULL)
++ {
++ qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
++ msg_puts(IObuff);
++ msg_puts_attr((char_u *)":", qfSepAttr);
++ }
++ 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
++ * with ^^^^. */
++ qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
++ ? skipwhite(qfp->qf_text) : qfp->qf_text,
++ IObuff, IOSIZE);
++ msg_prt_line(IObuff, FALSE);
++ out_flush(); /* show one line at a time */
++ }
++
++ /*
+ * ":clist": list all errors
+ * ":llist": list all locations
+ */
+ void
+ qf_list(exarg_T *eap)
+ {
+ qfline_T *qfp;
+ int i;
+ int idx1 = 1;
+ int idx2 = -1;
+ char_u *arg = eap->arg;
+ int plus = FALSE;
+ int all = eap->forceit; /* if not :cl!, only show
+ recognised errors */
+ qf_info_T *qi = &ql_info;
+***************
+*** 3066,3072 ****
+ }
+
+ if (qi->qf_curlist >= qi->qf_listcount
+! || qi->qf_lists[qi->qf_curlist].qf_count == 0)
+ {
+ EMSG(_(e_quickfix));
+ return;
+--- 3346,3352 ----
+ }
+
+ if (qi->qf_curlist >= qi->qf_listcount
+! || qf_list_empty(qi, qi->qf_curlist))
+ {
+ EMSG(_(e_quickfix));
+ return;
+***************
+*** 3123,3197 ****
+ if (got_int)
+ break;
+
+! fname = NULL;
+! if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
+! vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)qfp->qf_module);
+! else {
+! if (qfp->qf_fnum != 0
+! && (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
+! {
+! fname = buf->b_fname;
+! if (qfp->qf_type == 1) /* :helpgrep */
+! fname = gettail(fname);
+! }
+! if (fname == NULL)
+! sprintf((char *)IObuff, "%2d", i);
+! else
+! vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
+! i, (char *)fname);
+! }
+!
+! // Support for filtering entries using :filter /pat/ clist
+! // Match against the module name, file name, search pattern and
+! // text of the entry.
+! filter_entry = TRUE;
+! if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
+! filter_entry &= message_filtered(qfp->qf_module);
+! if (filter_entry && fname != NULL)
+! filter_entry &= message_filtered(fname);
+! if (filter_entry && qfp->qf_pattern != NULL)
+! filter_entry &= message_filtered(qfp->qf_pattern);
+! if (filter_entry)
+! filter_entry &= message_filtered(qfp->qf_text);
+! if (filter_entry)
+! goto next_entry;
+!
+! msg_putchar('\n');
+! msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
+! ? HL_ATTR(HLF_QFL) : qfFileAttr);
+!
+! if (qfp->qf_lnum != 0)
+! msg_puts_attr((char_u *)":", qfSepAttr);
+! if (qfp->qf_lnum == 0)
+! IObuff[0] = NUL;
+! else if (qfp->qf_col == 0)
+! sprintf((char *)IObuff, "%ld", qfp->qf_lnum);
+! else
+! sprintf((char *)IObuff, "%ld col %d",
+! qfp->qf_lnum, qfp->qf_col);
+! sprintf((char *)IObuff + STRLEN(IObuff), "%s",
+! (char *)qf_types(qfp->qf_type, qfp->qf_nr));
+! msg_puts_attr(IObuff, qfLineAttr);
+! msg_puts_attr((char_u *)":", qfSepAttr);
+! if (qfp->qf_pattern != NULL)
+! {
+! qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
+! msg_puts(IObuff);
+! msg_puts_attr((char_u *)":", qfSepAttr);
+! }
+! 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
+! * with ^^^^. */
+! qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
+! ? skipwhite(qfp->qf_text) : qfp->qf_text,
+! IObuff, IOSIZE);
+! msg_prt_line(IObuff, FALSE);
+! out_flush(); /* show one line at a time */
+ }
+
+- next_entry:
+ qfp = qfp->qf_next;
+ if (qfp == NULL)
+ break;
+--- 3403,3411 ----
+ if (got_int)
+ break;
+
+! qf_list_entry(qi, qfp, i);
+ }
+
+ qfp = qfp->qf_next;
+ if (qfp == NULL)
+ break;
+***************
+*** 3320,3326 ****
+ 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)
+--- 3534,3540 ----
+ if (eap->cmdidx == CMD_lhistory)
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL || (qi->qf_listcount == 0
+! && qf_list_empty(qi, qi->qf_curlist)))
+ MSG(_("No entries"));
+ else
+ for (i = 0; i < qi->qf_listcount; ++i)
+***************
+*** 3421,3427 ****
+ }
+
+ 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)
+--- 3635,3641 ----
+ }
+
+ for (idx = 0; idx < qi->qf_listcount; ++idx)
+! if (!qf_list_empty(qi, idx))
+ for (i = 0, qfp = qi->qf_lists[idx].qf_start;
+ i < qi->qf_lists[idx].qf_count && qfp != NULL;
+ ++i, qfp = qfp->qf_next)
+***************
+*** 3552,3558 ****
+ * it if we have errors; otherwise, leave it closed.
+ */
+ if (qi->qf_lists[qi->qf_curlist].qf_nonevalid
+! || qi->qf_lists[qi->qf_curlist].qf_count == 0
+ || qi->qf_curlist >= qi->qf_listcount)
+ {
+ if (win != NULL)
+--- 3766,3772 ----
+ * it if we have errors; otherwise, leave it closed.
+ */
+ if (qi->qf_lists[qi->qf_curlist].qf_nonevalid
+! || qf_list_empty(qi, qi->qf_curlist)
+ || qi->qf_curlist >= qi->qf_listcount)
+ {
+ if (win != NULL)
+***************
+*** 5154,5160 ****
+ qi->qf_curlist = qf_id2nr(qi, save_qfid);
+
+ /* Jump to first match. */
+! if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
+ {
+ if ((flags & VGR_NOJUMP) == 0)
+ vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
+--- 5368,5374 ----
+ qi->qf_curlist = qf_id2nr(qi, save_qfid);
+
+ /* Jump to first match. */
+! if (!qf_list_empty(qi, qi->qf_curlist))
+ {
+ if ((flags & VGR_NOJUMP) == 0)
+ vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
+***************
+*** 5387,5394 ****
+ if (qf_idx == INVALID_QFIDX)
+ qf_idx = qi->qf_curlist;
+
+! if (qf_idx >= qi->qf_listcount
+! || qi->qf_lists[qf_idx].qf_count == 0)
+ return FAIL;
+
+ qfp = qi->qf_lists[qf_idx].qf_start;
+--- 5601,5607 ----
+ if (qf_idx == INVALID_QFIDX)
+ qf_idx = qi->qf_curlist;
+
+! if (qf_idx >= qi->qf_listcount || qf_list_empty(qi, qf_idx))
+ return FAIL;
+
+ qfp = qi->qf_lists[qf_idx].qf_start;
+***************
+*** 5709,5715 ****
+ qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict)
+ {
+ int idx = qi->qf_lists[qf_idx].qf_index;
+! if (qi->qf_lists[qf_idx].qf_count == 0)
+ /* For empty lists, qf_index is set to 1 */
+ idx = 0;
+ return dict_add_number(retdict, "idx", idx);
+--- 5922,5928 ----
+ qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict)
+ {
+ int idx = qi->qf_lists[qf_idx].qf_index;
+! if (qf_list_empty(qi, qf_idx))
+ /* For empty lists, qf_index is set to 1 */
+ idx = 0;
+ return dict_add_number(retdict, "idx", idx);
+***************
+*** 5798,5804 ****
+ qf_new_list(qi, title);
+ qf_idx = qi->qf_curlist;
+ }
+! else if (action == 'a' && qi->qf_lists[qf_idx].qf_count > 0)
+ /* Adding to existing list, use last entry. */
+ old_last = qi->qf_lists[qf_idx].qf_last;
+ else if (action == 'r')
+--- 6011,6017 ----
+ qf_new_list(qi, title);
+ qf_idx = qi->qf_curlist;
+ }
+! else if (action == 'a' && !qf_list_empty(qi, qf_idx))
+ /* Adding to existing list, use last entry. */
+ old_last = qi->qf_lists[qf_idx].qf_last;
+ else if (action == 'r')
+***************
+*** 5887,5893 ****
+ {
+ qi->qf_lists[qf_idx].qf_ptr =
+ qi->qf_lists[qf_idx].qf_start;
+! if (qi->qf_lists[qf_idx].qf_count > 0)
+ qi->qf_lists[qf_idx].qf_index = 1;
+ }
+
+--- 6100,6106 ----
+ {
+ qi->qf_lists[qf_idx].qf_ptr =
+ qi->qf_lists[qf_idx].qf_start;
+! if (!qf_list_empty(qi, qf_idx))
+ qi->qf_lists[qf_idx].qf_index = 1;
+ }
+
+***************
+*** 6746,6752 ****
+ }
+
+ /* Jump to first match. */
+! if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
+ qf_jump(qi, 0, 0, FALSE);
+ else
+ EMSG2(_(e_nomatch2), eap->arg);
+--- 6959,6965 ----
+ }
+
+ /* Jump to first match. */
+! if (!qf_list_empty(qi, qi->qf_curlist))
+ qf_jump(qi, 0, 0, FALSE);
+ else
+ EMSG2(_(e_nomatch2), eap->arg);
+*** ../vim-8.1.0251/src/version.c 2018-08-07 21:39:09.251060096 +0200
+--- src/version.c 2018-08-07 21:43:08.981711510 +0200
+***************
+*** 796,797 ****
+--- 796,799 ----
+ { /* Add new patch number below this line */
++ /**/
++ 252,
+ /**/
+
+--
+Q: How do you tell the difference between a female cat and a male cat?
+A: You ask it a question and if HE answers, it's a male but, if SHE
+ answers, it's a female.
+
+ /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
+/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
+\\\ an exciting new programming language -- http://www.Zimbu.org ///
+ \\\ help me help AIDS victims -- http://ICCF-Holland.org ///