updated for version 7.0025
diff --git a/src/buffer.c b/src/buffer.c
index 4003b9c..1ed7a00 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1699,6 +1699,7 @@
     clear_string_option(&buf->b_p_kp);
     clear_string_option(&buf->b_p_mps);
     clear_string_option(&buf->b_p_fo);
+    clear_string_option(&buf->b_p_flp);
     clear_string_option(&buf->b_p_isk);
 #ifdef FEAT_KEYMAP
     clear_string_option(&buf->b_p_keymap);
@@ -2541,6 +2542,28 @@
 }
 
 /*
+ * Crude way of changing the name of a buffer.  Use with care!
+ * The name should be relative to the current directory.
+ */
+    void
+buf_set_name(fnum, name)
+    int		fnum;
+    char_u	*name;
+{
+    buf_T	*buf;
+
+    buf = buflist_findnr(fnum);
+    if (buf != NULL)
+    {
+	vim_free(buf->b_sfname);
+	vim_free(buf->b_ffname);
+	buf->b_sfname = vim_strsave(name);
+	buf->b_ffname = FullName_save(buf->b_sfname, FALSE);
+	buf->b_fname = buf->b_sfname;
+    }
+}
+
+/*
  * Take care of what needs to be done when the name of buffer "buf" has
  * changed.
  */
diff --git a/src/charset.c b/src/charset.c
index 4560a96..0a46306 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -415,7 +415,6 @@
     mch_memmove(ga.ga_data, str, (size_t)len);
     GA_CHAR(len) = NUL;
     ga.ga_len = len;
-    ga.ga_room -= len;
 
     /* Make each character lower case. */
     i = 0;
@@ -451,7 +450,6 @@
 			    mch_memmove(GA_PTR(i) + nl, GA_PTR(i) + ol,
 						  STRLEN(GA_PTR(i) + ol) + 1);
 			    ga.ga_len += nl - ol;
-			    ga.ga_room -= nl - ol;
 			}
 		    }
 		    (void)utf_char2bytes(lc, GA_PTR(i));
diff --git a/src/digraph.c b/src/digraph.c
index 4c15d49..31d7f37 100644
--- a/src/digraph.c
+++ b/src/digraph.c
@@ -2230,7 +2230,6 @@
 		dp->char2 = char2;
 		dp->result = n;
 		++user_digraphs.ga_len;
-		--user_digraphs.ga_room;
 	    }
 	}
     }
@@ -2450,10 +2449,7 @@
 		vim_free(kp->to);
 	    }
 	    else
-	    {
 		++curbuf->b_kmap_ga.ga_len;
-		--curbuf->b_kmap_ga.ga_room;
-	    }
 	}
 	vim_free(line);
     }
diff --git a/src/edit.c b/src/edit.c
index a2ceb50..15812c7 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -2707,7 +2707,6 @@
 		    break;
 		((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(p, len);
 		++ga.ga_len;
-		--ga.ga_room;
 	    }
 	    if (*pnext != NUL)
 		++pnext;
diff --git a/src/eval.c b/src/eval.c
index e06fd16..dcd86e5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5972,7 +5972,6 @@
     if (ga_userinput.ga_len > 0)
     {
 	--ga_userinput.ga_len;
-	++ga_userinput.ga_room;
 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
 						       + ga_userinput.ga_len);
 	retvar->var_val.var_number = 0; /* OK */
@@ -5999,7 +5998,6 @@
 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
 						       + ga_userinput.ga_len);
 	++ga_userinput.ga_len;
-	--ga_userinput.ga_room;
 	retvar->var_val.var_number = 0; /* OK */
     }
     else
@@ -8092,7 +8090,6 @@
 	    ga_grow(&ga, cplen);
 	    mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
 	    ga.ga_len += cplen;
-	    ga.ga_room -= cplen;
 
 	    instr += inlen;
 	}
@@ -9109,7 +9106,6 @@
 	{
 	    var_init(&SCRIPT_VARS(ga_scripts.ga_len + 1));
 	    ++ga_scripts.ga_len;
-	    --ga_scripts.ga_room;
 	}
     }
 }
@@ -9269,10 +9265,7 @@
 	if ((v->var_name = vim_strsave(varname)) == NULL)
 	    return;
 	if (i == gap->ga_len)
-	{
 	    ++gap->ga_len;
-	    --gap->ga_room;
-	}
     }
     copy_var(varp, v);
 }
@@ -9441,12 +9434,8 @@
 		break;
 	    }
 	    if (ga.ga_len)
-	    {
 		((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
-		--ga.ga_room;
-	    }
 	    STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
-	    ga.ga_room -= len;
 	    ga.ga_len += len;
 	}
 
@@ -9675,7 +9664,6 @@
 	    ((char_u **)(newargs.ga_data))[newargs.ga_len] = arg;
 	    *p = c;
 	    newargs.ga_len++;
-	    newargs.ga_room--;
 	    if (*p == ',')
 		++p;
 	    else
@@ -9829,7 +9817,6 @@
 	    goto erret;
 	((char_u **)(newlines.ga_data))[newlines.ga_len] = theline;
 	newlines.ga_len++;
-	newlines.ga_room--;
     }
 
     /* Don't define the function when skipping commands or when an error was
@@ -11398,7 +11385,6 @@
 	    (void)vim_regsub(&regmatch, sub, (char_u *)ga.ga_data
 					  + ga.ga_len + i, TRUE, TRUE, FALSE);
 	    ga.ga_len += i + sublen - 1;
-	    ga.ga_room -= i + sublen - 1;
 	    /* avoid getting stuck on a match with an empty string */
 	    if (tail == regmatch.endp[0])
 	    {
@@ -11406,7 +11392,6 @@
 		    break;
 		*((char_u *)ga.ga_data + ga.ga_len) = *tail++;
 		++ga.ga_len;
-		--ga.ga_room;
 	    }
 	    else
 	    {
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 7a176e0..adac95b 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -5315,7 +5315,6 @@
 		    break;
 		((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
 		((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
-		ga.ga_room -= 2;
 	    }
 	}
     }
@@ -5425,7 +5424,6 @@
 		sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
 		((char_u **)ga.ga_data)[ga.ga_len] = s;
 		++ga.ga_len;
-		--ga.ga_room;
 	    }
 	}
     }
@@ -5516,7 +5514,6 @@
 			}
 			((char_u **)ga.ga_data)[ga.ga_len] = s;
 			++ga.ga_len;
-			--ga.ga_room;
 			sprintf((char *)s, "%s\t%s", p1, fname);
 
 			/* find next '*' */
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index f59d018..b44dd1d 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -190,6 +190,8 @@
 			RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN),
 EX(CMD_catch,		"catch",	ex_catch,
 			EXTRA|SBOXOK|CMDWIN),
+EX(CMD_cbuffer,		"cbuffer",	ex_cbuffer,
+			RANGE|NOTADR|WORD1|TRLBAR),
 EX(CMD_cc,		"cc",		ex_cc,
 			RANGE|NOTADR|COUNT|TRLBAR|BANG),
 EX(CMD_cclose,		"cclose",	ex_cclose,
@@ -838,6 +840,10 @@
 			BANG|FILE1|EDITCMD|ARGOPT|TRLBAR),
 EX(CMD_view,		"view",		ex_edit,
 			BANG|FILE1|EDITCMD|ARGOPT|TRLBAR),
