updated for version 7.0117
diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak
index 44f58fb..2326c30 100644
--- a/src/Make_ivc.mak
+++ b/src/Make_ivc.mak
@@ -88,8 +88,8 @@
 CPP_PROJ= /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c
 # ADD CPP /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c
 
-LINK32_FLAGS= oldnames.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
-# ADD LINK32  oldnames.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
+LINK32_FLAGS= oldnames.lib kernel32.lib user32.lib gdi32.lib version.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
+# ADD LINK32  oldnames.lib kernel32.lib user32.lib gdi32.lib version.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
 # SUBTRACT LINK32 /incremental:yes
 
 RSC_PROJ= /l 0x409 /d "FEAT_GUI_W32"
diff --git a/src/Makefile b/src/Makefile
index 83732a2..2a74f4e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -879,6 +879,7 @@
 COLSUBDIR = /colors
 SYNSUBDIR = /syntax
 INDSUBDIR = /indent
+AUTOSUBDIR = /autoload
 PLUGSUBDIR = /plugin
 FTPLUGSUBDIR = /ftplugin
 LANGSUBDIR = /lang
@@ -899,6 +900,7 @@
 ### COLSUBLOC	location for colorscheme files
 ### SYNSUBLOC	location for syntax files
 ### INDSUBLOC	location for indent files
+### AUTOSUBLOC	location for standard autoload files
 ### PLUGSUBLOC	location for standard plugin files
 ### FTPLUGSUBLOC  location for ftplugin files
 ### LANGSUBLOC	location for language files
@@ -919,6 +921,7 @@
 COLSUBLOC	= $(VIMRTLOC)$(COLSUBDIR)
 SYNSUBLOC	= $(VIMRTLOC)$(SYNSUBDIR)
 INDSUBLOC	= $(VIMRTLOC)$(INDSUBDIR)
+AUTOSUBLOC	= $(VIMRTLOC)$(AUTOSUBDIR)
 PLUGSUBLOC	= $(VIMRTLOC)$(PLUGSUBDIR)
 FTPLUGSUBLOC	= $(VIMRTLOC)$(FTPLUGSUBDIR)
 LANGSUBLOC	= $(VIMRTLOC)$(LANGSUBDIR)
@@ -1018,6 +1021,9 @@
 INDSOURCE = ../runtime/indent
 
 # Where to copy the standard plugin files from
+AUTOSOURCE = ../runtime/autoload
+
+# Where to copy the standard plugin files from
 PLUGSOURCE = ../runtime/plugin
 
 # Where to copy the ftplugin files from
@@ -1290,6 +1296,7 @@
 DEST_COL = $(DESTDIR)$(COLSUBLOC)
 DEST_SYN = $(DESTDIR)$(SYNSUBLOC)
 DEST_IND = $(DESTDIR)$(INDSUBLOC)
+DEST_AUTO = $(DESTDIR)$(AUTOSUBLOC)
 DEST_PLUG = $(DESTDIR)$(PLUGSUBLOC)
 DEST_FTP = $(DESTDIR)$(FTPLUGSUBLOC)
 DEST_LANG = $(DESTDIR)$(LANGSUBLOC)
@@ -1739,7 +1746,8 @@
 # install the help files; first adjust the contents for the final location
 installruntime: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \
 		$(DEST_HELP) $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) \
-		$(DEST_FTP) $(DEST_PLUG) $(DEST_TUTOR) $(DEST_SPELL) $(DEST_COMP)
+		$(DEST_FTP) $(DEST_AUTO) $(DEST_PLUG) $(DEST_TUTOR) \
+		$(DEST_SPELL) $(DEST_COMP)
 	-$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS)
 	@echo generating help tags
 # Generate the help tags with ":helptags" to handle all languages.
@@ -1801,6 +1809,9 @@
 # install the indent files
 	cd $(INDSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_IND)
 	cd $(DEST_IND); chmod $(HELPMOD) *.vim README.txt
+# install the standard autoload files
+	cd $(AUTOSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_AUTO)
+	cd $(DEST_AUTO); chmod $(HELPMOD) *.vim README.txt
 # install the standard plugin files
 	cd $(PLUGSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_PLUG)
 	cd $(DEST_PLUG); chmod $(HELPMOD) *.vim README.txt
@@ -1965,7 +1976,7 @@
 		$(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) $(DEST_FTP) \
 		$(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) \
 		$(DEST_MACRO) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \
-		$(DEST_PLUG):
+		$(DEST_AUTO) $(DEST_PLUG):
 	-$(SHELL) ./mkinstalldirs $@
 	-chmod $(DIRMOD) $@
 
@@ -2103,8 +2114,9 @@
 	-rm -f $(DEST_PRINT)/*.ps
 	-rmdir $(DEST_HELP) $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND)
 	-rm -rf $(DEST_FTP)/*.vim $(DEST_FTP)/README.txt
+	-rm -f $(DEST_AUTO)/*.vim $(DEST_AUTO)/README.txt
 	-rm -f $(DEST_PLUG)/*.vim $(DEST_PLUG)/README.txt
-	-rmdir $(DEST_FTP) $(DEST_PLUG) $(DEST_RT)
+	-rmdir $(DEST_FTP) $(DEST_AUTO) $(DEST_PLUG) $(DEST_RT)
 #	This will fail when other Vim versions are installed, no worries.
 	-rmdir $(DEST_VIM)
 
diff --git a/src/buffer.c b/src/buffer.c
index 07e9723..09ca27d 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -25,7 +25,6 @@
  * The current implementation remembers all file names ever used.
  */
 
-
 #include "vim.h"
 
 #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
diff --git a/src/eval.c b/src/eval.c
index f18a3a9..f2cc2a0 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -639,7 +639,6 @@
 static typval_T *alloc_tv __ARGS((void));
 static typval_T *alloc_string_tv __ARGS((char_u *string));
 static void free_tv __ARGS((typval_T *varp));
-static void clear_tv __ARGS((typval_T *varp));
 static void init_tv __ARGS((typval_T *varp));
 static long get_tv_number __ARGS((typval_T *varp));
 static long get_tv_number_chk __ARGS((typval_T *varp, int *denote));
@@ -683,7 +682,7 @@
 # endif
 	prof_self_cmp __ARGS((const void *s1, const void *s2));
 #endif
-static int script_autoload __ARGS((char_u *name));
+static int script_autoload __ARGS((char_u *name, int reload));
 static char_u *autoload_name __ARGS((char_u *name));
 static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp));
 static void func_free __ARGS((ufunc_T *fp));
@@ -1308,6 +1307,30 @@
 }
 #endif
 
+/*
+ * Top level evaluation function, 
+ */
+    typval_T *
+eval_expr(arg, nextcmd)
+    char_u	*arg;
+    char_u	**nextcmd;
+{
+    typval_T	*tv;
+
+    tv = (typval_T *)alloc(sizeof(typval_T));
+    if (!tv)
+	return NULL;
+
+    if (eval0(arg, tv, nextcmd, TRUE) == FAIL)
+    {
+	vim_free(tv);
+	return NULL;
+    }
+
+    return tv;
+}
+
+
 #if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO)
 /*
  * Call some vimL function and return the result in "*rettv".
@@ -7101,7 +7124,7 @@
 	    }
 #endif
 	    /* Try loading a package. */
