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.

Raspunde prin e-mail lui