+EX(CMD_vimgrep,		"vimgrep",	ex_vimgrep,
+			EXTRA|TRLBAR|NEEDARG),
+EX(CMD_vimgrepadd,	"vimgrepadd",	ex_vimgrep,
+			EXTRA|TRLBAR|NEEDARG),
 EX(CMD_viusage,		"viusage",	ex_viusage,
 			TRLBAR),
 EX(CMD_vmap,		"vmap",		ex_map,
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 715bf99..a183133 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -491,7 +491,6 @@
 	    if (bp->dbg_lnum == 0)	/* default line number is 1 */
 		bp->dbg_lnum = 1;
 	    BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp;
-	    --dbg_breakp.ga_room;
 	    ++debug_tick;
 	}
     }
@@ -564,7 +563,6 @@
 	vim_free(BREAKP(todel).dbg_name);
 	vim_free(BREAKP(todel).dbg_prog);
 	--dbg_breakp.ga_len;
-	++dbg_breakp.ga_room;
 	if (todel < dbg_breakp.ga_len)
 	    mch_memmove(&BREAKP(todel), &BREAKP(todel + 1),
 		    (dbg_breakp.ga_len - todel) * sizeof(struct debuggy));
@@ -1063,6 +1061,31 @@
     return str;
 }
 
+/*
+ * Separate the arguments in "str" and return a list of pointers in the
+ * growarray "gap".
+ */
+    int
+get_arglist(gap, str)
+    garray_T	*gap;
+    char_u	*str;
+{
+    ga_init2(gap, (int)sizeof(char_u *), 20);
+    while (*str != NUL)
+    {
+	if (ga_grow(gap, 1) == FAIL)
+	{
+	    ga_clear(gap);
+	    return FAIL;
+	}
+	((char_u **)gap->ga_data)[gap->ga_len++] = str;
+
+	/* Isolate one argument, change it in-place, put a NUL after it. */
+	str = do_one_arg(str);
+    }
+    return OK;
+}
+
 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
 /*
  * Redefine the argument list.
@@ -1101,20 +1124,8 @@
     /*
      * Collect all file name arguments in "new_ga".
      */
-    ga_init2(&new_ga, (int)sizeof(char_u *), 20);
-    while (*str)
-    {
-	if (ga_grow(&new_ga, 1) == FAIL)
-	{
-	    ga_clear(&new_ga);
-	    return FAIL;
-	}
-	((char_u **)new_ga.ga_data)[new_ga.ga_len++] = str;
-	--new_ga.ga_room;
-
-	/* Isolate one argument, change it in-place, put a NUL after it. */
-	str = do_one_arg(str);
-    }
+    if (get_arglist(&new_ga, str) == FAIL)
+	return FAIL;
 
 #ifdef FEAT_LISTCMDS
     if (what == AL_DEL)
@@ -1154,7 +1165,6 @@
 		    mch_memmove(ARGLIST + match, ARGLIST + match + 1,
 			    (ARGCOUNT - match - 1) * sizeof(aentry_T));
 		    --ALIST(curwin)->al_ga.ga_len;
-		    ++ALIST(curwin)->al_ga.ga_room;
 		    if (curwin->w_arg_idx > match)
 			--curwin->w_arg_idx;
 		    --match;
@@ -1189,7 +1199,7 @@
 	}
 	else /* what == AL_SET */
 #endif
-	    alist_set(ALIST(curwin), exp_count, exp_files, FALSE);
+	    alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
     }
 
     alist_check_arg_idx();
@@ -1342,7 +1352,6 @@
 		    AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
 							  GARGLIST[i].ae_fnum;
 		    ++gap->ga_len;
-		    --gap->ga_room;
 		}
     }
 #endif
@@ -1579,7 +1588,6 @@
 	    mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
 			(size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
 	    ALIST(curwin)->al_ga.ga_len -= n;
-	    ALIST(curwin)->al_ga.ga_room += n;
 	    if (curwin->w_arg_idx >= eap->line2)
 		curwin->w_arg_idx -= n;
 	    else if (curwin->w_arg_idx > eap->line1)
@@ -1786,7 +1794,6 @@
 	    ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
 	}
 	ALIST(curwin)->al_ga.ga_len += count;
-	ALIST(curwin)->al_ga.ga_room -= count;
 	if (curwin->w_arg_idx >= after)
 	    ++curwin->w_arg_idx;
 	return after;
@@ -2365,7 +2372,6 @@
 	    {
 		SCRIPT_NAME(script_names.ga_len + 1) = NULL;
 		++script_names.ga_len;
-		--script_names.ga_room;
 	    }
 	    SCRIPT_NAME(current_SID) = fname_exp;
 # ifdef UNIX
@@ -2674,12 +2680,14 @@
 #ifdef USE_CR
 	if (sp->fileformat == EOL_MAC)
 	{
-	    if (fgets_cr((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
+	    if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
+							      sp->fp) == NULL)
 		break;
 	}
 	else
 #endif
-	    if (fgets((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
+	    if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
+							      sp->fp) == NULL)
 		break;
 	len = (int)STRLEN(buf);
 #ifdef USE_CRNL
@@ -2723,11 +2731,10 @@
 #endif
 
 	have_read = TRUE;
-	ga.ga_room -= len - ga.ga_len;
 	ga.ga_len = len;
 
 	/* If the line was longer than the buffer, read more. */
-	if (ga.ga_room == 1 && buf[len - 1] != '\n')
+	if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
 	    continue;
 
 	if (len >= 1 && buf[len - 1] == '\n')	/* remove trailing NL */
@@ -2749,7 +2756,6 @@
 		    buf[len - 2] = '\n';
 		    --len;
 		    --ga.ga_len;
-		    ++ga.ga_room;
 		}
 		else	    /* lines like ":map xx yy^M" will have failed */
 		{
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 82f90dd..3e5870b 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -112,12 +112,14 @@
 static int	getargopt __ARGS((exarg_T *eap));
 #ifndef FEAT_QUICKFIX
 # define ex_make		ex_ni
+# define ex_cbuffer		ex_ni
 # define ex_cc			ex_ni
 # define ex_cnext		ex_ni
 # define ex_cfile		ex_ni
 # define qf_list		ex_ni
 # define qf_age			ex_ni
 # define ex_helpgrep		ex_ni
+# define ex_vimgrep		ex_ni
 #endif
 #if !defined(FEAT_QUICKFIX) || !defined(FEAT_WINDOWS)
 # define ex_cclose		ex_ni
@@ -1469,7 +1471,6 @@
     ((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line);
     ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum;
     ++gap->ga_len;
-    --gap->ga_room;
     return OK;
 }
 
@@ -1484,7 +1485,6 @@
     {
 	vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line);
 	--gap->ga_len;
-	++gap->ga_room;
     }
 }
 #endif
@@ -2108,11 +2108,13 @@
 
 #ifdef FEAT_QUICKFIX
     /*
-     * For the :make and :grep commands we insert the 'makeprg'/'grepprg'
+     * For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg'
      * option here, so things like % get expanded.
+     * Don't do it when ":vimgrep" is used for ":grep".
      */