-	    if (fp == NULL && script_autoload(fname) && !aborting())
+	    if (fp == NULL && script_autoload(fname, TRUE) && !aborting())
 	    {
 		/* loaded a package, search for the function again */
 		fp = find_func(fname);
@@ -15528,7 +15551,7 @@
 /*
  * Free the memory for a variable value and set the value to NULL or 0.
  */
-    static void
+    void
 clear_tv(varp)
     typval_T *varp;
 {
@@ -15774,9 +15797,11 @@
     if (HASHITEM_EMPTY(hi))
     {
 	/* For global variables we may try auto-loading the script.  If it
-	 * worked find the variable again. */
+	 * worked find the variable again.  Don't auto-load a script if it was
+	 * loaded already, otherwise it would be loaded every time when
+	 * checking if a function name is a Funcref variable. */
 	if (ht == &globvarht && !writing
-				   && script_autoload(varname) && !aborting())
+			    && script_autoload(varname, FALSE) && !aborting())
 	    hi = hash_find(ht, varname);
 	if (HASHITEM_EMPTY(hi))
 	    return NULL;
@@ -17566,29 +17591,52 @@
 
 #endif
 
+/* The names of packages that once were loaded is remembered. */
+static garray_T	    ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
+
 /*
  * If "name" has a package name try autoloading the script for it.
  * Return TRUE if a package was loaded.
  */
     static int
-script_autoload(name)
-    char_u *name;
+script_autoload(name, reload)
+    char_u	*name;
+    int		reload;	    /* load script again when already loaded */
 {
     char_u	*p;
-    char_u	*scriptname;
+    char_u	*scriptname, *tofree;
     int		ret = FALSE;
+    int		i;
 
-    /* If there is no colon after name[1] there is no package name. */
+    /* If there is no '#' after name[0] there is no package name. */
     p = vim_strchr(name, AUTOLOAD_CHAR);
-    if (p == NULL || p <= name + 2)
+    if (p == NULL || p == name)
 	return FALSE;
 
-    /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
-    scriptname = autoload_name(name);
-    if (cmd_runtime(scriptname, FALSE) == OK)
-	ret = TRUE;
+    tofree = scriptname = autoload_name(name);
 
-    vim_free(scriptname);
+    /* Find the name in the list of previously loaded package names.  Skip
+     * "autoload/", it's always the same. */
+    for (i = 0; i < ga_loaded.ga_len; ++i)
+	if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
+	    break;
+    if (!reload && i < ga_loaded.ga_len)
+	ret = FALSE;	    /* was loaded already */
+    else
+    {
+	/* Remember the name if it wasn't loaded already. */
+	if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
+	{
+	    ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
+	    tofree = NULL;
+	}
+
+	/* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
+	if (cmd_runtime(scriptname, FALSE) == OK)
+	    ret = TRUE;
+    }
+
+    vim_free(tofree);
     return ret;
 }
 
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 51053c9..c5adaeb 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -187,6 +187,8 @@
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_cabclear,	"cabclear",	ex_abclear,
 			EXTRA|TRLBAR|CMDWIN),
+EX(CMD_caddfile,	"caddfile",	ex_cfile,
+			TRLBAR|FILE1),
 EX(CMD_call,		"call",		ex_call,
 			RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN),
 EX(CMD_catch,		"catch",	ex_catch,
@@ -201,6 +203,8 @@
 			BANG|FILE1|TRLBAR|CMDWIN),
 EX(CMD_center,		"center",	ex_align,
 			TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY),
+EX(CMD_cexpr,		"cexpr",	ex_cexpr,
+			NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG),
 EX(CMD_cfile,		"cfile",	ex_cfile,
 			TRLBAR|FILE1|BANG),
 EX(CMD_cfirst,		"cfirst",	ex_cc,
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 5b07cf6..ab11dff 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -114,6 +114,7 @@
 # define ex_cc			ex_ni
 # define ex_cnext		ex_ni
 # define ex_cfile		ex_ni
+# define ex_cexpr		ex_ni
 # define qf_list		ex_ni
 # define qf_age			ex_ni
 # define ex_helpgrep		ex_ni
diff --git a/src/globals.h b/src/globals.h
index 8460b49..fc1e61f 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -166,8 +166,6 @@
 #endif
 
 EXTERN int	quit_more INIT(= FALSE);    /* 'q' hit at "--more--" msg */
-EXTERN int	more_back INIT(= 0);	    /* 'b' or 'u' at "--more--" msg */
-EXTERN int	more_back_used INIT(= FALSE); /* using more_back */
 #if defined(UNIX) || defined(__EMX__) || defined(VMS) || defined(MACOS_X)
 EXTERN int	newline_on_exit INIT(= FALSE);	/* did msg in altern. screen */
 EXTERN int	intr_char INIT(= 0);	    /* extra interrupt character */
diff --git a/src/gui.c b/src/gui.c
index f0a5958..fd0c046 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -455,6 +455,7 @@
      * where Vim was started. */
     emsg_on_display = FALSE;
     msg_scrolled = 0;
+    clear_sb_text();
     need_wait_return = FALSE;
     msg_didany = FALSE;
 
diff --git a/src/main.aap b/src/main.aap
index daa6e8b..83a9cd8 100644
--- a/src/main.aap
+++ b/src/main.aap
@@ -237,6 +237,7 @@
 	fileio.c
 	fold.c
 	getchar.c
+        hardcopy.c
 	hashtable.c
 	if_cscope.c
 	if_xcmdsrv.c
@@ -440,6 +441,7 @@
 COLSUBDIR = /colors
 SYNSUBDIR = /syntax
 INDSUBDIR = /indent
+AUTOSUBDIR = /autoload
 PLUGSUBDIR = /plugin
 FTPLUGSUBDIR = /ftplugin
 LANGSUBDIR = /lang
@@ -459,6 +461,7 @@
 ### COLSUBLOC	location for colorscheme files
 ### SYNSUBLOC	location for syntax files
 ### INDSUBLOC	location for indent files
+### AUTOSUBLOC	location for standard autoload files
 ### PLUGSUBLOC	location for standard plugin files
 ### FTPLUGSUBLOC  location for ftplugin files
 ### LANGSUBLOC	location for language files
@@ -478,6 +481,7 @@
 COLSUBLOC	= $VIMRTLOC$COLSUBDIR
 SYNSUBLOC	= $VIMRTLOC$SYNSUBDIR
 INDSUBLOC	= $VIMRTLOC$INDSUBDIR
+AUTOSUBLOC	= $VIMRTLOC$AUTOSUBDIR
 PLUGSUBLOC	= $VIMRTLOC$PLUGSUBDIR
 FTPLUGSUBLOC	= $VIMRTLOC$FTPLUGSUBDIR
 LANGSUBLOC	= $VIMRTLOC$LANGSUBDIR
@@ -566,6 +570,9 @@
 INDSOURCE = ../runtime/indent
 
 # Where to copy the standard plugin files from
+AUTOSOURCE = ../runtime/autoload
+
+# Where to copy the standard plugin files from
 PLUGSOURCE = ../runtime/plugin
 
 # Where to copy the ftplugin files from
@@ -600,6 +607,7 @@
 DEST_COL = $DESTDIR$COLSUBLOC
 DEST_SYN = $DESTDIR$SYNSUBLOC
 DEST_IND = $DESTDIR$INDSUBLOC
+DEST_AUTO = $DESTDIR$AUTOSUBLOC
 DEST_PLUG = $DESTDIR$PLUGSUBLOC
 DEST_FTP = $DESTDIR$FTPLUGSUBLOC
 DEST_LANG = $DESTDIR$LANGSUBLOC
@@ -614,7 +622,7 @@
 
 # These are directories, create them when needed.
 :attr {directory = $DIRMOD} $DEST_BIN $DEST_VIM $DEST_RT $DEST_HELP $DEST_COL
-		$DEST_SYN $DEST_IND $DEST_PLUG $DEST_FTP $DEST_LANG
+		$DEST_SYN $DEST_IND $DEST_AUTO $DEST_PLUG $DEST_FTP $DEST_LANG
 		$DEST_COMP $DEST_KMAP $DEST_MACRO $DEST_TOOLS $DEST_TUTOR
 		$DEST_SCRIPT $DEST_PRINT $DEST_MAN
 
@@ -657,7 +665,8 @@
 # install the help files; first adjust the contents for the location
 installruntime {virtual}{force}: $HELPSOURCE/vim.1 $DEST_MAN $DEST_VIM
 		$DEST_RT $DEST_HELP $DEST_COL $DEST_SYN $DEST_IND
-		$DEST_FTP $DEST_PLUG $DEST_TUTOR $DEST_COMP $DEST_PRINT
+		$DEST_FTP $DEST_AUTO $DEST_PLUG $DEST_TUTOR $DEST_COMP
+                $DEST_PRINT
 	:print generating $DEST_MAN/$(VIMNAME).1
 	:cat $HELPSOURCE/vim.1 |
 		:eval re.sub("/usr/local/lib/vim", _no.VIMLOC, stdin) |
@@ -762,6 +771,9 @@
 # install the indent files
 	:copy $INDSOURCE/*.vim $INDSOURCE/README.txt $DEST_IND
 	:chmod $HELPMOD $DEST_IND/*.vim
+# install the standard autoload files
+	:copy $AUTOSOURCE/*.vim $AUTOSOURCE/README.txt $DEST_AUTO
+	:chmod $HELPMOD $DEST_AUTO/*.vim $DEST_AUTO/README.txt
 # install the standard plugin files
 	:copy $PLUGSOURCE/*.vim $PLUGSOURCE/README.txt $DEST_PLUG
 	:chmod $HELPMOD $DEST_PLUG/*.vim $DEST_PLUG/README.txt
@@ -1041,8 +1053,9 @@
     :del {force}{recursive} $DEST_COMP
     :deldir {force} $DEST_HELP $DEST_COL $DEST_SYN $DEST_IND
     :del {force}{recursive} $DEST_FTP/*.vim $DEST_FTP/README.txt
+    :del {force} $DEST_AUTO/*.vim $DEST_AUTO/README.txt
     :del {force} $DEST_PLUG/*.vim $DEST_PLUG/README.txt
-    :deldir {force} $DEST_FTP $DEST_PLUG $DEST_PRINT $DEST_RT
+    :deldir {force} $DEST_FTP $DEST_AUTO $DEST_PLUG $DEST_PRINT $DEST_RT
 #	This will fail when other Vim versions are installed, no worries.
     @try:
 	:deldir $DEST_VIM
diff --git a/src/main.c b/src/main.c
index f6a31aa..876289f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1034,6 +1034,7 @@
 	    emsg_on_display = FALSE;	/* can delete error message now */
 	    did_emsg = FALSE;
 	    msg_didany = FALSE;		/* reset lines_left in msg_start() */
+	    clear_sb_text();		/* clear scroll-back text */
 	    showruler(FALSE);
 
 	    setcursor();
diff --git a/src/message.c b/src/message.c
index 94b8851..81c0a8e 100644
--- a/src/message.c
+++ b/src/message.c
@@ -29,7 +29,12 @@
 static char_u *screen_puts_mbyte __ARGS((char_u *s, int l, int attr));
 #endif
 static void msg_puts_attr_len __ARGS((char_u *str, int maxlen, int attr));
-static void t_puts __ARGS((int t_col, char_u *t_s, char_u *s, int attr));
+static void msg_puts_display __ARGS((char_u *str, int maxlen, int attr, int recurse));
+static void msg_scroll_up __ARGS((void));
+static void store_sb_text __ARGS((char_u **sb_str, char_u *s, int attr, int *sb_col, int finish));
+static void t_puts __ARGS((int *t_col, char_u *t_s, char_u *s, int attr));
+static void msg_puts_printf __ARGS((char_u *str, int maxlen));
+static int do_more_prompt __ARGS((int typed_char));
 static void msg_screen_putchar __ARGS((int c, int attr));
 static int  msg_check_screen __ARGS((void));
 static void redir_write __ARGS((char_u *s, int maxlen));
@@ -924,6 +929,22 @@
 		c = K_IGNORE;
 	    }
 #endif
+	    if (p_more && !p_cp && (c == 'b' || c == 'k' || c == 'u'))
+	    {
+		/* scroll back to show older messages */
+		do_more_prompt(c);
+		if (quit_more)
+		{
+		    c = CAR;		/* just pretend CR was hit */
+		    quit_more = FALSE;
+		    got_int = FALSE;
+		}
+		else
+		{
+		    c = K_IGNORE;
+		    hit_return_msg();
+		}
+	    }
 	} while ((had_got_int && c == Ctrl_C)
 				|| c == K_IGNORE
 #ifdef FEAT_GUI
@@ -1031,14 +1052,18 @@
     static void
 hit_return_msg()
 {
-    if (msg_didout)		    /* start on a new line */
+    int		save_p_more = p_more;
+
+    p_more = FALSE;	/* don't want see this message when scrolling back */
+    if (msg_didout)	/* start on a new line */
 	msg_putchar('\n');
     if (got_int)
 	MSG_PUTS(_("Interrupt: "));
 
-    MSG_PUTS_ATTR(_("Hit ENTER or type command to continue"), hl_attr(HLF_R));
+    MSG_PUTS_ATTR(_("Press ENTER or type command to continue"), hl_attr(HLF_R));
     if (!msg_use_printf())
 	msg_clr_eos();
+    p_more = save_p_more;
 }
 
 /*
@@ -1515,7 +1540,7 @@
     if (*s == NUL && !(list && lcs_eol != NUL))
 	msg_putchar(' ');
 
-    for (;;)
+    while (!got_int)
     {
 	if (n_extra)
 	{
@@ -1711,22 +1736,10 @@
     int		maxlen;
     int		attr;
 {
-    int		oldState;
-    char_u	*s = str;
-    char_u	*p;
-    char_u	buf[4];
-    char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
-    int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
-#ifdef FEAT_MBYTE
-    int		l;
-    int		cw;
-#endif
-    int		c;
-
     /*
      * If redirection is on, also write to the redirection file.
      */
-    redir_write(s, maxlen);
+    redir_write(str, maxlen);
 
     /*
      * Don't print anything when using ":silent cmd".
@@ -1737,7 +1750,7 @@
     /* if MSG_HIST flag set, add message to history */
     if ((attr & MSG_HIST) && maxlen < 0)
     {
-	add_msg_hist(s, -1, attr);
+	add_msg_hist(str, -1, attr);
 	attr &= ~MSG_HIST;
     }
 
@@ -1759,72 +1772,42 @@
      * cursor is.
      */
     if (msg_use_printf())
-    {
-#ifdef WIN3264
-	if (!(silent_mode && p_verbose == 0))
-	    mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
-#endif
-	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
-	{
-	    if (!(silent_mode && p_verbose == 0))
-	    {
-		p = &buf[0];
-		/* NL --> CR NL translation (for Unix, not for "--version") */
-		/* NL --> CR translation (for Mac) */
-		if (*s == '\n' && !info_message)
-		    *p++ = '\r';
-#if defined(USE_CR) && !defined(MACOS_X_UNIX)
-		else
-#endif
-		    *p++ = *s;
-		*p = '\0';
-		if (info_message)	/* informative message, not an error */
-		    mch_msg((char *)buf);
-		else
-		    mch_errmsg((char *)buf);
-	    }
+	msg_puts_printf(str, maxlen);
+    else
+	msg_puts_display(str, maxlen, attr, FALSE);
+}
 
-	    /* primitive way to compute the current column */
-#ifdef FEAT_RIGHTLEFT
-	    if (cmdmsg_rl)
-	    {
-		if (*s == '\r' || *s == '\n')
-		    msg_col = Columns - 1;
-		else
-		    --msg_col;
-	    }
-	    else
+/*
+ * The display part of msg_puts_attr_len().
+ * May be called recursively to display scroll-back text.
+ */
+    static void
+msg_puts_display(str, maxlen, attr, recurse)
+    char_u	*str;
+    int		maxlen;
+    int		attr;
+    int		recurse;
+{
+    char_u	*s = str;
+    char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
+    int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
+#ifdef FEAT_MBYTE
+    int		l;
+    int		cw;
 #endif
-	    {
-		if (*s == '\r' || *s == '\n')
-		    msg_col = 0;
-		else
-		    ++msg_col;
-	    }
-	    ++s;
-	}
-	msg_didout = TRUE;	    /* assume that line is not empty */
-
-#ifdef WIN3264
-	if (!(silent_mode && p_verbose == 0))
-	    mch_settmode(TMODE_RAW);
-#endif
-	return;
-    }
+    char_u	*sb_str = str;
+    int		sb_col = msg_col;
+    int		wrap;
 
     did_wait_return = FALSE;
     while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
     {
 	/*
-	 * The screen is scrolled up when:
-	 * - When outputting a newline in the last row
-	 * - when outputting a character in the last column of the last row
-	 *   (some terminals scroll automatically, some don't. To avoid
-	 *   problems we scroll ourselves)
+	 * We are at the end of the screen line when:
+	 * - When outputting a newline.
+	 * - When outputting a character in the last column.
 	 */
-	if (msg_row >= Rows - 1
-		&& (*s == '\n'
-		    || (
+	if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || (
 #ifdef FEAT_RIGHTLEFT
 		    cmdmsg_rl
 		    ? (
@@ -1844,47 +1827,55 @@
 # endif
 		      ))))
 	{
+	    /*
+	     * The screen is scrolled up when at the last row (some terminals
+	     * scroll automatically, some don't.  To avoid problems we scroll
+	     * ourselves).
+	     */
 	    if (t_col > 0)
-	    {
 		/* output postponed text */
-		t_puts(t_col, t_s, s, attr);
-		t_col = 0;
-	    }
+		t_puts(&t_col, t_s, s, attr);
 
 	    /* When no more prompt an no more room, truncate here */
 	    if (msg_no_more && lines_left == 0)
 		break;
-#ifdef FEAT_GUI
-	    /* Remove the cursor before scrolling, ScreenLines[] is going to
-	     * become invalid. */
-	    if (gui.in_use)
-		gui_undraw_cursor();
-#endif
-	    /* scrolling up always works */
-	    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
 
-	    if (!can_clear((char_u *)" "))
-	    {
-		/* Scrolling up doesn't result in the right background.  Set
-		 * the background here.  It's not efficient, but avoids that
-		 * we have to do it all over the code. */
-		screen_fill((int)Rows - 1, (int)Rows, 0,
-						   (int)Columns, ' ', ' ', 0);
-
-		/* Also clear the last char of the last but one line if it was
-		 * not cleared before to avoid a scroll-up. */
-		if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1]
-							       == (sattr_T)-1)
-		    screen_fill((int)Rows - 2, (int)Rows - 1,
-				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
-	    }
+	    /* Scroll the screen up one line. */
+	    msg_scroll_up();
 
 	    msg_row = Rows - 2;
 	    if (msg_col >= Columns)	/* can happen after screen resize */
 		msg_col = Columns - 1;
 
+	    /* Display char in last column before showing more-prompt. */
+	    if (*s >= ' '
+#ifdef FEAT_RIGHTLEFT
+		    && !cmdmsg_rl
+#endif
+	       )
+	    {
+#ifdef FEAT_MBYTE
+		if (has_mbyte)
+		{
+		    if (enc_utf8 && maxlen >= 0)
+			/* avoid including composing chars after the end */
+			l = utfc_ptr2len_check_len(s,
+						   (int)((str + maxlen) - s));
+		    else
+			l = (*mb_ptr2len_check)(s);
+		    s = screen_puts_mbyte(s, l, attr);
+		}
+		else
+#endif
+		    msg_screen_putchar(*s++, attr);
+	    }
+
+	    if (p_more)
+		/* store text for scrolling back */
+		store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
+
 	    ++msg_scrolled;
-	    need_wait_return = TRUE;	/* may need wait_return in main() */
+	    need_wait_return = TRUE; /* may need wait_return in main() */
 	    if (must_redraw < VALID)
 		must_redraw = VALID;
 	    redraw_cmdline = TRUE;
@@ -1892,170 +1883,38 @@
 		--cmdline_row;
 
 	    /*
-	     * if screen is completely filled wait for a character
+	     * If screen is completely filled and 'more' is set then wait
+	     * for a character.
 	     */
 	    if (p_more && --lines_left == 0 && State != HITRETURN
 					    && !msg_no_more && !exmode_active)
 	    {
-		oldState = State;
-		State = ASKMORE;
-#ifdef FEAT_MOUSE
-		setmouse();
-#endif
-		msg_moremsg(FALSE);
-		for (;;)
-		{
-		    /*
-		     * Get a typed character directly from the user.
-		     */
-		    c = get_keystroke();
-
-#if defined(FEAT_MENU) && defined(FEAT_GUI)
-		    if (c == K_MENU)
-		    {
-			int idx = get_menu_index(current_menu, ASKMORE);
-
-			/* Used a menu.  If it starts with CTRL-Y, it must
-			 * be a "Copy" for the clipboard.  Otherwise
-			 * assume that we end */
-			if (idx == MENU_INDEX_INVALID)
-			    continue;
-			c = *current_menu->strings[idx];
-			if (c != NUL && current_menu->strings[idx][1] != NUL)
-			    ins_typebuf(current_menu->strings[idx] + 1,
-				    current_menu->noremap[idx], 0, TRUE,
-				    current_menu->silent[idx]);
-		    }
-#endif
-
-		    switch (c)
-		    {
-		    case BS:
-		    case 'k':
-		    case K_UP:
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = 1;
-			lines_left = 1;
-			break;
-		    case CAR:		/* one extra line */
-		    case NL:
-		    case 'j':
-		    case K_DOWN:
-			lines_left = 1;
-			break;
-		    case ':':		/* start new command line */
 #ifdef FEAT_CON_DIALOG
-			if (!confirm_msg_used)
-#endif
-			{
-			    /* Since got_int is set all typeahead will be
-			     * flushed, but we want to keep this ':', remember
-			     * that in a special way. */
-			    typeahead_noflush(':');
-			    cmdline_row = Rows - 1;   /* put ':' on this line */
-			    skip_redraw = TRUE;	      /* skip redraw once */
-			    need_wait_return = FALSE; /* don't wait in main() */
-			}
-			/*FALLTHROUGH*/
-		    case 'q':		/* quit */
-		    case Ctrl_C:
-		    case ESC:
-#ifdef FEAT_CON_DIALOG
-			if (confirm_msg_used)
-			{
-			    /* Jump to the choices of the dialog. */
-			    s = confirm_msg_tail;
-			    lines_left = Rows - 1;
-			}
-			else
-#endif
-			{
-			    got_int = TRUE;
-			    quit_more = TRUE;
-			}
-			break;
-		    case 'u':		/* Up half a page */
-		    case K_PAGEUP:
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = Rows / 2;
-			/*FALLTHROUGH*/
-		    case 'd':		/* Down half a page */
-			lines_left = Rows / 2;
-			break;
-		    case 'b':		/* one page back */
-			if (!more_back_used)
-			{
-			    msg_moremsg(TRUE);
-			    continue;
-			}
-			more_back = Rows - 1;
-			/*FALLTHROUGH*/
-		    case ' ':		/* one extra page */
-		    case K_PAGEDOWN:
-		    case K_LEFTMOUSE:
-			lines_left = Rows - 1;
-			break;
-
-#ifdef FEAT_CLIPBOARD
-		    case Ctrl_Y:
-			/* Strange way to allow copying (yanking) a modeless
-			 * selection at the more prompt.  Use CTRL-Y,
-			 * because the same is used in Cmdline-mode and at the
-			 * hit-enter prompt.  However, scrolling one line up
-			 * might be expected... */
-			if (clip_star.state == SELECT_DONE)
-			    clip_copy_modeless_selection(TRUE);
-			continue;
-#endif
-		    default:		/* no valid response */
-			msg_moremsg(TRUE);
-			continue;
-		    }
-		    break;
-		}
-
-		/* clear the --more-- message */
-		screen_fill((int)Rows - 1, (int)Rows,
-						0, (int)Columns, ' ', ' ', 0);
-		State = oldState;
-#ifdef FEAT_MOUSE
-		setmouse();
+		if (do_more_prompt(NUL))
+		    s = confirm_msg_tail;
+#else
+		(void)do_more_prompt(NUL);
 #endif
 		if (quit_more)
-		{
-		    msg_row = Rows - 1;
-		    msg_col = 0;
-		    return;	    /* the string is not displayed! */
-		}
-#ifdef FEAT_RIGHTLEFT
-		if (cmdmsg_rl)
-		    msg_col = Columns - 1;
-#endif
+		    return;
 	    }
 	}
 
-	if (t_col > 0
-		&& (vim_strchr((char_u *)"\n\r\b\t", *s) != NULL
-		    || *s == BELL
+	wrap = *s == '\n'
 		    || msg_col + t_col >= Columns
 #ifdef FEAT_MBYTE
 		    || (has_mbyte && (*mb_ptr2cells)(s) > 1
 					    && msg_col + t_col >= Columns - 1)
 #endif
-		    ))
-	{
+		    ;
+	if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
+						 || *s == '\t' || *s == BELL))
 	    /* output any postponed text */
-	    t_puts(t_col, t_s, s, attr);
-	    t_col = 0;
-	}
+	    t_puts(&t_col, t_s, s, attr);
+
+	if (wrap && p_more && !recurse)
+	    /* store text for scrolling back */
+	    store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
 
 	if (*s == '\n')		    /* go to next line */
 	{
@@ -2073,7 +1932,7 @@
 	    if (msg_col)
 		--msg_col;
 	}
-	else if (*s == TAB)	    /* translate into spaces */
+	else if (*s == TAB)	    /* translate Tab into spaces */
 	{
 	    do
 		msg_screen_putchar(' ', attr);
@@ -2141,17 +2000,172 @@
 
     /* output any postponed text */
     if (t_col > 0)
-	t_puts(t_col, t_s, s, attr);
+	t_puts(&t_col, t_s, s, attr);
+    if (p_more && !recurse)
+	store_sb_text(&sb_str, s, attr, &sb_col, FALSE);
 
     msg_check();
 }
 
 /*
+ * Scroll the screen up one line for displaying the next message line.
+ */
+    static void
+msg_scroll_up()
+{
+#ifdef FEAT_GUI
+    /* Remove the cursor before scrolling, ScreenLines[] is going
+     * to become invalid. */
+    if (gui.in_use)
+	gui_undraw_cursor();
+#endif
+    /* scrolling up always works */
+    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
+
+    if (!can_clear((char_u *)" "))
+    {
+	/* Scrolling up doesn't result in the right background.  Set the
+	 * background here.  It's not efficient, but avoids that we have to do
+	 * it all over the code. */
+	screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+
+	/* Also clear the last char of the last but one line if it was not
+	 * cleared before to avoid a scroll-up. */
+	if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1)
+	    screen_fill((int)Rows - 2, (int)Rows - 1,
+				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
+    }
+}
+
+/*
+ * To be able to scroll back at the "more" and "hit-enter" prompts we need to
+ * store the displayed text and remember where screen lines start.
+ */
+typedef struct msgchunk_S msgchunk_T;
+struct msgchunk_S
+{
+    msgchunk_T	*sb_next;
+    msgchunk_T	*sb_prev;
+    char	sb_eol;		/* TRUE when line ends after this text */
+    int		sb_msg_col;	/* column in which text starts */
+    int		sb_attr;	/* text attributes */
+    char_u	sb_text[1];	/* text to be displayed, actually longer */
+};
+
+static msgchunk_T *last_msgchunk = NULL; /* last displayed text */
+
+static msgchunk_T *msg_sb_start __ARGS((msgchunk_T *mps));
+static msgchunk_T *disp_sb_line __ARGS((int row, msgchunk_T *smp));
+
+/*
+ * Store part of a printed message for displaying when scrolling back.
+ */
+    static void
+store_sb_text(sb_str, s, attr, sb_col, finish)
+    char_u	**sb_str;	/* start of string */
+    char_u	*s;		/* just after string */
+    int		attr;
+    int		*sb_col;
+    int		finish;		/* line ends */
+{
+    msgchunk_T	*mp;
+
+    if (s > *sb_str)
+    {
+	mp = (msgchunk_T *)alloc((int)(sizeof(msgchunk_T) + (s - *sb_str)));
+	if (mp != NULL)
+	{
+	    mp->sb_eol = finish;
+	    mp->sb_msg_col = *sb_col;
+	    mp->sb_attr = attr;
+	    vim_strncpy(mp->sb_text, *sb_str, s - *sb_str);
+
+	    if (last_msgchunk == NULL)
+	    {
+		last_msgchunk = mp;
+		mp->sb_prev = NULL;
+	    }
+	    else
+	    {
+		mp->sb_prev = last_msgchunk;
+		last_msgchunk->sb_next = mp;
+		last_msgchunk = mp;
+	    }
+	    mp->sb_next = NULL;
+	}
+    }
+    else if (finish && last_msgchunk != NULL)
+	last_msgchunk->sb_eol = TRUE;
+
+    *sb_str = s;
+    *sb_col = 0;
+}
+
+/*
+ * Clear any text remembered for scrolling back.
+ * Called when redrawing the screen.
+ */
+    void
+clear_sb_text()
+{
+    msgchunk_T	*mp;
+
+    while (last_msgchunk != NULL)
+    {
+	mp = last_msgchunk->sb_prev;
+	vim_free(last_msgchunk);
+	last_msgchunk = mp;
+    }
+    last_msgchunk = NULL;
+}
+
+/*
+ * Move to the start of screen line in already displayed text.
+ */
+    static msgchunk_T *
+msg_sb_start(mps)
+    msgchunk_T *mps;
+{
+    msgchunk_T *mp = mps;
+
+    while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol)
+	mp = mp->sb_prev;
+    return mp;
+}
+
+/*
+ * Display a screen line from previously displayed text at row "row".
+ * Returns a pointer to the text for the next line (can be NULL).
+ */
+    static msgchunk_T *
+disp_sb_line(row, smp)
+    int		row;
+    msgchunk_T	*smp;
+{
+    msgchunk_T	*mp = smp;
+    char_u	*p;
+
+    for (;;)
+    {
+	msg_row = row;
+	msg_col = mp->sb_msg_col;
+	p = mp->sb_text;
+	if (*p == '\n')	    /* don't display the line break */
+	    ++p;
+	msg_puts_display(p, -1, mp->sb_attr, TRUE);
+	if (mp->sb_eol || mp->sb_next == NULL)
+	    break;
+	mp = mp->sb_next;
+    }
+    return mp->sb_next;
+}
+
+/*
  * Output any postponed text for msg_puts_attr_len().
  */
     static void
 t_puts(t_col, t_s, s, attr)
-    int		t_col;
+    int		*t_col;
     char_u	*t_s;
     char_u	*s;
     int		attr;
@@ -2159,7 +2173,8 @@
     /* output postponed text */
     msg_didout = TRUE;		/* remember that line is not empty */
     screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr);
