Patch 7.4.1964
Problem: The quickfix init function is too big.
Solution: Factor out parsing 'errorformat' to a separate function. (Yegappan
Lakshmanan)
Files: src/quickfix.c
*** ../vim-7.4.1963/src/quickfix.c 2016-06-20 21:41:08.146876332 +0200
--- src/quickfix.c 2016-06-26 22:00:30.259421677 +0200
***************
*** 205,210 ****
--- 205,494 ----
return *growbuf;
}
+ 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', ".\\+"}
+ };
+
+ /*
+ * 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)
+ {
+ char_u *ptr;
+ char_u *efmp;
+ char_u *srcptr;
+ int round;
+ int idx = 0;
+
+ /*
+ * Build regexp pattern from current 'errorformat' option
+ */
+ ptr = regpat;
+ *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);
+ 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))
+ {
+ sprintf((char *)errmsg,
+ _("E373: Unexpected %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ return -1;
+ }
+ 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++ = ')';
+ }
+ 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"));
+ return -1;
+ }
+ }
+ }
+ 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);
+ 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
+ {
+ sprintf((char *)errmsg,
+ _("E376: Invalid %%%c in format string prefix"),
*efmp);
+ EMSG(errmsg);
+ return -1;
+ }
+ }
+ else
+ {
+ sprintf((char *)errmsg,
+ _("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;
+ }
+ }
+ *ptr++ = '$';
+ *ptr = NUL;
+
+ return 0;
+ }
+
+ static void
+ free_efm_list(efm_T **efm_first)
+ {
+ efm_T *efm_ptr;
+
+ for (efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first)
+ {
+ *efm_first = efm_ptr->next;
+ vim_regfree(efm_ptr->prog);
+ vim_free(efm_ptr);
+ }
+ }
+
+ /* Parse 'errorformat' option */
+ static efm_T *
+ parse_efm_option(char_u *efm)
+ {
+ char_u *errmsg = NULL;
+ int errmsglen;
+ efm_T *fmt_ptr = NULL;
+ efm_T *fmt_first = NULL;
+ 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);
+ if (errmsg == NULL)
+ goto parse_efm_end;
+
+ /*
+ * 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 COLON_IN_FILENAME
+ i += 12; /* "%f" can become twelve chars longer */
+ #else
+ i += 2; /* "%f" can become two chars longer */
+ #endif
+ if ((fmtstr = alloc(i)) == NULL)
+ goto parse_efm_error;
+
+ while (efm[0] != NUL)
+ {
+ /*
+ * Allocate a new eformat structure and put it at the end of the list
+ */
+ fmt_ptr = (efm_T *)alloc_clear((unsigned)sizeof(efm_T));
+ if (fmt_ptr == NULL)
+ goto parse_efm_error;
+ 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 */
+ EMSG(_("E378: 'errorformat' contains no pattern"));
+
+ goto parse_efm_end;
+
+ parse_efm_error:
+ free_efm_list(&fmt_first);
+
+ parse_efm_end:
+ vim_free(fmtstr);
+ vim_free(errmsg);
+
+ return fmt_first;
+ }
+
/*
* Read the errorfile "efile" into memory, line by line, building the error
* list.
***************
*** 231,237 ****
char_u *errmsg;
int errmsglen;
char_u *pattern;
- char_u *fmtstr = NULL;
char_u *growbuf = NULL;
int growbuflen;
int growbufsiz = 0;
--- 515,520 ----
***************
*** 249,265 ****
#ifdef FEAT_WINDOWS
qfline_T *old_last = NULL;
#endif
- 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;
int multiline = FALSE;
int multiignore = FALSE;
--- 532,544 ----
***************
*** 273,295 ****
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 = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
errmsglen = CMDBUFFSIZE + 1;
--- 552,557 ----
***************
*** 324,529 ****
efm = buf->b_p_efm;
else
efm = errorformat;
- /*
- * 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 COLON_IN_FILENAME
- i += 12; /* "%f" can become twelve chars longer */
- #else
- i += 2; /* "%f" can become two chars longer */
- #endif
- if ((fmtstr = alloc(i)) == NULL)
- goto error2;
! while (efm[0] != NUL)
! {
! /*
! * Allocate a new eformat structure and put it at the end of the list
! */
! fmt_ptr = (efm_T *)alloc_clear((unsigned)sizeof(efm_T));
! if (fmt_ptr == NULL)
! goto error2;
! if (fmt_first == NULL) /* first one */
! fmt_first = fmt_ptr;
! else
! fmt_last->next = fmt_ptr;
! fmt_last = fmt_ptr;
!
! /*
! * 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;
! }
! 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;
! }
! 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++ = ')';
! }
! 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;
! }
! }
! }
! 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;
! }
! }
! else
! {
! sprintf((char *)errmsg,
! _("E377: Invalid %%%c in format string"), *efmp);
! EMSG(errmsg);
! goto error2;
! }
! }
! 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 */
! }
if (fmt_first == NULL) /* nothing found */
- {
- EMSG(_("E378: 'errorformat' contains no pattern"));
goto error2;
- }
/*
* got_int is reset here, because it was probably set when killing the
--- 586,595 ----
efm = buf->b_p_efm;
else
efm = errorformat;
! fmt_first = parse_efm_option(efm);
if (fmt_first == NULL) /* nothing found */
goto error2;
/*
* got_int is reset here, because it was probably set when killing the
***************
*** 1046,1064 ****
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);
! vim_free(fmt_ptr);
! }
qf_clean_dir_stack(&dir_stack);
qf_clean_dir_stack(&file_stack);
qf_init_end:
vim_free(namebuf);
vim_free(errmsg);
vim_free(pattern);
- vim_free(fmtstr);
vim_free(growbuf);
#ifdef FEAT_WINDOWS
--- 1112,1124 ----
qf_init_ok:
if (fd != NULL)
fclose(fd);
! free_efm_list(&fmt_first);
qf_clean_dir_stack(&dir_stack);
qf_clean_dir_stack(&file_stack);
qf_init_end:
vim_free(namebuf);
vim_free(errmsg);
vim_free(pattern);
vim_free(growbuf);
#ifdef FEAT_WINDOWS
*** ../vim-7.4.1963/src/version.c 2016-06-26 20:37:24.571968881 +0200
--- src/version.c 2016-06-26 22:05:24.894191665 +0200
***************
*** 755,756 ****
--- 755,758 ----
{ /* Add new patch number below this line */
+ /**/
+ 1964,
/**/
--
Fingers not found - Pound head on keyboard to continue.
/// 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.