-    if (ea.cmdidx == CMD_make || ea.cmdidx == CMD_grep
-						  || ea.cmdidx == CMD_grepadd)
+    if ((ea.cmdidx == CMD_make
+			 || ea.cmdidx == CMD_grep || ea.cmdidx == CMD_grepadd)
+	    && !grep_internal(&ea))
     {
 	char_u		*new_cmdline;
 	char_u		*program;
@@ -4200,7 +4202,20 @@
 {
     char_u	*p;
 
-    for (p = eap->arg; *p; ++p)
+    p = eap->arg;
+#ifdef FEAT_QUICKFIX
+    if (eap->cmdidx == CMD_vimgrep
+	    || eap->cmdidx == CMD_vimgrepadd
+	    || grep_internal(eap))
+    {
+	/* Skip over the pattern. */
+	p = skip_regexp(p + 1, *p, TRUE, NULL);
+	if (*p == *eap->arg)
+	    ++p;
+    }
+#endif
+
+    for ( ; *p; mb_ptr_adv(p))
     {
 	if (*p == Ctrl_V)
 	{
@@ -4218,8 +4233,6 @@
 	{
 	    p += 2;
 	    (void)skip_expr(&p);
-	    if (*p == '`')
-		++p;
 	}
 #endif
 
@@ -4250,11 +4263,8 @@
 		break;
 	    }
 	}
-#ifdef FEAT_MBYTE
-	else if (has_mbyte)
-	    p += (*mb_ptr2len_check)(p) - 1; /* skip bytes of multi-byte char */
-#endif
     }
+
     if (!(eap->argt & NOTRLCOM))	/* remove trailing spaces */
 	del_trailing_spaces(eap->arg);
 }
@@ -4780,7 +4790,6 @@
 	mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T));
 
 	++gap->ga_len;
-	--gap->ga_room;
 
 	cmd->uc_name = p;
     }
@@ -5292,7 +5301,6 @@
 # endif
 
     --gap->ga_len;
-    ++gap->ga_room;
 
     if (i < gap->ga_len)
 	mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T));
@@ -6171,7 +6179,7 @@
     /*
      * Set up the new argument list.
      */
-    alist_set(ALIST(curwin), filec, filev, FALSE);
+    alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0);
 
     /*
      * Move to the first file.
@@ -6257,11 +6265,16 @@
 #if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) || defined(PROTO)
 /*
  * Expand the file names in the global argument list.
+ * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer
+ * numbers to be re-used.
  */
     void
-alist_expand()
+alist_expand(fnum_list, fnum_len)
+    int		*fnum_list;
+    int		fnum_len;
 {
     char_u	**old_arg_files;
+    int		old_arg_count;
     char_u	**new_arg_files;
     int		new_arg_file_count;
     char_u	*save_p_su = p_su;
@@ -6275,14 +6288,16 @@
     if (old_arg_files != NULL)
     {
 	for (i = 0; i < GARGCOUNT; ++i)
-	    old_arg_files[i] = GARGLIST[i].ae_fname;
-	if (expand_wildcards(GARGCOUNT, old_arg_files,
+	    old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname);
+	old_arg_count = GARGCOUNT;
+	if (expand_wildcards(old_arg_count, old_arg_files,
 		    &new_arg_file_count, &new_arg_files,
 		    EW_FILE|EW_NOTFOUND|EW_ADDSLASH) == OK
 		&& new_arg_file_count > 0)
 	{
-	    alist_set(&global_alist, new_arg_file_count, new_arg_files, TRUE);
-	    vim_free(old_arg_files);
+	    alist_set(&global_alist, new_arg_file_count, new_arg_files,
+						   TRUE, fnum_list, fnum_len);
+	    FreeWild(old_arg_count, old_arg_files);
 	}
     }
     p_su = save_p_su;
@@ -6294,11 +6309,13 @@
  * Takes over the allocated files[] and the allocated fnames in it.
  */
     void
-alist_set(al, count, files, use_curbuf)
+alist_set(al, count, files, use_curbuf, fnum_list, fnum_len)
     alist_T	*al;
     int		count;
     char_u	**files;
     int		use_curbuf;
+    int		*fnum_list;
+    int		fnum_len;
 {
     int		i;
 
@@ -6315,6 +6332,12 @@
 		    vim_free(files[i++]);
 		break;
 	    }
+
+	    /* May set buffer name of a buffer previously used for the
+	     * argument list, so that it's re-used by alist_add. */
+	    if (fnum_list != NULL && i < fnum_len)
+		buf_set_name(fnum_list[i], files[i]);
+
 	    alist_add(al, files[i], use_curbuf ? 2 : 1);
 	    ui_breakcheck();
 	}
@@ -6348,7 +6371,6 @@
 	AARGLIST(al)[al->al_ga.ga_len].ae_fnum =
 	    buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
     ++al->al_ga.ga_len;
-    --al->al_ga.ga_room;
 }
 
 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 8c15302..103bf1b 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -1964,7 +1964,6 @@
 			    char_u	*q;
 
 			    --line_ga.ga_len;
-			    ++line_ga.ga_room;
 			    /* compute column that cursor should be in */
 			    v = 0;
 			    q = ((char_u *)line_ga.ga_data);
@@ -1992,7 +1991,6 @@
 		    {
 			msg_col = startcol;
 			msg_clr_eos();
-			line_ga.ga_room += line_ga.ga_len;
 			line_ga.ga_len = 0;
 			continue;
 		    }
@@ -2024,7 +2022,6 @@
 		    vcol += char2cells(c1);
 		}
 		++line_ga.ga_len;
-		--line_ga.ga_room;
 		escaped = FALSE;
 	    }
 	    windgoto(msg_row, msg_col);
@@ -2036,7 +2033,6 @@
 #ifndef NO_COOKED_INPUT
 	{
 	    line_ga.ga_len += len;
-	    line_ga.ga_room -= len;
 	}
 #endif
 	p = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
@@ -4122,7 +4118,6 @@
 
 	((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s));
 	++ga.ga_len;
-	--ga.ga_room;
 
 	*e = keep;
 	if (*e != NUL)
@@ -4179,7 +4174,6 @@
 	    ((char_u **)ga.ga_data)[ga.ga_len] =
 					    vim_strnsave(s, (int)(e - s - 4));
 	    ++ga.ga_len;
-	    --ga.ga_room;
 	}
 	if (*e != NUL)
 	    ++e;
@@ -4247,7 +4241,6 @@
 			*cur++ = '\n';
 		    }
 		    ga.ga_len += len;
-		    ga.ga_room -= len;
 		}
 		FreeWild(num_p, p);
 	    }
diff --git a/src/fileio.c b/src/fileio.c
index 98d9cff..accd81c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6933,10 +6933,7 @@
 	if (AUGROUP_NAME(i) == NULL)
 	    return AUGROUP_ERROR;
 	if (i == augroups.ga_len)
-	{
 	    ++augroups.ga_len;
-	    --augroups.ga_room;
-	}
     }
 
     return i;
diff --git a/src/fold.c b/src/fold.c
index b1c7031..6c3334e 100644
--- a/src/fold.c
+++ b/src/fold.c
@@ -689,7 +689,6 @@
 	    /* Move contained folds to inside new fold. */
 	    mch_memmove(fold_ga.ga_data, fp, sizeof(fold_T) * cont);
 	    fold_ga.ga_len += cont;
-	    fold_ga.ga_room -= cont;
 	    i += cont;
 
 	    /* Adjust line numbers in contained folds to be relative to the
@@ -702,7 +701,6 @@
 	    mch_memmove(fp + 1, (fold_T *)gap->ga_data + i,
 				     sizeof(fold_T) * (gap->ga_len - i));
 	gap->ga_len = gap->ga_len + 1 - cont;
-	gap->ga_room = gap->ga_room - 1 + cont;
 
 	/* insert new fold */
 	fp->fd_nested = fold_ga;