-    msg_col += t_col;
+    msg_col += *t_col;
+    *t_col = 0;
 #ifdef FEAT_MBYTE
     /* If the string starts with a composing character don't increment the
      * column position for it. */
@@ -2173,7 +2188,6 @@
     }
 }
 
-
 /*
  * Returns TRUE when messages should be printed with mch_errmsg().
  * This is used when there is no valid screen, so we can see error messages.
@@ -2193,6 +2207,309 @@
 	       );
 }
 
+/*
+ * Print a message when there is no valid screen.
+ */
+    static void
+msg_puts_printf(str, maxlen)
+    char_u	*str;
+    int		maxlen;
+{
+    char_u	*s = str;
+    char_u	buf[4];
+    char_u	*p;
+
+#ifdef WIN3264
+    if (!(silent_mode && p_verbose == 0))
+	mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
+#endif
+    while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
+    {
+	if (!(silent_mode && p_verbose == 0))
+	{
+	    /* NL --> CR NL translation (for Unix, not for "--version") */
+	    /* NL --> CR translation (for Mac) */
+	    p = &buf[0];
+	    if (*s == '\n' && !info_message)
+		*p++ = '\r';
+#if defined(USE_CR) && !defined(MACOS_X_UNIX)
+	    else
+#endif
+		*p++ = *s;
+	    *p = '\0';
+	    if (info_message)	/* informative message, not an error */
+		mch_msg((char *)buf);
+	    else
+		mch_errmsg((char *)buf);
+	}
+
+	/* primitive way to compute the current column */
+#ifdef FEAT_RIGHTLEFT
+	if (cmdmsg_rl)
+	{
+	    if (*s == '\r' || *s == '\n')
+		msg_col = Columns - 1;
+	    else
+		--msg_col;
+	}
+	else
+#endif
+	{
+	    if (*s == '\r' || *s == '\n')
+		msg_col = 0;
+	    else
+		++msg_col;
+	}
+	++s;
+    }
+    msg_didout = TRUE;	    /* assume that line is not empty */
+
+#ifdef WIN3264
+    if (!(silent_mode && p_verbose == 0))
+	mch_settmode(TMODE_RAW);
+#endif
+}
+
+/*
+ * Show the more-prompt and handle the user response.
+ * This takes care of scrolling back and displaying previously displayed text.
+ * When at hit-enter prompt "typed_char" is the already typed character.
+ * Returns TRUE when jumping ahead to "confirm_msg_tail".
+ */
+    static int
+do_more_prompt(typed_char)
+    int		typed_char;
+{
+    int		used_typed_char = typed_char;
+    int		oldState = State;
+    int		c;
+#ifdef FEAT_CON_DIALOG
+    int		retval = FALSE;
+#endif
+    int		scroll;
+    msgchunk_T	*mp_last = NULL;
+    msgchunk_T	*mp;
+    int		i;
+
+    State = ASKMORE;
+#ifdef FEAT_MOUSE
+    setmouse();
+#endif
+    msg_moremsg(FALSE);
+    for (;;)
+    {
+	/*
+	 * Get a typed character directly from the user.
+	 */
+	if (used_typed_char != NUL)
+	{
+	    c = used_typed_char;	/* was typed at hit-enter prompt */
+	    used_typed_char = NUL;
+	}
+	else
+	    c = get_keystroke();
+
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+	if (c == K_MENU)
+	{
+	    int idx = get_menu_index(current_menu, ASKMORE);
+
+	    /* Used a menu.  If it starts with CTRL-Y, it must
+	     * be a "Copy" for the clipboard.  Otherwise
+	     * assume that we end */
+	    if (idx == MENU_INDEX_INVALID)
+		continue;
+	    c = *current_menu->strings[idx];
+	    if (c != NUL && current_menu->strings[idx][1] != NUL)
+		ins_typebuf(current_menu->strings[idx] + 1,
+				current_menu->noremap[idx], 0, TRUE,
+						   current_menu->silent[idx]);
+	}
+#endif
+
+	scroll = 0;
+	switch (c)
+	{
+	case BS:		/* scroll one line back */
+	case K_BS:
+	case 'k':
+	case K_UP:
+	    scroll = -1;
+	    break;
+
+	case CAR:		/* one extra line */
+	case NL:
+	case 'j':
+	case K_DOWN:
+	    scroll = 1;
+	    break;
+
+	case 'u':		/* Up half a page */
+	case K_PAGEUP:
+	    scroll = -(Rows / 2);
+	    break;
+
+	case 'd':		/* Down half a page */
+	    scroll = Rows / 2;
+	    break;
+
+	case 'b':		/* one page back */
+	    scroll = -(Rows - 1);
+	    break;
+
+	case ' ':		/* one extra page */
+	case K_PAGEDOWN:
+	case K_LEFTMOUSE:
+	    scroll = Rows - 1;
+	    break;
+
+	case ':':		/* start new command line */
+#ifdef FEAT_CON_DIALOG
+	    if (!confirm_msg_used)
+#endif
+	    {
+		/* Since got_int is set all typeahead will be flushed, but we
+		 * want to keep this ':', remember that in a special way. */
+		typeahead_noflush(':');
+		cmdline_row = Rows - 1;		/* put ':' on this line */
+		skip_redraw = TRUE;		/* skip redraw once */
+		need_wait_return = FALSE;	/* don't wait in main() */
+	    }
+	    /*FALLTHROUGH*/
+	case 'q':		/* quit */
+	case Ctrl_C:
+	case ESC:
+#ifdef FEAT_CON_DIALOG
+	    if (confirm_msg_used)
+	    {
+		/* Jump to the choices of the dialog. */
+		retval = TRUE;
+		lines_left = Rows - 1;
+	    }
+	    else
+#endif
+	    {
+		got_int = TRUE;
+		quit_more = TRUE;
+	    }
+	    break;
+
+#ifdef FEAT_CLIPBOARD
+	case Ctrl_Y:
+	    /* Strange way to allow copying (yanking) a modeless
+	     * selection at the more prompt.  Use CTRL-Y,
+	     * because the same is used in Cmdline-mode and at the
+	     * hit-enter prompt.  However, scrolling one line up
+	     * might be expected... */
+	    if (clip_star.state == SELECT_DONE)
+		clip_copy_modeless_selection(TRUE);
+	    continue;
+#endif
+	default:		/* no valid response */
+	    msg_moremsg(TRUE);
+	    continue;
+	}
+
+	if (scroll != 0)
+	{
+	    if (scroll < 0)
+	    {
+		/* go to start of last line */
+		if (mp_last == NULL)
+		    mp = msg_sb_start(last_msgchunk);
+		else if (mp_last->sb_prev != NULL)
+		    mp = msg_sb_start(mp_last->sb_prev);
+		else
+		    mp = NULL;
+
+		/* go to start of line at top of the screen */
+		for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
+									  ++i)
+		    mp = msg_sb_start(mp->sb_prev);
+
+		if (mp != NULL && mp->sb_prev != NULL)
+		{
+		    /* Find line to be displayed at top. */
+		    for (i = 0; i > scroll; --i)
+		    {
+			if (mp == NULL || mp->sb_prev == NULL)
+			    break;
+			mp = msg_sb_start(mp->sb_prev);
+			if (mp_last == NULL)
+			    mp_last = msg_sb_start(last_msgchunk);
+			else
+			    mp_last = msg_sb_start(mp_last->sb_prev);
+		    }
+
+		    if (scroll == -1 && screen_ins_lines(0, 0, 1,
+						       (int)Rows, NULL) == OK)
+		    {
+			/* clear last line, display line at top */
+			screen_fill((int)Rows - 1, (int)Rows, 0,
+						   (int)Columns, ' ', ' ', 0);
+			(void)disp_sb_line(0, mp);
+		    }
+		    else
+		    {
+			/* redisplay */
+			screenclear();
+			for (i = 0; i < Rows - 1; ++i)
+			    mp = disp_sb_line(i, mp);
+		    }
+		    scroll = 0;
+		}
+	    }
+	    else
+	    {
+		/* First display any text that we scrolled back. */
+		while (scroll > 0 && mp_last != NULL)
+		{
+		    /* scroll up, display line at bottom */
+		    msg_scroll_up();
+		    screen_fill((int)Rows - 2, (int)Rows - 1, 0,
+						   (int)Columns, ' ', ' ', 0);
+		    mp_last = disp_sb_line((int)Rows - 2, mp_last);
+		    --scroll;
+		}
+	    }
+
+	    if (scroll <= 0)
+	    {
+		/* displayed the requested text, more prompt again */
+		msg_moremsg(FALSE);
+		continue;
+	    }
+
+	    /* display more text, return to caller */
+	    lines_left = scroll;
+	}
+
+	break;
+    }
+
+    /* clear the --more-- message */
+    screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+    State = oldState;
+#ifdef FEAT_MOUSE
+    setmouse();
+#endif
+    if (quit_more)
+    {
+	msg_row = Rows - 1;
+	msg_col = 0;
+    }
+#ifdef FEAT_RIGHTLEFT
+    else if (cmdmsg_rl)
+	msg_col = Columns - 1;
+#endif
+
+#ifdef FEAT_CON_DIALOG
+    return retval;
+#else
+    return FALSE;
+#endif
+}
+
 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
 
 #ifdef mch_errmsg
