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 -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.