@@ -1136,7 +1134,6 @@
 	to_p->fd_small = from_p->fd_small;
 	cloneFoldGrowArray(&from_p->fd_nested, &to_p->fd_nested);
 	++to->ga_len;
-	--to->ga_room;
 	++from_p;
 	++to_p;
     }
@@ -1455,7 +1452,6 @@
 	/* recursively delete the contained folds */
 	deleteFoldRecurse(&fp->fd_nested);
 	--gap->ga_len;
-	++gap->ga_room;
 	if (idx < gap->ga_len)
 	    mch_memmove(fp, fp + 1, sizeof(fold_T) * (gap->ga_len - idx));
     }
@@ -1485,7 +1481,6 @@
 	    mch_memmove(fp, nfp, (size_t)(sizeof(fold_T) * moved));
 	    vim_free(nfp);
 	    gap->ga_len += moved - 1;
-	    gap->ga_room -= moved - 1;
 	}
     }
 }
@@ -2762,7 +2757,6 @@
     if (i < gap->ga_len)
 	mch_memmove(fp + 1, fp, sizeof(fold_T) * (gap->ga_len - i));
     ++gap->ga_len;
-    --gap->ga_room;
     ga_init2(&fp->fd_nested, (int)sizeof(fold_T), 10);
     return OK;
 }
@@ -2812,9 +2806,7 @@
 						 -= fp[1].fd_top - fp->fd_top;
 	}
 	gap2->ga_len = len;
-	gap2->ga_room -= len;
 	gap1->ga_len -= len;
-	gap1->ga_room += len;
     }
     fp->fd_len = top - fp->fd_top;
     fold_changed = TRUE;
@@ -2931,10 +2923,8 @@
 					= ((fold_T *)gap2->ga_data)[idx];
 	    ((fold_T *)gap1->ga_data)[gap1->ga_len].fd_top += fp1->fd_len;
 	    ++gap1->ga_len;
-	    --gap1->ga_room;
 	}
 	gap2->ga_len = 0;
-	/* fp2->fd_nested.ga_room isn't updated, we delete it below */
     }
 
     fp1->fd_len += fp2->fd_len;
diff --git a/src/gui_gtk.c b/src/gui_gtk.c
index 4e4c1d9..e97dc4f 100644
--- a/src/gui_gtk.c
+++ b/src/gui_gtk.c
@@ -1348,6 +1348,8 @@
     return vim_strsave(p);
 }
 
+#if defined(HAVE_GTK2) || defined(PROTO)
+
 /*
  * Put up a directory selector
  * Returns the selected name in allocated memory, or NULL for Cancel.
@@ -1416,6 +1418,7 @@
     return gui_mch_browse(0, title, NULL, NULL, initdir, NULL);
 # endif
 }
+#endif
 
 #endif	/* FEAT_BROWSE */
 
diff --git a/src/if_xcmdsrv.c b/src/if_xcmdsrv.c
index b24101f..4a091bd 100644
--- a/src/if_xcmdsrv.c
+++ b/src/if_xcmdsrv.c
@@ -735,7 +735,6 @@
 	    ga_init2(&e.strings, 1, 100);
 	    memcpy(p, &e, sizeof(e));
 	    serverReply.ga_len++;
-	    serverReply.ga_room--;
 	}
     }
     else if (p != NULL && op == SROP_Delete)
@@ -743,7 +742,6 @@
 	ga_clear(&p->strings);
 	mch_memmove(p, p + 1, (serverReply.ga_len - i - 1) * sizeof(*p));
 	serverReply.ga_len--;
-	serverReply.ga_room++;
     }
 
     return p;
@@ -844,7 +842,6 @@
 	{
 	    s = (char_u *) p->strings.ga_data;
 	    mch_memmove(s, s + len, p->strings.ga_len - len);
-	    p->strings.ga_room += len;
 	    p->strings.ga_len -= len;
 	}
 	else
@@ -1276,7 +1273,6 @@
 		sprintf(reply.ga_data, "%cr%c-s %s%c-r ", 0, 0, serial, 0);
 #endif
 		reply.ga_len = 10 + STRLEN(serial);
-		reply.ga_room -= reply.ga_len;
 	    }
 	    res = NULL;
 	    if (serverName != NULL && STRICMP(name, serverName) == 0)
diff --git a/src/main.c b/src/main.c
index b35aaf9..d71ef60 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1137,7 +1137,7 @@
 	     * filename characters but are excluded from 'isfname' to make
 	     * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
 	    do_cmdline_cmd((char_u *)":set isf+=(,)");
-	    alist_expand();
+	    alist_expand(NULL, 0);
 	    do_cmdline_cmd((char_u *)":set isf&");
 	}
 #endif
diff --git a/src/mbyte.c b/src/mbyte.c
index e739a5b..8b997af 100644
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -692,11 +692,7 @@
     /* When changing 'encoding' while starting up, then convert the command
      * line arguments from the active codepage to 'encoding'. */
     if (starting != 0)
-    {
-	extern void fix_arg_enc(void);
-
 	fix_arg_enc();
-    }
 #endif
 
 #ifdef FEAT_AUTOCMD
diff --git a/src/menu.c b/src/menu.c
index aeb3c61..17d4371 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -2306,7 +2306,6 @@
 		    tp[menutrans_ga.ga_len].from_noamp = from_noamp;
 		    tp[menutrans_ga.ga_len].to = to;
 		    ++menutrans_ga.ga_len;
-		    --menutrans_ga.ga_room;
 		}
 		else
 		{
diff --git a/src/message.c b/src/message.c
index 6a23864..58e4ffb 100644
--- a/src/message.c
+++ b/src/message.c
@@ -2275,7 +2275,6 @@
 #endif
 	--len;		/* don't count the NUL at the end */
 	error_ga.ga_len += len;
-	error_ga.ga_room -= len;
     }
 }
 
diff --git a/src/misc1.c b/src/misc1.c
index 891fbb5..0bdcce8 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -382,30 +382,36 @@
 /*
  * Return the indent of the current line after a number.  Return -1 if no
  * number was found.  Used for 'n' in 'formatoptions': numbered list.
+ * Since a pattern is used it can actually handle more than numbers.
  */
     int
 get_number_indent(lnum)
     linenr_T	lnum;
 {
-    char_u	*line;
-    char_u	*p;
     colnr_T	col;
     pos_T	pos;
+    regmmatch_T	regmatch;
 
     if (lnum > curbuf->b_ml.ml_line_count)
 	return -1;
-    line = ml_get(lnum);
-    p = skipwhite(line);
-    if (!VIM_ISDIGIT(*p))
+    pos.lnum = 0;
+    regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
+    if (regmatch.regprog != NULL)
+    {
+	regmatch.rmm_ic = FALSE;
+	if (vim_regexec_multi(&regmatch, curwin, curbuf, lnum, (colnr_T)0))
+	{
+	    pos.lnum = regmatch.endpos[0].lnum + lnum;
+	    pos.col = regmatch.endpos[0].col;
+#ifdef FEAT_VIRTUALEDIT
+	    pos.coladd = 0;
+#endif
+	}
+	vim_free(regmatch.regprog);
+    }
+
+    if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
 	return -1;
-    p = skipdigits(p);
-    if (vim_strchr((char_u *)":.)]}\t ", *p) == NULL)
-	return -1;
-    p = skipwhite(p + 1);
-    if (*p == NUL)
-	return -1;
-    pos.lnum = lnum;
-    pos.col = (colnr_T)(p - line);
     getvcol(curwin, &pos, &col, NULL, NULL);
     return (int)col;
 }