@@ -2344,15 +2661,15 @@
 msg_moremsg(full)
     int	    full;
 {
-    int	    attr;
+    int		attr;
+    char_u	*s = (char_u *)_("-- More --");
 
     attr = hl_attr(HLF_M);
-    screen_puts((char_u *)_("-- More --"), (int)Rows - 1, 0, attr);
+    screen_puts(s, (int)Rows - 1, 0, attr);
     if (full)
-	screen_puts(more_back_used
-	    ? (char_u *)_(" (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)")
-	    : (char_u *)_(" (RET: line, SPACE: page, d: half page, q: quit)"),
-	    (int)Rows - 1, 10, attr);
+	screen_puts((char_u *)
+		_(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
+		(int)Rows - 1, vim_strsize(s), attr);
 }
 
 /*
diff --git a/src/ops.c b/src/ops.c
index 8941941..b5492c6 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -1580,9 +1580,15 @@
 	    && *ml_get(oap->start.lnum) == NUL)
     {
 	/*
-	 * It's an error to operate on an empty region, when 'E' inclucded in
+	 * It's an error to operate on an empty region, when 'E' included in
 	 * 'cpoptions' (Vi compatible).
 	 */
+#ifdef FEAT_VIRTUALEDIT
+	if (virtual_op)
+	    /* Virtual editing: Nothing gets deleted, but we set the '[ and ']
+	     * marks as if it happened. */
+	    goto setmarks;
+#endif
 	if (vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL)
 	    beep_flush();
 	return OK;
@@ -1858,6 +1864,9 @@
 
     msgmore(curbuf->b_ml.ml_line_count - old_lcount);
 
+#ifdef FEAT_VIRTUALEDIT
+setmarks:
+#endif
 #ifdef FEAT_VISUAL
     if (oap->block_mode)
     {
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
index 6a2d44e..86ea396 100644
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -22,6 +22,7 @@
 int eval_to_number __ARGS((char_u *expr));
 list_T *eval_spell_expr __ARGS((char_u *badword, char_u *expr));
 int get_spellword __ARGS((list_T *list, char_u **pp));
+typval_T *eval_expr __ARGS((char_u *arg, char_u **nextcmd));
 void *call_func_retstr __ARGS((char_u *func, int argc, char_u **argv, int safe));
 void *call_func_retlist __ARGS((char_u *func, int argc, char_u **argv, int safe));
 void *save_funccal __ARGS((void));
@@ -59,6 +60,7 @@
 char_u *v_exception __ARGS((char_u *oldval));
 char_u *v_throwpoint __ARGS((char_u *oldval));
 char_u *set_cmdarg __ARGS((exarg_T *eap, char_u *oldarg));
+void clear_tv __ARGS((typval_T *varp));
 char_u *get_var_value __ARGS((char_u *name));
 void new_script_vars __ARGS((scid_T id));
 void init_var_dict __ARGS((dict_T *dict, dictitem_T *dict_var));
diff --git a/src/proto/message.pro b/src/proto/message.pro
index db09d85..faa0368 100644
--- a/src/proto/message.pro
+++ b/src/proto/message.pro
@@ -39,6 +39,7 @@
 void msg_puts_long_attr __ARGS((char_u *longstr, int attr));
 void msg_puts_long_len_attr __ARGS((char_u *longstr, int len, int attr));
 void msg_puts_attr __ARGS((char_u *s, int attr));
+void clear_sb_text __ARGS((void));
 int msg_use_printf __ARGS((void));
 void mch_errmsg __ARGS((char *str));
 void mch_msg __ARGS((char *str));
diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro
index 7369a64..6712cf1 100644
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -24,5 +24,6 @@
 int get_errorlist __ARGS((list_T *list));
 int set_errorlist __ARGS((list_T *list, int action));
 void ex_cbuffer __ARGS((exarg_T *eap));
+void ex_cexpr __ARGS((exarg_T *eap));
 void ex_helpgrep __ARGS((exarg_T *eap));
 /* vim: set ft=c : */
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
index b5b6eec..fd6a1fa 100644
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -37,6 +37,7 @@
 void setcursor __ARGS((void));
 int win_ins_lines __ARGS((win_T *wp, int row, int line_count, int invalid, int mayclear));
 int win_del_lines __ARGS((win_T *wp, int row, int line_count, int invalid, int mayclear));
+int screen_ins_lines __ARGS((int off, int row, int line_count, int end, win_T *wp));
 int screen_del_lines __ARGS((int off, int row, int line_count, int end, int force, win_T *wp));
 int showmode __ARGS((void));
 void unshowmode __ARGS((int force));
diff --git a/src/quickfix.c b/src/quickfix.c
index d465787..5847ae1 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -88,7 +88,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 int	qf_init_ext __ARGS((char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
 static void	qf_new_list __ARGS((void));
 static int	qf_add_entry __ARGS((qfline_T **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid));
 static void	qf_msg __ARGS((void));
@@ -124,7 +124,7 @@
 {
     if (efile == NULL)
 	return FAIL;
-    return qf_init_ext(efile, curbuf, errorformat, newlist,
+    return qf_init_ext(efile, curbuf, NULL, errorformat, newlist,
 						    (linenr_T)0, (linenr_T)0);
 }
 
@@ -137,9 +137,10 @@
  * Return -1 for error, number of errors for success.
  */
     static int
-qf_init_ext(efile, buf, errorformat, newlist, lnumfirst, lnumlast)
+qf_init_ext(efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast)
     char_u	    *efile;
     buf_T	    *buf;
+    typval_T	    *tv;
     char_u	    *errorformat;
     int		    newlist;		/* TRUE: start a new error list */
     linenr_T	    lnumfirst;		/* first line number to use */
@@ -176,6 +177,8 @@
     char_u	    *directory = NULL;
     char_u	    *currfile = NULL;
     char_u	    *tail = NULL;
+    char_u	    *p_str = NULL;
+    listitem_T	    *p_li = NULL;
     struct dir_stack_T  *file_stack = NULL;
     regmatch_T	    regmatch;
     static struct fmtpattern
@@ -222,7 +225,7 @@
  * regex prog.  Only a few % characters are allowed.
  */
     /* Use the local value of 'errorformat' if it's set. */
-    if (errorformat == p_efm && *buf->b_p_efm != NUL)
+    if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
 	efm = buf->b_p_efm;
     else
 	efm = errorformat;
@@ -432,6 +435,14 @@
     /* Always ignore case when looking for a matching error. */
     regmatch.rm_ic = TRUE;
 
+    if (tv != NULL)
+    {
+	if (tv->v_type == VAR_STRING)
+	    p_str = tv->vval.v_string;
+	else if (tv->v_type == VAR_LIST)
+	    p_li = tv->vval.v_list->lv_first;
+    }
+
     /*
      * Read the lines in the error file one by one.
      * Try to recognize one of the error formats in each line.
@@ -441,10 +452,57 @@
 	/* Get the next line. */
 	if (fd == NULL)
 	{
-	    if (buflnum > lnumlast)
-		break;
-	    vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE),
-							     CMDBUFFSIZE - 2);
+	    if (tv != NULL)
+	    {
+		int len;
+
+		if (tv->v_type == VAR_STRING)
+		{
+		    /* Get the next line from the supplied string */
+		    char_u *p;
+
+		    if (!*p_str) /* Reached the end of the string */
+			break;
+
+		    p = vim_strchr(p_str, '\n');
+		    if (p)
+			len = p - p_str + 1;
+		    else
+			len = STRLEN(p_str);
+
+		    if (len > CMDBUFFSIZE - 2)
+			vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2);
+		    else
+			vim_strncpy(IObuff, p_str, len);
+
+		    p_str += len;
+		}
+		else if (tv->v_type == VAR_LIST)
+		{
+		    /* Get the next line from the supplied list */
+		    while (p_li && p_li->li_tv.v_type != VAR_STRING)
+			p_li = p_li->li_next;	/* Skip non-string items */
+
+		    if (!p_li)			/* End of the list */
+			break;
+
+		    len = STRLEN(p_li->li_tv.vval.v_string);
+		    if (len > CMDBUFFSIZE - 2)
+			len = CMDBUFFSIZE - 2;
+
+		    vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len);
+
+		    p_li = p_li->li_next;	/* next item */
+		}
+	    }
+	    else
+	    {
+		/* Get the next line from the supplied buffer */
+		if (buflnum > lnumlast)
+		    break;
+		vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE),
+			    CMDBUFFSIZE - 2);
+	    }
 	}
 	else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
 	    break;