@@ -3804,9 +3810,9 @@
     char_u	*newend = pend - len;
 
     if (newend >= p && fnamencmp(newend, ext, len - 1) == 0)
-	while (newend != p && !after_pathsep(newend))
-	    mb_ptr_back(newend);
-    if (newend == p || after_pathsep(newend))
+	while (newend > p && !after_pathsep(p, newend))
+	    mb_ptr_back(p, newend);
+    if (newend == p || after_pathsep(p, newend))
 	return newend;
     return pend;
 }
@@ -8447,7 +8453,6 @@
 	add_pathsep(p);
 #endif
     ((char_u **)gap->ga_data)[gap->ga_len++] = p;
-    --gap->ga_room;
 }
 #endif /* !NO_EXPANDPATH */
 
diff --git a/src/misc2.c b/src/misc2.c
index 7a85026..30e1a1f 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1525,7 +1525,7 @@
     garray_T *gap;
 {
     gap->ga_data = NULL;
-    gap->ga_room = 0;
+    gap->ga_maxlen = 0;
     gap->ga_len = 0;
 }
 
@@ -1552,7 +1552,7 @@
     size_t	len;
     char_u	*pp;
 
-    if (gap->ga_room < n)
+    if (gap->ga_maxlen - gap->ga_len < n)
     {
 	if (n < gap->ga_growsize)
 	    n = gap->ga_growsize;
@@ -1560,7 +1560,7 @@
 	pp = alloc_clear((unsigned)len);
 	if (pp == NULL)
 	    return FAIL;
-	gap->ga_room = n;
+	gap->ga_maxlen = gap->ga_len + n;
 	if (gap->ga_data != NULL)
 	{
 	    mch_memmove(pp, gap->ga_data,
@@ -1587,7 +1587,6 @@
     {
 	mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
 	gap->ga_len += len;
-	gap->ga_room -= len;
     }
 }
 
@@ -1603,7 +1602,6 @@
     {
 	*((char *)gap->ga_data + gap->ga_len) = c;
 	++gap->ga_len;
-	--gap->ga_room;
     }
 }
 
@@ -5224,7 +5222,7 @@
     int maxlen;
 {
     int		i;
-    const char	*s;
+    const char	*s = NULL;
 
     for (i = 0; maxlen < 0 || i < maxlen; ++i)
     {
@@ -5264,18 +5262,19 @@
 	    return ((char_u *)p)[i] - ((char_u *)q)[i];	    /* no match */
 	}
     }
+    if (s == NULL)	/* "i" ran into "maxlen" */
+	return 0;
 
     /* ignore a trailing slash, but not "//" or ":/" */
-    if (i >= maxlen
-	    || (s[i + 1] == NUL
-		&& i > 0
-		&& !after_pathsep((char_u *)s, (char_u *)s + i)
+    if (s[i + 1] == NUL
+	    && i > 0
+	    && !after_pathsep((char_u *)s, (char_u *)s + i)
 #ifdef BACKSLASH_IN_FILENAME
-		&& (s[i] == '/' || s[i] == '\\')
+	    && (s[i] == '/' || s[i] == '\\')
 #else
-		&& s[i] == '/'
+	    && s[i] == '/'
 #endif
-	       ))
+       )
 	return 0;   /* match with trailing slash */
     if (s == q)
 	return -1;	    /* no match */
diff --git a/src/option.c b/src/option.c
index 3cb91a4..2bfeec3 100644
--- a/src/option.c
+++ b/src/option.c
@@ -82,6 +82,7 @@
     , PV_FF
     , PV_FML
     , PV_FMR
+    , PV_FLP
     , PV_FO
     , PV_FT
     , PV_GP
@@ -183,6 +184,7 @@
 #endif
 static char_u	*p_ff;
 static char_u	*p_fo;
+static char_u	*p_flp;
 #ifdef FEAT_AUTOCMD
 static char_u	*p_ft;
 #endif
@@ -952,6 +954,9 @@
     {"formatoptions","fo",  P_STRING|P_ALLOCED|P_VIM|P_FLAGLIST,
 			    (char_u *)&p_fo, PV_FO,
 			    {(char_u *)DFLT_FO_VI, (char_u *)DFLT_FO_VIM}},
+    {"formatlistpat","flp", P_STRING|P_ALLOCED|P_VI_DEF,
+			    (char_u *)&p_flp, PV_FLP,
+			    {(char_u *)"^\\s*\\d\\+[\\]:.)}\\t ]\\s*", (char_u *)0L}},
     {"formatprg",   "fp",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 			    (char_u *)&p_fp, PV_NONE,
 			    {(char_u *)"", (char_u *)0L}},
@@ -2636,7 +2641,6 @@
 		    STRCAT(ga.ga_data, p);
 		    add_pathsep(ga.ga_data);
 		    STRCAT(ga.ga_data, "*");
-		    ga.ga_room -= len;
 		    ga.ga_len += len;
 		}
 	    }
@@ -4487,6 +4491,7 @@
     check_string_option(&buf->b_p_kp);
     check_string_option(&buf->b_p_mps);
     check_string_option(&buf->b_p_fo);
+    check_string_option(&buf->b_p_flp);
     check_string_option(&buf->b_p_isk);
 #ifdef FEAT_COMMENTS
     check_string_option(&buf->b_p_com);
@@ -8082,6 +8087,7 @@
 	case PV_FT:	return (char_u *)&(curbuf->b_p_ft);
 #endif
 	case PV_FO:	return (char_u *)&(curbuf->b_p_fo);
+	case PV_FLP:	return (char_u *)&(curbuf->b_p_flp);
 	case PV_IMI:	return (char_u *)&(curbuf->b_p_iminsert);
 	case PV_IMS:	return (char_u *)&(curbuf->b_p_imsearch);
 	case PV_INF:	return (char_u *)&(curbuf->b_p_inf);
@@ -8404,6 +8410,7 @@
 	    buf->b_p_cms = vim_strsave(p_cms);
 #endif
 	    buf->b_p_fo = vim_strsave(p_fo);
+	    buf->b_p_flp = vim_strsave(p_flp);
 	    buf->b_p_nf = vim_strsave(p_nf);
 	    buf->b_p_mps = vim_strsave(p_mps);
 #ifdef FEAT_SMARTINDENT
diff --git a/src/os_mswin.c b/src/os_mswin.c
index cea1054..f2a6c90 100644
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -2908,7 +2908,6 @@
 
 #define REPLY_ITEM(i) ((reply_T *)(reply_list.ga_data) + (i))
 #define REPLY_COUNT (reply_list.ga_len)
-#define REPLY_ROOM (reply_list.ga_room)
 
 /* Flag which is used to wait for a reply */
 static int reply_received = 0;
@@ -2932,7 +2931,6 @@
 	return FAIL;
 
     ++REPLY_COUNT;
-    --REPLY_ROOM;
     reply_received = 1;
     return OK;
 }
@@ -2976,7 +2974,6 @@
 		    mch_memmove(rep, rep + 1,
 				     (REPLY_COUNT - i - 1) * sizeof(reply_T));
 		    --REPLY_COUNT;
-		    ++REPLY_ROOM;
 		}
 
 		/* Return the reply to the caller, who takes on responsibility
diff --git a/src/os_win32.c b/src/os_win32.c
index 40544b2..a50f5d9 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -4988,6 +4988,7 @@
     int		i;
     int		idx;
     char_u	*str;
+    int		*fnum_list;
 
     /* Safety checks:
      * - if argument count differs between the wide and non-wide argument
@@ -5002,17 +5003,31 @@
 	    || used_alist_count != GARGCOUNT)
 	return;
 
+    /* Remember the buffer numbers for the arguments. */
+    fnum_list = (int *)alloc((int)sizeof(int) * GARGCOUNT);
+    if (fnum_list == NULL)
+	return;		/* out of memory */
+    for (i = 0; i < GARGCOUNT; ++i)
+	fnum_list[i] = GARGLIST[i].ae_fnum;
+
     /* Clear the argument list.  Make room for the new arguments. */
     alist_clear(&global_alist);
     if (ga_grow(&global_alist.al_ga, used_file_count) == FAIL)
-	return;	    /* out of memory */
+	return;		/* out of memory */
 
     for (i = 0; i < used_file_count; ++i)
     {
 	idx = used_file_indexes[i];
 	str = ucs2_to_enc(ArglistW[idx], NULL);
 	if (str != NULL)
+	{
+	    /* Re-use the old buffer by renaming it.  When not using literal
+	     * names it's done by alist_expand() below. */
+	    if (used_file_literal)
+		buf_set_name(fnum_list[i], str);
+
 	    alist_add(&global_alist, str, used_file_literal ? 2 : 0);
+	}
     }
 
     if (!used_file_literal)
@@ -5022,7 +5037,7 @@
 	 * filename characters but are excluded from 'isfname' to make
 	 * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
 	do_cmdline_cmd((char_u *)":let SaVe_ISF = &isf|set isf+=(,)");
-	alist_expand();
+	alist_expand(fnum_list, used_alist_count);
 	do_cmdline_cmd((char_u *)":let &isf = SaVe_ISF|unlet SaVe_ISF");
     }
 
@@ -5034,5 +5049,7 @@
 	if (GARGCOUNT == 1 && used_file_full_path)
 	    (void)vim_chdirfile(alist_name(&GARGLIST[0]));
     }
+
+    set_alist_count();
 }
 #endif
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 861fba2..4f00e9c 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -25,6 +25,7 @@
 void buflist_list __ARGS((exarg_T *eap));
 int buflist_name_nr __ARGS((int fnum, char_u **fname, linenr_T *lnum));
 int setfname __ARGS((buf_T *buf, char_u *ffname, char_u *sfname, int message));
+void buf_set_name __ARGS((int fnum, char_u *name));
 void buf_name_changed __ARGS((buf_T *buf));
 buf_T *setaltfname __ARGS((char_u *ffname, char_u *sfname, linenr_T lnum));
 char_u *getaltfname __ARGS((int errmsg));
diff --git a/src/proto/ex_cmds2.pro b/src/proto/ex_cmds2.pro
index c66c702..304bbef 100644
--- a/src/proto/ex_cmds2.pro
+++ b/src/proto/ex_cmds2.pro
@@ -18,6 +18,7 @@
 int check_changed_any __ARGS((int hidden));
 int check_fname __ARGS((void));
 int buf_write_all __ARGS((buf_T *buf, int forceit));
+int get_arglist __ARGS((garray_T *gap, char_u *str));
 void set_arglist __ARGS((char_u *str));
 void check_arg_idx __ARGS((win_T *win));
 void ex_args __ARGS((exarg_T *eap));
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index b6f3b7a..9fabda4 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -25,8 +25,8 @@
 void alist_init __ARGS((alist_T *al));
 void alist_unlink __ARGS((alist_T *al));
 void alist_new __ARGS((void));
-void alist_expand __ARGS((void));
-void alist_set __ARGS((alist_T *al, int count, char_u **files, int use_curbuf));
+void alist_expand __ARGS((int *fnum_list, int fnum_len));
+void alist_set __ARGS((alist_T *al, int count, char_u **files, int use_curbuf, int *fnum_list, int fnum_len));
 void alist_add __ARGS((alist_T *al, char_u *fname, int set_fnum));
 void alist_slash_adjust __ARGS((void));
 void ex_splitview __ARGS((exarg_T *eap));
diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro
index c1d619d..adec72f 100644
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -13,9 +13,12 @@
 int bt_dontwrite __ARGS((buf_T *buf));
 int bt_dontwrite_msg __ARGS((buf_T *buf));
 int buf_hide __ARGS((buf_T *buf));
+int grep_internal __ARGS((exarg_T *eap));
 void ex_make __ARGS((exarg_T *eap));
 void ex_cc __ARGS((exarg_T *eap));
 void ex_cnext __ARGS((exarg_T *eap));
 void ex_cfile __ARGS((exarg_T *eap));
+void ex_vimgrep __ARGS((exarg_T *eap));
+void ex_cbuffer __ARGS((exarg_T *eap));
 void ex_helpgrep __ARGS((exarg_T *eap));
 /* vim: set ft=c : */
diff --git a/src/quickfix.c b/src/quickfix.c
index 0cb9c69..dbde155 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -86,6 +86,7 @@
 				/*   '-' do not include this line */
 };
 
+static int qf_init_ext __ARGS((char_u *efile, buf_T *buf, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
 static void	qf_new_list __ARGS((void));
 static int	qf_add_entry __ARGS((struct qf_line **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int virt_col, int nr, int type, int valid));
 static void	qf_msg __ARGS((void));
@@ -106,7 +107,8 @@
 static char_u	*get_mef_name __ARGS((void));
 
 /*
- * Read the errorfile into memory, line by line, building the error list.
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
  * Return -1 for error, number of errors for success.
  */
     int
@@ -115,6 +117,29 @@
     char_u	    *errorformat;
     int		    newlist;		/* TRUE: start a new error list */
 {
+    if (efile == NULL)
+	return FAIL;
+    return qf_init_ext(efile, curbuf, errorformat, newlist,
+						    (linenr_T)0, (linenr_T)0);
+}
+
+/*
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
+ * Alternative: when "efile" is null read errors from buffer "buf".
+ * Always use 'errorformat' from "buf" if there is a local value.
+ * Then lnumfirst and lnumlast specify the range of lines to use.
+ * Return -1 for error, number of errors for success.
+ */
+    static int
+qf_init_ext(efile, buf, errorformat, newlist, lnumfirst, lnumlast)
+    char_u	    *efile;
+    buf_T	    *buf;
+    char_u	    *errorformat;
+    int		    newlist;		/* TRUE: start a new error list */
+    linenr_T	    lnumfirst;		/* first line number to use */
+    linenr_T	    lnumlast;		/* last line number to use */
+{
     char_u	    *namebuf;
     char_u	    *errmsg;
     char_u	    *fmtstr = NULL;
@@ -122,9 +147,10 @@
     char_u	    use_virt_col = FALSE;
     int		    type = 0;
     int		    valid;
+    linenr_T	    buflnum = lnumfirst;
     long	    lnum = 0L;
     int		    enr = 0;
-    FILE	    *fd;
+    FILE	    *fd = NULL;
     struct qf_line  *qfprev = NULL;	/* init to make SASC shut up */
     char_u	    *efmp;
     struct eformat  *fmt_first = NULL;
@@ -163,15 +189,12 @@
 			{'v', "\\d\\+"}
 		    };
 
-    if (efile == NULL)
-	return FAIL;
-
     namebuf = alloc(CMDBUFFSIZE + 1);
     errmsg = alloc(CMDBUFFSIZE + 1);
     if (namebuf == NULL || errmsg == NULL)
 	goto qf_init_end;
 
-    if ((fd = mch_fopen((char *)efile, "r")) == NULL)
+    if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL)
     {
 	EMSG2(_(e_openerrf), efile);
 	goto qf_init_end;
@@ -191,8 +214,8 @@
  * regex prog.  Only a few % characters are allowed.
  */
     /* Use the local value of 'errorformat' if it's set. */
-    if (errorformat == p_efm && *curbuf->b_p_efm != NUL)
-	efm = curbuf->b_p_efm;
+    if (errorformat == p_efm && *buf->b_p_efm != NUL)
+	efm = buf->b_p_efm;
     else
 	efm = errorformat;
     /*
@@ -405,8 +428,18 @@
      * Read the lines in the error file one by one.
      * Try to recognize one of the error formats in each line.
      */
-    while (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) != NULL && !got_int)
+    while (!got_int)
     {
+	/* Get the next line. */
+	if (fd == NULL)
+	{
+	    if (buflnum > lnumlast)
+		break;
+	    STRNCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE), CMDBUFFSIZE - 2);
+	}
+	else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
+	    break;
+
 	IObuff[CMDBUFFSIZE - 2] = NUL;  /* for very long lines */
 	if ((efmp = vim_strrchr(IObuff, '\n')) != NULL)
 	    *efmp = NUL;