@@ -1446,7 +1504,6 @@
     int		idx1 = 1;
     int		idx2 = -1;
     int		need_return = TRUE;
-    int		last_printed = 1;
     char_u	*arg = eap->arg;
     int		all = eap->forceit;	/* if not :cl!, only show
 						   recognised errors */
@@ -1467,7 +1524,6 @@
     if (idx2 < 0)
 	idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
 
-    more_back_used = TRUE;
     if (qf_lists[qf_curlist].qf_nonevalid)
 	all = TRUE;
     qfp = qf_lists[qf_curlist].qf_start;
@@ -1478,79 +1534,59 @@
 	    if (need_return)
 	    {
 		msg_putchar('\n');
+		if (got_int)
+		    break;
 		need_return = FALSE;
 	    }
-	    if (more_back == 0)
-	    {
-		fname = NULL;
-		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);
-		msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index
-			? hl_attr(HLF_L) : hl_attr(HLF_D));
-		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, hl_attr(HLF_N));
-		if (qfp->qf_pattern != NULL)
-		{
-		    qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
-		    STRCAT(IObuff, ":");
-		    msg_puts(IObuff);
-		}
-		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)
+	    fname = NULL;
+	    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);
+	    msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index
+					   ? hl_attr(HLF_L) : hl_attr(HLF_D));
+	    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, hl_attr(HLF_N));
+	    if (qfp->qf_pattern != NULL)
+	    {
+		qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
+		STRCAT(IObuff, ":");
+		msg_puts(IObuff);
+	    }
+	    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 */
-		need_return = TRUE;
-		last_printed = i;
-	    }
+	    msg_prt_line(IObuff, FALSE);
+	    out_flush();		/* show one line at a time */
+	    need_return = TRUE;
 	}