@@ -594,7 +627,7 @@
 	    goto error2;
 	line_breakcheck();
     }
-    if (!ferror(fd))
+    if (fd == NULL || !ferror(fd))
     {
 	if (qf_lists[qf_curlist].qf_index == 0)	/* no valid entry found */
 	{
@@ -618,7 +651,8 @@
     if (qf_curlist > 0)
 	--qf_curlist;
 qf_init_ok:
-    fclose(fd);
+    if (fd != NULL)
+	fclose(fd);
     for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
     {
 	fmt_first = fmt_ptr->next;
@@ -2026,6 +2060,18 @@
 }
 
 /*
+ * Return TRUE when using ":vimgrep" for ":grep".
+ */
+    int
+grep_internal(eap)
+    exarg_T	*eap;
+{
+    return ((eap->cmdidx == CMD_grep || eap->cmdidx == CMD_grepadd)
+	    && STRCMP("internal",
+			*curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
+}
+
+/*
  * Used for ":make", ":grep" and ":grepadd".
  */
     void
@@ -2036,6 +2082,13 @@
     char_u	*cmd;
     unsigned	len;
 
+    /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */
+    if (grep_internal(eap))
+    {
+	ex_vimgrep(eap);
+	return;
+    }
+
     autowrite_all();
     name = get_mef_name();
     if (name == NULL)
@@ -2075,7 +2128,7 @@
 #endif
 
     if (qf_init(name, eap->cmdidx != CMD_make ? p_gefm : p_efm,
-					      eap->cmdidx != CMD_grepadd) > 0
+					       eap->cmdidx != CMD_grepadd) > 0
 	    && !eap->forceit)
 	qf_jump(0, 0, FALSE);		/* display first error */
 
@@ -2190,6 +2243,171 @@
 }
 
 /*
+ * ":vimgrep {pattern} file(s)"
+ */
+    void
+ex_vimgrep(eap)
+    exarg_T	*eap;
+{
+    regmatch_T	regmatch;
+    char_u	*save_cpo;
+    int         fcount;
+    char_u	**fnames;
+    char_u      *p;
+    int		i;
+    FILE	*fd;
+    int         fi;
+    struct qf_line *prevp = NULL;
+    long	lnum;
+    garray_T	ga;
+
+    /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
+    save_cpo = p_cpo;
+    p_cpo = empty_option;
+
+    /* Get the search pattern */
+    regmatch.regprog = NULL;
+    p = skip_regexp(eap->arg + 1, *eap->arg, TRUE, NULL);
+    if (*p != *eap->arg)
+    {
+	EMSG(_("E682: Invalid search pattern or delimiter"));
+	goto theend;
+    }
+    *p++ = NUL;
+    regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC);
+    if (regmatch.regprog == NULL)
+	goto theend;
+    regmatch.rm_ic = FALSE;
+
+    p = skipwhite(p);
+    if (*p == NUL)
+    {
+	EMSG(_("E683: File name missing or invalid pattern"));
+	goto theend;
+    }
+
+    if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_vimgrepadd)
+						|| qf_curlist == qf_listcount)
+	/* make place for a new list */
+	qf_new_list();
+    else if (qf_lists[qf_curlist].qf_count > 0)
+	/* Adding to existing list, find last entry. */
+	for (prevp = qf_lists[qf_curlist].qf_start;
+			    prevp->qf_next != prevp; prevp = prevp->qf_next)
+	    ;
+
+    /* parse the list of arguments */
+    if (get_arglist(&ga, p) == FAIL)
+	goto theend;
+    i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+				       &fcount, &fnames, EW_FILE|EW_NOTFOUND);
+    ga_clear(&ga);
+    if (i == FAIL)
+	goto theend;
+    if (fcount == 0)
+    {
+	EMSG(_(e_nomatch));
+	goto theend;
+    }
+
+    for (fi = 0; fi < fcount && !got_int; ++fi)
+    {
+	fd = fopen((char *)fnames[fi], "r");
+	if (fd == NULL)
+	    smsg((char_u *)_("Cannot open file \"%s\""), fnames[fi]);
+	else
+	{
+	    lnum = 1;
+	    while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
+	    {
+		if (vim_regexec(&regmatch, IObuff, (colnr_T)0))
+		{
+		    int     l = STRLEN(IObuff);
+
+		    /* remove trailing CR, LF, spaces, etc. */
+		    while (l > 0 && IObuff[l - 1] <= ' ')
+			IObuff[--l] = NUL;
+
+		    if (qf_add_entry(&prevp,
+				NULL,       /* dir */
+				fnames[fi],
+				IObuff,
+				lnum,
+				(int)(regmatch.startp[0] - IObuff) + 1,/* col */
+				FALSE,      /* virt_col */
+				0,          /* nr */
+				0,          /* type */
+				TRUE        /* valid */
+				) == FAIL)
+		    {
+			got_int = TRUE;
+			break;
+		    }
+		}
+		++lnum;
+		line_breakcheck();
+	    }
+	    fclose(fd);
+	}
+    }
+
+    FreeWild(fcount, fnames);
+
+    qf_lists[qf_curlist].qf_nonevalid = FALSE;
+    qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
+    qf_lists[qf_curlist].qf_index = 1;
+
+#ifdef FEAT_WINDOWS
+    qf_update_buffer();
+#endif
+
+    /* Jump to first match. */
+    if (qf_lists[qf_curlist].qf_count > 0)
+	qf_jump(0, 0, FALSE);
+
+theend:
+    vim_free(regmatch.regprog);
+
+    /* Only resture 'cpo' when it wasn't set in the mean time. */
+    if (p_cpo == empty_option)
+	p_cpo = save_cpo;
+    else
+	free_string_option(save_cpo);
+}
+
+/*
+ * ":[range]cbuffer [bufnr]" command.
+ */
+    void
+ex_cbuffer(eap)
+    exarg_T   *eap;
+{
+    buf_T	*buf = NULL;
+
+    if (*eap->arg == NUL)
+	buf = curbuf;
+    else if (*skipwhite(skipdigits(eap->arg)) == NUL)
+	buf = buflist_findnr(atoi((char *)eap->arg));
+    if (buf == NULL)
+	EMSG(_(e_invarg));
+    else if (buf->b_ml.ml_mfp == NULL)
+	EMSG(_("E681: Buffer is not loaded"));
+    else
+    {
+	if (eap->addr_count == 0)
+	{
+	    eap->line1 = 1;
+	    eap->line2 = buf->b_ml.ml_line_count;
+	}
+	if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
+		|| eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
+	    EMSG(_(e_invrange));
+	else
+	    qf_init_ext(NULL, buf, p_efm, TRUE, eap->line1, eap->line2);
+    }
+}
+
+/*
  * ":helpgrep {pattern}"
  */
     void