-	if (more_back)
-	{
-	    /* scrolling backwards from the more-prompt */
-	    /* TODO: compute the number of items from the screen lines */
-	    more_back = more_back * 2 - 1;
-	    while (i > last_printed - more_back && i > idx1)
-	    {
-		do
-		{
-		    qfp = qfp->qf_prev;
-		    --i;
-		}
-		while (i > idx1 && !qfp->qf_valid && !all);
-	    }
-	    more_back = 0;
-	}
-	else
-	{
-	    qfp = qfp->qf_next;
-	    ++i;
-	}
+
+	qfp = qfp->qf_next;
+	++i;
 	ui_breakcheck();
     }
-    more_back_used = FALSE;
 }
 
 /*
@@ -2330,7 +2366,7 @@
 }
 
 /*
- * ":cfile" command.
+ * ":cfile"/":cgetfile"/":caddfile" commands.
  */
     void
 ex_cfile(eap)
@@ -2338,7 +2374,19 @@
 {
     if (*eap->arg != NUL)
 	set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE);
-    if (qf_init(p_ef, p_efm, TRUE) > 0 && eap->cmdidx == CMD_cfile)
+
+    /*
+     * This function is used by the :cfile, :cgetfile and :caddfile
+     * commands.
+     * :cfile always creates a new quickfix list and jumps to the
+     * first error.
+     * :cgetfile creates a new quickfix list but doesn't jump to the
+     * first error.
+     * :caddfile adds to an existing quickfix list. If there is no
+     * quickfix list then a new list is created.
+     */
+    if (qf_init(p_ef, p_efm, eap->cmdidx != CMD_caddfile) > 0
+						  && eap->cmdidx == CMD_cfile)
 	qf_jump(0, 0, eap->forceit);		/* display first error */
 }
 
@@ -2917,11 +2965,32 @@
 		|| 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);
+	    qf_init_ext(NULL, buf, NULL, p_efm, TRUE, eap->line1, eap->line2);
     }
 }
 
 /*
+ * ":cexpr {expr}" command.
+ */
+    void
+ex_cexpr(eap)
+    exarg_T	*eap;
+{
+    typval_T	*tv;
+
+    tv = eval_expr(eap->arg, NULL);
+    if (!tv || (tv->v_type != VAR_STRING && tv->v_type != VAR_LIST) ||
+	(tv->v_type == VAR_STRING && !tv->vval.v_string) ||
+	(tv->v_type == VAR_LIST && !tv->vval.v_list))
+	return;
+
+    if (qf_init_ext(NULL, NULL, tv, p_efm, TRUE, (linenr_T)0, (linenr_T)0) > 0)
+	qf_jump(0, 0, eap->forceit);		/* display first error */
+
+    clear_tv(tv);
+}
+
+/*
  * ":helpgrep {pattern}"
  */
     void
diff --git a/src/screen.c b/src/screen.c
index c07691e..a3f3e0b 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -169,7 +169,6 @@
 #endif
 static int win_do_lines __ARGS((win_T *wp, int row, int line_count, int mayclear, int del));
 static void win_rest_invalid __ARGS((win_T *wp));
-static int screen_ins_lines __ARGS((int, int, int, int, win_T *wp));
 static void msg_pos_mode __ARGS((void));
 #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
 static int fillchar_status __ARGS((int *attr, int is_curwin));
@@ -7618,7 +7617,7 @@
  *
  * return FAIL for failure, OK for success.
  */
-    static int
+    int
 screen_ins_lines(off, row, line_count, end, wp)
     int		off;
     int		row;
diff --git a/src/tag.c b/src/tag.c
index f46ae72..03f498b 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -770,11 +770,6 @@
 #endif
 		    break;
 		}
-#if 0
-		/* avoid the need to hit <CR> when jumping to another file */
-		msg_scrolled = 0;
-		redraw_all_later(NOT_VALID);
-#endif
 		cur_match = i - 1;
 	    }
 
diff --git a/src/version.h b/src/version.h
index a2074a2..03557c2 100644
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT	"vim70aa"
 #define VIM_VERSION_SHORT	"7.0aa"
 #define VIM_VERSION_MEDIUM	"7.0aa ALPHA"
-#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Jul 25)"
-#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Jul 25, compiled "
+#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Jul 27)"
+#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Jul 27, compiled "