diff --git a/src/regexp.c b/src/regexp.c
index 2e82854..4aa5b6a 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -726,7 +726,7 @@
 
 /*
  * Skip past regular expression.
- * Stop at end of 'p' of where 'dirc' is found ('/', '?', etc).
+ * Stop at end of 'p' or where 'dirc' is found ('/', '?', etc).
  * Take care of characters with a backslash in front of it.
  * Skip strings inside [ and ].
  * When "newp" is not NULL and "dirc" is '?', make an allocated copy of the
@@ -787,7 +787,8 @@
 }
 
 /*
- * vim_regcomp - compile a regular expression into internal code
+ * vim_regcomp() - compile a regular expression into internal code
+ * Returns the program in allocated space.  Returns NULL for an error.
  *
  * We can't allocate space until we know how big the compiled form will be,
  * but we can't compile it (and thus know how big it is) until we've got a
diff --git a/src/structs.h b/src/structs.h
index 84b1a24..3d71393 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -55,7 +55,7 @@
 typedef struct growarray
 {
     int	    ga_len;		    /* current number of items used */
-    int	    ga_room;		    /* number of unused items at the end */
+    int	    ga_maxlen;		    /* maximum number of items possible */
     int	    ga_itemsize;	    /* sizeof(item) */
     int	    ga_growsize;	    /* number of items to grow each time */
     void    *ga_data;		    /* pointer to the first item */
@@ -1127,6 +1127,7 @@
     char_u	*b_p_ft;	/* 'filetype' */
 #endif
     char_u	*b_p_fo;	/* 'formatoptions' */
+    char_u	*b_p_flp;	/* 'formatlistpat' */
     int		b_p_inf;	/* 'infercase' */
     char_u	*b_p_isk;	/* 'iskeyword' */
 #ifdef FEAT_FIND_ID
diff --git a/src/syntax.c b/src/syntax.c
index 0c706c8..91ef7cd 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -1394,10 +1394,7 @@
 	    if (ga_grow(&sp->sst_union.sst_ga, current_state.ga_len) == FAIL)
 		sp->sst_stacksize = 0;
 	    else
-	    {
 		sp->sst_union.sst_ga.ga_len = current_state.ga_len;
-		sp->sst_union.sst_ga.ga_room -= current_state.ga_len;
-	    }
 	    bp = SYN_STATE_P(&(sp->sst_union.sst_ga));
 	}
 	else
@@ -1454,7 +1451,6 @@
 	    update_si_attr(i);
 	}
 	current_state.ga_len = from->sst_stacksize;
-	current_state.ga_room -= current_state.ga_len;
     }
     current_next_list = from->sst_next_list;
     current_next_flags = from->sst_next_flags;
@@ -2089,7 +2085,6 @@
 			{
 			    ((int *)(zero_width_next_ga.ga_data))
 				[zero_width_next_ga.ga_len++] = next_match_idx;
-			    --zero_width_next_ga.ga_room;
 			}
 			next_match_idx = -1;
 		    }
@@ -2579,7 +2574,6 @@
     vim_memset(&CUR_STATE(current_state.ga_len), 0, sizeof(stateitem_T));
     CUR_STATE(current_state.ga_len).si_idx = idx;
     ++current_state.ga_len;
-    --current_state.ga_room;
     return OK;
 }
 
@@ -2593,7 +2587,6 @@
     {
 	unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch);
 	--current_state.ga_len;
-	++current_state.ga_room;
     }
     /* after the end of a pattern, try matching a keyword or pattern */
     next_match_idx = -1;
@@ -3151,7 +3144,6 @@
     mch_memmove(spp, spp + 1,
 		   sizeof(synpat_T) * (buf->b_syn_patterns.ga_len - idx - 1));
     --buf->b_syn_patterns.ga_len;
-    --buf->b_syn_patterns.ga_room;
 }
 
 /*
@@ -4499,7 +4491,6 @@
 		curbuf->b_syn_containedin = TRUE;
 	    SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
 	    ++curbuf->b_syn_patterns.ga_len;
-	    --curbuf->b_syn_patterns.ga_room;
 
 	    /* remember that we found a match for syncing on */
 	    if (flags & (HL_SYNC_HERE|HL_SYNC_THERE))
@@ -4742,7 +4733,6 @@
 			SYN_ITEMS(curbuf)[idx].sp_next_list = next_list;
 		    }
 		    ++curbuf->b_syn_patterns.ga_len;
-		    --curbuf->b_syn_patterns.ga_room;
 		    ++idx;
 #ifdef FEAT_FOLDING
 		    if (flags & HL_FOLD)
@@ -5033,7 +5023,6 @@
     SYN_CLSTR(curbuf)[len].scl_name_u = vim_strsave_up(name);
     SYN_CLSTR(curbuf)[len].scl_list = NULL;
     ++curbuf->b_syn_clusters.ga_len;
-    --curbuf->b_syn_clusters.ga_room;
 
     return len + SYNID_CLUSTER;
 }
@@ -7467,7 +7456,6 @@
 	gap->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
     }
     ++table->ga_len;
-    --table->ga_room;
     return (table->ga_len - 1 + ATTR_OFF);
 }
 
@@ -7972,7 +7960,6 @@
     HL_TABLE()[highlight_ga.ga_len].sg_gui_fg = INVALCOLOR;
 #endif
     ++highlight_ga.ga_len;
-    --highlight_ga.ga_room;
 
     return highlight_ga.ga_len;		    /* ID is index plus one */
 }
@@ -7985,7 +7972,6 @@
 syn_unadd_group()
 {
     --highlight_ga.ga_len;
-    ++highlight_ga.ga_room;
     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name);
     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
 }
diff --git a/src/tag.c b/src/tag.c
index b72cf03..a3bed7a 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -2174,7 +2174,6 @@
 			{
 			    ((struct match_found **)(ga_match[mtt].ga_data))
 					       [ga_match[mtt].ga_len++] = mfp;
-			    ga_match[mtt].ga_room--;
 			    ++match_count;
 			}
 			else
@@ -2345,11 +2344,8 @@
     char_u	*fname;
 {
     if (ga_grow(&tag_fnames, 1) == OK)
-    {
 	((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] =
 							   vim_strsave(fname);
-	--tag_fnames.ga_room;
-    }
 }
 
 /*
diff --git a/src/term.c b/src/term.c
index 8144fad..a471c1e 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2978,6 +2978,9 @@
 	Rows = min_rows();
 }
 
+/*
+ * Invoked just before the screen structures are going to be (re)allocated.
+ */
     void
 win_new_shellsize()
 {