r1881 - trunk/vim

matthew at linuxfromscratch.org matthew at linuxfromscratch.org
Sat Dec 8 15:50:07 PST 2007


Author: matthew
Date: 2007-12-08 16:50:07 -0700 (Sat, 08 Dec 2007)
New Revision: 1881

Added:
   trunk/vim/vim-7.1-fixes-4.patch
Log:
Add latest upstream patches for Vim

Added: trunk/vim/vim-7.1-fixes-4.patch
===================================================================
--- trunk/vim/vim-7.1-fixes-4.patch	                        (rev 0)
+++ trunk/vim/vim-7.1-fixes-4.patch	2007-12-08 23:50:07 UTC (rev 1881)
@@ -0,0 +1,9592 @@
+Submitted By: Matt Burgess (matthew at linuxfromscratch dot org)
+Date: 2007-12-09
+Initial Package Version: 7.1
+Origin: Upstream
+Upstream Status: Applied
+Description: Contains patches 001-171 from upstream excluding patches 003, 007,
+             041, 065, 070, 072, 080, 088, 091, 092, 124, 126, 128, 129, 134,
+             146, 158 and 168 as they are for "extras" (e.g. Mac, Windows) only.
+
+diff -Naur vim71.orig/runtime/doc/change.txt vim71/runtime/doc/change.txt
+--- vim71.orig/runtime/doc/change.txt	2007-05-12 10:18:46.000000000 +0000
++++ vim71/runtime/doc/change.txt	2007-12-08 20:34:50.000000000 +0000
+@@ -1571,6 +1571,10 @@
+ 			in their original order, right before the sorted
+ 			lines.
+ 
++			If {pattern} is empty (e.g. // is specified), the
++			last search pattern is used.  This allows trying out
++			a pattern first.
++
+ Note that using ":sort" with ":global" doesn't sort the matching lines, it's
+ quite useless.
+ 
+diff -Naur vim71.orig/runtime/doc/eval.txt vim71/runtime/doc/eval.txt
+--- vim71.orig/runtime/doc/eval.txt	2007-05-12 10:18:46.000000000 +0000
++++ vim71/runtime/doc/eval.txt	2007-12-08 20:34:52.000000000 +0000
+@@ -1,4 +1,4 @@
+-*eval.txt*      For Vim version 7.1.  Last change: 2007 May 11
++*eval.txt*      For Vim version 7.1.  Last change: 2007 Sep 25
+ 
+ 
+ 		  VIM REFERENCE MANUAL    by Bram Moolenaar
+@@ -1557,6 +1557,7 @@
+ changenr()			Number  current change number
+ char2nr( {expr})		Number	ASCII value of first char in {expr}
+ cindent( {lnum})		Number	C indent for line {lnum}
++clearmatches()			None	clear all matches
+ col( {expr})			Number	column nr of cursor or mark
+ complete({startcol}, {matches})	String  set Insert mode completion
+ complete_add( {expr})		Number	add completion match
+@@ -1602,7 +1603,7 @@
+ foldtextresult( {lnum})		String	text for closed fold at {lnum}
+ foreground( )			Number	bring the Vim window to the foreground
+ function( {name})		Funcref reference to function {name}
+-garbagecollect()		none	free memory, breaking cyclic references
++garbagecollect( [at_exit])	none	free memory, breaking cyclic references
+ get( {list}, {idx} [, {def}])	any	get item {idx} from {list} or {def}
+ get( {dict}, {key} [, {def}])	any	get item {key} from {dict} or {def}
+ getbufline( {expr}, {lnum} [, {end}])
+@@ -1622,6 +1623,7 @@
+ getline( {lnum})		String	line {lnum} of current buffer
+ getline( {lnum}, {end})		List	lines {lnum} to {end} of current buffer
+ getloclist({nr})		List	list of location list items
++getmatches()			List	list of current matches
+ getpos( {expr})			List	position of cursor, mark, etc.
+ getqflist()			List	list of quickfix items
+ getreg( [{regname} [, 1]])	String	contents of register
+@@ -1676,7 +1678,10 @@
+ 				String	check for mappings matching {name}
+ match( {expr}, {pat}[, {start}[, {count}]])
+ 				Number	position where {pat} matches in {expr}
++matchadd( {group}, {pattern}[, {priority}[, {id}]])
++				Number	highlight {pattern} with {group}
+ matcharg( {nr})			List	arguments of |:match|
++matchdelete( {id})		Number	delete match identified by {id}
+ matchend( {expr}, {pat}[, {start}[, {count}]])
+ 				Number	position where {pat} ends in {expr}
+ matchlist( {expr}, {pat}[, {start}[, {count}]])
+@@ -1731,6 +1736,7 @@
+ setline( {lnum}, {line})	Number	set line {lnum} to {line}
+ setloclist( {nr}, {list}[, {action}])
+ 				Number	modify location list using {list}
++setmatches( {list})		Number	restore a list of matches
+ setpos( {expr}, {list})		none	set the {expr} position to {list}
+ setqflist( {list}[, {action}])	Number	modify quickfix list using {list}
+ setreg( {n}, {v}[, {opt}])	Number	set register to value and type
+@@ -2012,6 +2018,10 @@
+ 		feature, -1 is returned.
+ 		See |C-indenting|.
+ 
++clearmatches()						*clearmatches()*
++		Clears all matches previously defined by |matchadd()| and the
++		|:match| commands.
++
+ 							*col()*
+ col({expr})	The result is a Number, which is the byte index of the column
+ 		position given with {expr}.  The accepted positions are:
+@@ -2020,6 +2030,10 @@
+ 			    number of characters in the cursor line plus one)
+ 		    'x	    position of mark x (if the mark is not set, 0 is
+ 			    returned)
++		Additionally {expr} can be [lnum, col]: a |List| with the line
++		and column number. Most useful when the column is "$", to get
++		the las column of a specific line.  When "lnum" or "col" is
++		out of range then col() returns zero.
+ 		To get the line number use |line()|.  To get both use
+ 		|getpos()|.
+ 		For the screen column position use |virtcol()|.
+@@ -2659,7 +2673,7 @@
+ 		{name} can be a user defined function or an internal function.
+ 
+ 
+-garbagecollect()					*garbagecollect()*
++garbagecollect([at_exit])				*garbagecollect()*
+ 		Cleanup unused |Lists| and |Dictionaries| that have circular
+ 		references.  There is hardly ever a need to invoke this
+ 		function, as it is automatically done when Vim runs out of
+@@ -2669,6 +2683,9 @@
+ 		This is useful if you have deleted a very big |List| and/or
+ 		|Dictionary| with circular references in a script that runs
+ 		for a long time.
++		When the optional "at_exit" argument is one, garbage
++		collection will also be done when exiting Vim, if it wasn't
++		done before.  This is useful when checking for memory leaks.
+ 
+ get({list}, {idx} [, {default}])			*get()*
+ 		Get item {idx} from |List| {list}.  When this item is not
+@@ -2824,6 +2841,8 @@
+ 		given file {fname}.
+ 		If {fname} is a directory, 0 is returned.
+ 		If the file {fname} can't be found, -1 is returned.
++		If the size of {fname} is too big to fit in a Number then -2
++		is returned.
+ 
+ getfontname([{name}])					*getfontname()*
+ 		Without an argument returns the name of the normal font being
+@@ -2912,6 +2931,28 @@
+ 		returned.  For an invalid window number {nr}, an empty list is
+ 		returned. Otherwise, same as getqflist().
+ 
++getmatches()						*getmatches()*
++		Returns a |List| with all matches previously defined by
++		|matchadd()| and the |:match| commands.  |getmatches()| is
++		useful in combination with |setmatches()|, as |setmatches()|
++		can restore a list of matches saved by |getmatches()|.
++		Example: >
++			:echo getmatches()
++<			[{'group': 'MyGroup1', 'pattern': 'TODO',
++			'priority': 10, 'id': 1}, {'group': 'MyGroup2',
++			'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
++			:let m = getmatches()
++			:call clearmatches()
++			:echo getmatches()
++<			[] >
++			:call setmatches(m)
++			:echo getmatches()
++<			[{'group': 'MyGroup1', 'pattern': 'TODO',
++			'priority': 10, 'id': 1}, {'group': 'MyGroup2',
++			'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
++			:unlet m
++<
++
+ getqflist()						*getqflist()*
+ 		Returns a list with all the current quickfix errors.  Each
+ 		list item is a dictionary with these entries:
+@@ -3616,6 +3657,44 @@
+ 		the pattern.  'smartcase' is NOT used.  The matching is always
+ 		done like 'magic' is set and 'cpoptions' is empty.
+ 
++					*matchadd()* *E798* *E799* *E801*
++matchadd({group}, {pattern}[, {priority}[, {id}]])
++		Defines a pattern to be highlighted in the current window (a
++		"match").  It will be highlighted with {group}.  Returns an
++		identification number (ID), which can be used to delete the
++		match using |matchdelete()|.
++
++		The optional {priority} argument assigns a priority to the
++		match.  A match with a high priority will have its
++		highlighting overrule that of a match with a lower priority.
++		A priority is specified as an integer (negative numbers are no
++		exception).  If the {priority} argument is not specified, the
++		default priority is 10.  The priority of 'hlsearch' is zero,
++		hence all matches with a priority greater than zero will
++		overrule it.  Syntax highlighting (see 'syntax') is a separate
++		mechanism, and regardless of the chosen priority a match will
++		always overrule syntax highlighting.
++
++		The optional {id} argument allows the request for a specific
++		match ID.  If a specified ID is already taken, an error
++		message will appear and the match will not be added.  An ID
++		is specified as a positive integer (zero excluded).  IDs 1, 2
++		and 3 are reserved for |:match|, |:2match| and |:3match|,
++		respectively.  If the {id} argument is not specified,
++		|matchadd()| automatically chooses a free ID.
++
++		The number of matches is not limited, as it is the case with
++		the |:match| commands.
++
++		Example: >
++			:highlight MyGroup ctermbg=green guibg=green
++			:let m = matchadd("MyGroup", "TODO")
++<		Deletion of the pattern: >
++			:call matchdelete(m)
++
++<		A list of matches defined by |matchadd()| and |:match| are
++		available from |getmatches()|.  All matches can be deleted in
++		one operation by |clearmatches()|.
+ 
+ matcharg({nr})							*matcharg()*
+ 		Selects the {nr} match item, as set with a |:match|,
+@@ -3625,8 +3704,15 @@
+ 			The pattern used.
+ 		When {nr} is not 1, 2 or 3 returns an empty |List|.
+ 		When there is no match item set returns ['', ''].
+-		This is usef to save and restore a |:match|.
+-
++		This is useful to save and restore a |:match|.
++		Highlighting matches using the |:match| commands are limited
++		to three matches. |matchadd()| does not have this limitation.
++
++matchdelete({id})			       *matchdelete()* *E802* *E803*
++		Deletes a match with ID {id} previously defined by |matchadd()|
++		or one of the |:match| commands.  Returns 0 if succesfull,
++		otherwise -1.  See example for |matchadd()|.  All matches can
++		be deleted in one operation by |clearmatches()|.
+ 
+ matchend({expr}, {pat}[, {start}[, {count}]])			*matchend()*
+ 		Same as match(), but return the index of first character after
+@@ -4379,7 +4465,13 @@
+ 		When {nr} is zero the current window is used. For a location
+ 		list window, the displayed location list is modified.  For an
+ 		invalid window number {nr}, -1 is returned.
+-		Otherwise, same as setqflist().
++		Otherwise, same as |setqflist()|.
++		Also see |location-list|.
++
++setmatches({list})					*setmatches()*
++		Restores a list of matches saved by |getmatches()|.  Returns 0
++		if succesfull, otherwise -1.  All current matches are cleared
++		before the list is restored.  See example for |getmatches()|.
+ 
+ 							*setpos()*
+ setpos({expr}, {list})
+@@ -5022,14 +5114,12 @@
+ 		position, the returned Number will be the column at the end of
+ 		the <Tab>.  For example, for a <Tab> in column 1, with 'ts'
+ 		set to 8, it returns 8.
+-		For the use of {expr} see |col()|.  Additionally you can use
+-		[lnum, col]: a |List| with the line and column number.  When
+-		"lnum" or "col" is out of range then virtcol() returns zero.
+-		When 'virtualedit' is used it can be [lnum, col, off], where
++		For the byte position use |col()|.
++		For the use of {expr} see |col()|.
++		When 'virtualedit' is used {expr} can be [lnum, col, off], where
+ 		"off" is the offset in screen columns from the start of the
+ 		character.  E.g., a position within a <Tab> or after the last
+ 		character.
+-		For the byte position use |col()|.
+ 		When Virtual editing is active in the current mode, a position
+ 		beyond the end of the line can be returned. |'virtualedit'|
+ 		The accepted positions are:
+diff -Naur vim71.orig/runtime/doc/options.txt vim71/runtime/doc/options.txt
+--- vim71.orig/runtime/doc/options.txt	2007-05-12 10:18:47.000000000 +0000
++++ vim71/runtime/doc/options.txt	2007-12-08 20:34:51.000000000 +0000
+@@ -1,4 +1,4 @@
+-*options.txt*	For Vim version 7.1.  Last change: 2007 May 11
++*options.txt*	For Vim version 7.1.  Last change: 2007 Aug 10
+ 
+ 
+ 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
+@@ -2415,8 +2415,8 @@
+ 	When mixing vertically and horizontally split windows, a minimal size
+ 	is computed and some windows may be larger if there is room.  The
+ 	'eadirection' option tells in which direction the size is affected.
+-	Changing the height of a window can be avoided by setting
+-	'winfixheight'.
++	Changing the height and width of a window can be avoided by setting
++	'winfixheight' and 'winfixwidth', respectively.
+ 
+ 						*'equalprg'* *'ep'*
+ 'equalprg' 'ep'		string	(default "")
+diff -Naur vim71.orig/runtime/doc/pattern.txt vim71/runtime/doc/pattern.txt
+--- vim71.orig/runtime/doc/pattern.txt	2007-05-12 10:18:47.000000000 +0000
++++ vim71/runtime/doc/pattern.txt	2007-12-08 20:34:50.000000000 +0000
+@@ -1212,7 +1212,10 @@
+ 		{group} must exist at the moment this command is executed.
+ 
+ 		The {group} highlighting still applies when a character is
+-		to be highlighted for 'hlsearch'.
++		to be highlighted for 'hlsearch', as the highlighting for
++		matches is given higher priority than that of 'hlsearch'.
++		Syntax highlighting (see 'syntax') is also overruled by
++		matches.
+ 
+ 		Note that highlighting the last used search pattern with
+ 		'hlsearch' is used in all windows, while the pattern defined
+@@ -1226,8 +1229,15 @@
+ 		display you may get unexpected results.  That is because Vim
+ 		looks for a match in the line where redrawing starts.
+ 
+-		Also see |matcharg()|, it returns the highlight group and
+-		pattern of a previous :match command.
++		Also see |matcharg()|and |getmatches()|. The former returns
++		the highlight group and pattern of a previous |:match|
++		command.  The latter returns a list with highlight groups and
++		patterns defined by both |matchadd()| and |:match|.
++
++		Highlighting matches using |:match| are limited to three
++		matches (aside from |:match|, |:2match| and |:3match|are
++		available). |matchadd()| does not have this limitation and in
++		addition makes it possible to prioritize matches.
+ 
+ 		Another example, which highlights all characters in virtual
+ 		column 72 and more: >
+diff -Naur vim71.orig/runtime/doc/pi_paren.txt vim71/runtime/doc/pi_paren.txt
+--- vim71.orig/runtime/doc/pi_paren.txt	2007-05-12 10:18:47.000000000 +0000
++++ vim71/runtime/doc/pi_paren.txt	2007-12-08 20:34:51.000000000 +0000
+@@ -12,8 +12,8 @@
+ You can avoid loading this plugin by setting the "loaded_matchparen" variable: >
+ 	:let loaded_matchparen = 1
+ 
+-The plugin installs CursorMoved autocommands to redefine the match
+-highlighting.
++The plugin installs CursorMoved, CursorMovedI and WinEnter autocommands to
++redefine the match highlighting.
+ 
+ To disable the plugin after it was loaded use this command: >
+ 
+diff -Naur vim71.orig/runtime/doc/usr_41.txt vim71/runtime/doc/usr_41.txt
+--- vim71.orig/runtime/doc/usr_41.txt	2007-05-12 10:18:48.000000000 +0000
++++ vim71/runtime/doc/usr_41.txt	2007-12-08 20:34:50.000000000 +0000
+@@ -763,13 +763,22 @@
+ 	foldtextresult()	get the text displayed for a closed fold
+ 
+ Syntax and highlighting:
++	clearmatches()		clear all matches defined by |matchadd()| and
++				the |:match| commands
++	getmatches()		get all matches defined by |matchadd()| and
++				the |:match| commands
+ 	hlexists()		check if a highlight group exists
+ 	hlID()			get ID of a highlight group
+ 	synID()			get syntax ID at a specific position
+ 	synIDattr()		get a specific attribute of a syntax ID
+ 	synIDtrans()		get translated syntax ID
+ 	diff_hlID()		get highlight ID for diff mode at a position
++	matchadd()		define a pattern to highlight (a "match")
+ 	matcharg()		get info about |:match| arguments
++	matchdelete()		delete a match defined by |matchadd()| or a
++				|:match| command
++	setmatches()		restore a list of matches saved by
++				|getmatches()|
+ 
+ Spelling:
+ 	spellbadword()		locate badly spelled word at or after cursor
+diff -Naur vim71.orig/runtime/doc/windows.txt vim71/runtime/doc/windows.txt
+--- vim71.orig/runtime/doc/windows.txt	2007-05-12 10:18:49.000000000 +0000
++++ vim71/runtime/doc/windows.txt	2007-12-08 20:34:51.000000000 +0000
+@@ -132,7 +132,8 @@
+ 		the same file.  Make new window N high (default is to use half
+ 		the height of the current window).  Reduces the current window
+ 		height to create room (and others, if the 'equalalways' option
+-		is set and 'eadirection' isn't "hor").
++		is set, 'eadirection' isn't "hor", and one of them is higher
++		than the current or the new window).
+ 		Note: CTRL-S does not work on all terminals and might block
+ 		further input, use CTRL-Q to get going again.
+ 		Also see |++opt| and |+cmd|.
+@@ -140,9 +141,13 @@
+ CTRL-W CTRL-V						*CTRL-W_CTRL-V*
+ CTRL-W v						*CTRL-W_v*
+ :[N]vs[plit] [++opt] [+cmd] [file]			*:vs* *:vsplit*
+-		Like |:split|, but split vertically.  If 'equalalways' is set
+-		and 'eadirection' isn't "ver" the windows will be spread out
+-		horizontally, unless a width was specified.
++		Like |:split|, but split vertically.  The windows will be
++		spread out horizontally if
++		1. a width was not specified,
++		2. 'equalalways' is set,
++		3. 'eadirection' isn't "ver", and
++		4. one of the other windows are wider than the current or new
++		   window.
+ 		Note: In other places CTRL-Q does the same as CTRL-V, but here
+ 		it doesn't!
+ 
+diff -Naur vim71.orig/runtime/filetype.vim vim71/runtime/filetype.vim
+--- vim71.orig/runtime/filetype.vim	2007-05-10 15:14:37.000000000 +0000
++++ vim71/runtime/filetype.vim	2007-12-08 20:34:50.000000000 +0000
+@@ -1,7 +1,7 @@
+ " Vim support file to detect file types
+ "
+ " Maintainer:	Bram Moolenaar <Bram at vim.org>
+-" Last Change:	2007 May 10
++" Last Change:	2007 May 15
+ 
+ " Listen very carefully, I will say this only once
+ if exists("did_load_filetypes")
+@@ -1286,7 +1286,7 @@
+ au BufNewFile,BufRead *.it,*.ih			setf ppwiz
+ 
+ " Oracle Pro*C/C++
+-au BufNewFile,BufRead .pc			setf proc
++au BufNewFile,BufRead *.pc			setf proc
+ 
+ " Privoxy actions file
+ au BufNewFile,BufRead *.action			setf privoxy
+diff -Naur vim71.orig/runtime/menu.vim vim71/runtime/menu.vim
+--- vim71.orig/runtime/menu.vim	2007-01-09 13:31:40.000000000 +0000
++++ vim71/runtime/menu.vim	2007-12-08 20:34:53.000000000 +0000
+@@ -2,7 +2,7 @@
+ " You can also use this as a start for your own set of menus.
+ "
+ " Maintainer:	Bram Moolenaar <Bram at vim.org>
+-" Last Change:	2007 Jan 09
++" Last Change:	2007 Nov 19
+ 
+ " Note that ":an" (short for ":anoremenu") is often used to make a menu work
+ " in all modes and avoid side effects from mappings defined by the user.
+@@ -658,7 +658,6 @@
+   let buf = 1
+   while buf <= bufnr('$')
+     if bufexists(buf) && !isdirectory(bufname(buf)) && buflisted(buf)
+-					    \ && !getbufvar(buf, "&bufsecret")
+       let s:bmenu_count = s:bmenu_count + 1
+     endif
+     let buf = buf + 1
+@@ -671,7 +670,6 @@
+   let buf = 1
+   while buf <= bufnr('$')
+     if bufexists(buf) && !isdirectory(bufname(buf)) && buflisted(buf)
+-					    \ && !getbufvar(buf, "&bufsecret")
+       call <SID>BMFilename(bufname(buf), buf)
+     endif
+     let buf = buf + 1
+diff -Naur vim71.orig/runtime/plugin/matchparen.vim vim71/runtime/plugin/matchparen.vim
+--- vim71.orig/runtime/plugin/matchparen.vim	2006-10-12 20:05:05.000000000 +0000
++++ vim71/runtime/plugin/matchparen.vim	2007-12-08 20:34:51.000000000 +0000
+@@ -1,6 +1,6 @@
+ " Vim plugin for showing matching parens
+ " Maintainer:  Bram Moolenaar <Bram at vim.org>
+-" Last Change: 2006 Oct 12
++" Last Change: 2007 Aug 8
+ 
+ " Exit quickly when:
+ " - this plugin was already loaded (or disabled)
+@@ -13,7 +13,7 @@
+ 
+ augroup matchparen
+   " Replace all matchparen autocommands
+-  autocmd! CursorMoved,CursorMovedI * call s:Highlight_Matching_Pair()
++  autocmd! CursorMoved,CursorMovedI,WinEnter * call s:Highlight_Matching_Pair()
+ augroup END
+ 
+ " Skip the rest if it was already done.
+@@ -62,25 +62,37 @@
+   " Figure out the arguments for searchpairpos().
+   " Restrict the search to visible lines with "stopline".
+   " And avoid searching very far (e.g., for closed folds and long lines)
++  " The "viewable" variables give a range in which we can scroll while keeping
++  " the cursor at the same position
++  " adjustedScrolloff accounts for very large numbers of scrolloff
++  let adjustedScrolloff = min([&scrolloff, (line('w$') - line('w0')) / 2])
++  let bottom_viewable = min([line('$'), c_lnum + &lines - adjustedScrolloff - 2])
++  let top_viewable = max([1, c_lnum-&lines+adjustedScrolloff + 2])
++  " one of these stoplines will be adjusted below, but the current values are
++  " minimal boundaries within the current window
++  let stoplinebottom = line('w$')
++  let stoplinetop = line('w0')
+   if i % 2 == 0
+     let s_flags = 'nW'
+     let c2 = plist[i + 1]
+     if has("byte_offset") && has("syntax_items") && &smc > 0
+       let stopbyte = min([line2byte("$"), line2byte(".") + col(".") + &smc * 2])
+-      let stopline = min([line('w$'), byte2line(stopbyte)])
++      let stopline = min([bottom_viewable, byte2line(stopbyte)])
+     else
+-      let stopline = min([line('w$'), c_lnum + 100])
++      let stopline = min([bottom_viewable, c_lnum + 100])
+     endif
++    let stoplinebottom = stopline
+   else
+     let s_flags = 'nbW'
+     let c2 = c
+     let c = plist[i - 1]
+     if has("byte_offset") && has("syntax_items") && &smc > 0
+       let stopbyte = max([1, line2byte(".") + col(".") - &smc * 2])
+-      let stopline = max([line('w0'), byte2line(stopbyte)])
++      let stopline = max([top_viewable, byte2line(stopbyte)])
+     else
+-      let stopline = max([line('w0'), c_lnum - 100])
++      let stopline = max([top_viewable, c_lnum - 100])
+     endif
++    let stoplinetop = stopline
+   endif
+   if c == '['
+     let c = '\['
+@@ -106,7 +118,7 @@
+   endif
+ 
+   " If a match is found setup match highlighting.
+-  if m_lnum > 0 && m_lnum >= line('w0') && m_lnum <= line('w$')
++  if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom 
+     exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
+ 	  \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+     let w:paren_hl_on = 1
+@@ -114,7 +126,8 @@
+ endfunction
+ 
+ " Define commands that will disable and enable the plugin.
+-command! NoMatchParen 3match none | unlet! g:loaded_matchparen | au! matchparen
+-command! DoMatchParen runtime plugin/matchparen.vim | doau CursorMoved
++command! NoMatchParen windo 3match none | unlet! g:loaded_matchparen |
++	  \ au! matchparen
++command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved
+ 
+ let &cpo = cpo_save
+diff -Naur vim71.orig/src/auto/configure vim71/src/auto/configure
+--- vim71.orig/src/auto/configure	2007-05-12 11:49:09.000000000 +0000
++++ vim71/src/auto/configure	2007-12-08 20:34:53.000000000 +0000
+@@ -3843,7 +3843,9 @@
+   fi
+ 
+   if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+-    if test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then
++    if test "x$MACOSX" = "xyes"; then
++      MZSCHEME_LIBS="-framework PLT_MzScheme"
++    elif test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then
+       MZSCHEME_LIBS="${vi_cv_path_mzscheme_pfx}/lib/libmzscheme.a ${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"
+     else
+       MZSCHEME_LIBS="-L${vi_cv_path_mzscheme_pfx}/lib -lmzscheme -lmzgc"
+@@ -10263,8 +10265,9 @@
+ 
+ 
+ 
++
+ for ac_header in stdarg.h stdlib.h string.h sys/select.h sys/utsname.h \
+-	termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h termio.h \
++	termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h sys/types.h termio.h \
+ 	iconv.h langinfo.h unistd.h stropts.h errno.h \
+ 	sys/resource.h sys/systeminfo.h locale.h \
+ 	sys/stream.h sys/ptem.h termios.h libc.h sys/statfs.h \
+diff -Naur vim71.orig/src/buffer.c vim71/src/buffer.c
+--- vim71.orig/src/buffer.c	2007-05-10 15:25:59.000000000 +0000
++++ vim71/src/buffer.c	2007-12-08 20:34:53.000000000 +0000
+@@ -171,6 +171,13 @@
+ 	    /* Put the cursor on the first line. */
+ 	    curwin->w_cursor.lnum = 1;
+ 	    curwin->w_cursor.col = 0;
++
++	    /* Set or reset 'modified' before executing autocommands, so that
++	     * it can be changed there. */
++	    if (!readonlymode && !bufempty())
++		changed();
++	    else if (retval != FAIL)
++		unchanged(curbuf, FALSE);
+ #ifdef FEAT_AUTOCMD
+ # ifdef FEAT_EVAL
+ 	    apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
+@@ -194,16 +201,16 @@
+     /* When reading stdin, the buffer contents always needs writing, so set
+      * the changed flag.  Unless in readonly mode: "ls | gview -".
+      * When interrupted and 'cpoptions' contains 'i' set changed flag. */
+-    if ((read_stdin && !readonlymode && !bufempty())
++    if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
+ #ifdef FEAT_AUTOCMD
+ 		|| modified_was_set	/* ":set modified" used in autocmd */
+ # ifdef FEAT_EVAL
+ 		|| (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
+ # endif
+ #endif
+-		|| (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL))
++       )
+ 	changed();
+-    else if (retval != FAIL)
++    else if (retval != FAIL && !read_stdin)
+ 	unchanged(curbuf, FALSE);
+     save_file_ff(curbuf);		/* keep this fileformat */
+ 
+@@ -495,6 +502,7 @@
+     buf->b_start_eol = TRUE;
+ #ifdef FEAT_MBYTE
+     buf->b_p_bomb = FALSE;
++    buf->b_start_bomb = FALSE;
+ #endif
+     buf->b_ml.ml_mfp = NULL;
+     buf->b_ml.ml_flags = ML_EMPTY;		/* empty buffer */
+@@ -4167,29 +4175,35 @@
+      * mess up the full path name, even though it starts with a '/'.
+      * Also expand when there is ".." in the file name, try to remove it,
+      * because "c:/src/../README" is equal to "c:/README".
++     * Similarly "c:/src//file" is equal to "c:/src/file".
+      * For MS-Windows also expand names like "longna~1" to "longname".
+      */
+ #ifdef UNIX
+     return FullName_save(fname, TRUE);
+ #else
+-    if (!vim_isAbsName(fname) || strstr((char *)fname, "..") != NULL
+-#if defined(MSWIN) || defined(DJGPP)
++    if (!vim_isAbsName(fname)
++	    || strstr((char *)fname, "..") != NULL
++	    || strstr((char *)fname, "//") != NULL
++# ifdef BACKSLASH_IN_FILENAME
++	    || strstr((char *)fname, "\\\\") != NULL
++# endif
++# if defined(MSWIN) || defined(DJGPP)
+ 	    || vim_strchr(fname, '~') != NULL
+-#endif
++# endif
+ 	    )
+ 	return FullName_save(fname, FALSE);
+ 
+     fname = vim_strsave(fname);
+ 
+-#ifdef USE_FNAME_CASE
+-# ifdef USE_LONG_FNAME
++# ifdef USE_FNAME_CASE
++#  ifdef USE_LONG_FNAME
+     if (USE_LONG_FNAME)
+-# endif
++#  endif
+     {
+ 	if (fname != NULL)
+ 	    fname_case(fname, 0);	/* set correct case for file name */
+     }
+-#endif
++# endif
+ 
+     return fname;
+ #endif
+@@ -4853,7 +4867,7 @@
+ 	     */
+ 	    for (e = s; *e != ':' && *e != NUL; ++e)
+ 		if (e[0] == '\\' && e[1] == ':')
+-		    STRCPY(e, e + 1);
++		    mch_memmove(e, e + 1, STRLEN(e));
+ 	    if (*e == NUL)
+ 		end = TRUE;
+ 
+@@ -5507,11 +5521,11 @@
+ 
+ #ifdef FEAT_AUTOCMD
+     if (!aucmd)		    /* Don't trigger BufDelete autocommands here. */
+-	++autocmd_block;
++	block_autocmds();
+ #endif
+     close_buffer(NULL, buf, DOBUF_WIPE);
+ #ifdef FEAT_AUTOCMD
+     if (!aucmd)
+-	--autocmd_block;
++	unblock_autocmds();
+ #endif
+ }
+diff -Naur vim71.orig/src/charset.c vim71/src/charset.c
+--- vim71.orig/src/charset.c	2007-03-24 20:10:37.000000000 +0000
++++ vim71/src/charset.c	2007-12-08 20:34:51.000000000 +0000
+@@ -207,7 +207,10 @@
+ 	    }
+ 	    while (c <= c2)
+ 	    {
+-		if (!do_isalpha || isalpha(c)
++		/* Use the MB_ functions here, because isalpha() doesn't
++		 * work properly when 'encoding' is "latin1" and the locale is
++		 * "C".  */
++		if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)
+ #ifdef FEAT_FKMAP
+ 			|| (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))
+ #endif
+@@ -929,6 +932,23 @@
+ }
+ 
+ /*
++ * return TRUE if 'c' is a valid file-name character or a wildcard character
++ * Assume characters above 0x100 are valid (multi-byte).
++ * Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]")
++ * returns false.
++ */
++    int
++vim_isfilec_or_wc(c)
++    int c;
++{
++    char_u buf[2];
++
++    buf[0] = (char_u)c;
++    buf[1] = NUL;
++    return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf);
++}
++
++/*
+  * return TRUE if 'c' is a printable character
+  * Assume characters above 0x100 are printable (multi-byte), except for
+  * Unicode.
+@@ -1898,7 +1918,7 @@
+ {
+     for ( ; *p; ++p)
+ 	if (rem_backslash(p))
+-	    STRCPY(p, p + 1);
++	    mch_memmove(p, p + 1, STRLEN(p));
+ }
+ 
+ /*
+diff -Naur vim71.orig/src/configure.in vim71/src/configure.in
+--- vim71.orig/src/configure.in	2007-05-12 09:19:27.000000000 +0000
++++ vim71/src/configure.in	2007-12-08 20:34:53.000000000 +0000
+@@ -423,7 +423,9 @@
+   fi
+ 
+   if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+-    if test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then
++    if test "x$MACOSX" = "xyes"; then
++      MZSCHEME_LIBS="-framework PLT_MzScheme"
++    elif test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then
+       MZSCHEME_LIBS="${vi_cv_path_mzscheme_pfx}/lib/libmzscheme.a ${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"
+     else
+       MZSCHEME_LIBS="-L${vi_cv_path_mzscheme_pfx}/lib -lmzscheme -lmzgc"
+@@ -2024,7 +2026,7 @@
+ fi
+ 
+ AC_CHECK_HEADERS(stdarg.h stdlib.h string.h sys/select.h sys/utsname.h \
+-	termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h termio.h \
++	termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h sys/types.h termio.h \
+ 	iconv.h langinfo.h unistd.h stropts.h errno.h \
+ 	sys/resource.h sys/systeminfo.h locale.h \
+ 	sys/stream.h sys/ptem.h termios.h libc.h sys/statfs.h \
+diff -Naur vim71.orig/src/diff.c vim71/src/diff.c
+--- vim71.orig/src/diff.c	2007-02-16 00:18:41.000000000 +0000
++++ vim71/src/diff.c	2007-12-08 20:34:53.000000000 +0000
+@@ -791,6 +791,9 @@
+     }
+     mch_remove(tmp_orig);
+ 
++    /* force updating cursor position on screen */
++    curwin->w_valid_cursor.lnum = 0;
++
+     diff_redraw(TRUE);
+ 
+ theend:
+@@ -840,11 +843,11 @@
+ 		    tmp_orig, tmp_new);
+ 	    append_redir(cmd, p_srr, tmp_diff);
+ #ifdef FEAT_AUTOCMD
+-	    ++autocmd_block;	/* Avoid ShellCmdPost stuff */
++	    block_autocmds();	/* Avoid ShellCmdPost stuff */
+ #endif
+ 	    (void)call_shell(cmd, SHELL_FILTER|SHELL_SILENT|SHELL_DOOUT);
+ #ifdef FEAT_AUTOCMD
+-	    --autocmd_block;
++	    unblock_autocmds();
+ #endif
+ 	    vim_free(cmd);
+ 	}
+@@ -949,11 +952,11 @@
+ # endif
+ 		eap->arg);
+ #ifdef FEAT_AUTOCMD
+-	++autocmd_block;	/* Avoid ShellCmdPost stuff */
++	block_autocmds();	/* Avoid ShellCmdPost stuff */
+ #endif
+ 	(void)call_shell(buf, SHELL_FILTER | SHELL_COOKED);
+ #ifdef FEAT_AUTOCMD
+-	--autocmd_block;
++	unblock_autocmds();
+ #endif
+     }
+ 
+@@ -1310,7 +1313,7 @@
+ 		    dp->df_count[idx_new] += -off;
+ 		off = 0;
+ 	    }
+-	    for (i = idx_orig; i < idx_new + !notset; ++i)
++	    for (i = idx_orig; i < idx_new; ++i)
+ 		if (curtab->tp_diffbuf[i] != NULL)
+ 		    dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i]
+ 						       - dp->df_lnum[i] + off;
+diff -Naur vim71.orig/src/digraph.c vim71/src/digraph.c
+--- vim71.orig/src/digraph.c	2006-05-02 18:24:04.000000000 +0000
++++ vim71/src/digraph.c	2007-12-08 20:34:51.000000000 +0000
+@@ -2028,7 +2028,7 @@
+ 
+     ++no_mapping;
+     ++allow_keys;
+-    c = safe_vgetc();
++    c = plain_vgetc();
+     --no_mapping;
+     --allow_keys;
+     if (c != ESC)		/* ESC cancels CTRL-K */
+@@ -2050,7 +2050,7 @@
+ #endif
+ 	++no_mapping;
+ 	++allow_keys;
+-	cc = safe_vgetc();
++	cc = plain_vgetc();
+ 	--no_mapping;
+ 	--allow_keys;
+ 	if (cc != ESC)	    /* ESC cancels CTRL-K */
+@@ -2349,8 +2349,10 @@
+ 
+     if (*curbuf->b_p_keymap == NUL)
+     {
+-	/* Stop any active keymap and clear the table. */
++	/* Stop any active keymap and clear the table.  Also remove
++	 * b:keymap_name, as no keymap is active now. */
+ 	keymap_unload();
++	do_cmdline_cmd((char_u *)"unlet! b:keymap_name");
+     }
+     else
+     {
+@@ -2500,7 +2502,6 @@
+ 
+     ga_clear(&curbuf->b_kmap_ga);
+     curbuf->b_kmap_state &= ~KEYMAP_LOADED;
+-    do_cmdline_cmd((char_u *)"unlet! b:keymap_name");
+ #ifdef FEAT_WINDOWS
+     status_redraw_curbuf();
+ #endif
+diff -Naur vim71.orig/src/edit.c vim71/src/edit.c
+--- vim71.orig/src/edit.c	2007-05-07 19:43:55.000000000 +0000
++++ vim71/src/edit.c	2007-12-08 20:34:53.000000000 +0000
+@@ -129,6 +129,7 @@
+ 
+ static void ins_ctrl_x __ARGS((void));
+ static int  has_compl_option __ARGS((int dict_opt));
++static int  ins_compl_accept_char __ARGS((int c));
+ static int ins_compl_add __ARGS((char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int adup));
+ static int  ins_compl_equal __ARGS((compl_T *match, char_u *str, int len));
+ static void ins_compl_longest_match __ARGS((compl_T *match));
+@@ -754,8 +755,9 @@
+ 		    continue;
+ 		}
+ 
+-		/* A printable, non-white character: Add to "compl_leader". */
+-		if (vim_isprintc(c) && !vim_iswhite(c))
++		/* A non-white character that fits in with the current
++		 * completion: Add to "compl_leader". */
++		if (ins_compl_accept_char(c))
+ 		{
+ 		    ins_compl_addleader(c);
+ 		    continue;
+@@ -788,7 +790,7 @@
+ 	    ins_redraw(FALSE);
+ 	    ++no_mapping;
+ 	    ++allow_keys;
+-	    c = safe_vgetc();
++	    c = plain_vgetc();
+ 	    --no_mapping;
+ 	    --allow_keys;
+ 	    if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
+@@ -981,7 +983,7 @@
+ #ifdef FEAT_NETBEANS_INTG
+ 	case K_F21:	/* NetBeans command */
+ 	    ++no_mapping;		/* don't map the next key hits */
+-	    i = safe_vgetc();
++	    i = plain_vgetc();
+ 	    --no_mapping;
+ 	    netbeans_keycommand(i);
+ 	    break;
+@@ -2053,11 +2055,44 @@
+ }
+ 
+ /*
++ * Return TRUE when character "c" is part of the item currently being
++ * completed.  Used to decide whether to abandon complete mode when the menu
++ * is visible.
++ */
++    static int
++ins_compl_accept_char(c)
++    int c;
++{
++    if (ctrl_x_mode & CTRL_X_WANT_IDENT)
++	/* When expanding an identifier only accept identifier chars. */
++	return vim_isIDc(c);
++
++    switch (ctrl_x_mode)
++    {
++	case CTRL_X_FILES:
++	    /* When expanding file name only accept file name chars. But not
++	     * path separators, so that "proto/<Tab>" expands files in
++	     * "proto", not "proto/" as a whole */
++	    return vim_isfilec(c) && !vim_ispathsep(c);
++
++	case CTRL_X_CMDLINE:
++	case CTRL_X_OMNI:
++	    /* Command line and Omni completion can work with just about any
++	     * printable character, but do stop at white space. */
++	    return vim_isprintc(c) && !vim_iswhite(c);
++
++	case CTRL_X_WHOLE_LINE:
++	    /* For while line completion a space can be part of the line. */
++	    return vim_isprintc(c);
++    }
++    return vim_iswordc(c);
++}
++
++/*
+  * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
+  * case of the originally typed text is used, and the case of the completed
+  * text is inferred, ie this tries to work out what case you probably wanted
+  * the rest of the word to be in -- webb
+- * TODO: make this work for multi-byte characters.
+  */
+     int
+ ins_compl_add_infercase(str, len, icase, fname, dir, flags)
+@@ -2068,54 +2103,147 @@
+     int		dir;
+     int		flags;
+ {
++    char_u	*p;
++    int		i, c;
++    int		actual_len;		/* Take multi-byte characters */
++    int		actual_compl_length;	/* into account. */
++    int		*wca;		        /* Wide character array. */
+     int		has_lower = FALSE;
+     int		was_letter = FALSE;
+-    int		idx;
+ 
+-    if (p_ic && curbuf->b_p_inf && len < IOSIZE)
++    if (p_ic && curbuf->b_p_inf && len > 0)
+     {
+-	/* Infer case of completed part -- webb */
+-	/* Use IObuff, str would change text in buffer! */
+-	vim_strncpy(IObuff, str, len);
++	/* Infer case of completed part. */
+ 
+-	/* Rule 1: Were any chars converted to lower? */
+-	for (idx = 0; idx < compl_length; ++idx)
++	/* Find actual length of completion. */
++#ifdef FEAT_MBYTE
++	if (has_mbyte)
+ 	{
+-	    if (islower(compl_orig_text[idx]))
++	    p = str;
++	    actual_len = 0;
++	    while (*p != NUL)
+ 	    {
+-		has_lower = TRUE;
+-		if (isupper(IObuff[idx]))
+-		{
+-		    /* Rule 1 is satisfied */
+-		    for (idx = compl_length; idx < len; ++idx)
+-			IObuff[idx] = TOLOWER_LOC(IObuff[idx]);
+-		    break;
+-		}
++		mb_ptr_adv(p);
++		++actual_len;
++	    }
++	}
++	else
++#endif
++	    actual_len = len;
++
++	/* Find actual length of original text. */
++#ifdef FEAT_MBYTE
++	if (has_mbyte)
++	{
++	    p = compl_orig_text;
++	    actual_compl_length = 0;
++	    while (*p != NUL)
++	    {
++		mb_ptr_adv(p);
++		++actual_compl_length;
+ 	    }
+ 	}
++	else
++#endif
++	    actual_compl_length = compl_length;
+ 
+-	/*
+-	 * Rule 2: No lower case, 2nd consecutive letter converted to
+-	 * upper case.
+-	 */
+-	if (!has_lower)
++	/* Allocate wide character array for the completion and fill it. */
++	wca = (int *)alloc(actual_len * sizeof(int));
++	if (wca != NULL)
+ 	{
+-	    for (idx = 0; idx < compl_length; ++idx)
++	    p = str;
++	    for (i = 0; i < actual_len; ++i)
++#ifdef FEAT_MBYTE
++		if (has_mbyte)
++		    wca[i] = mb_ptr2char_adv(&p);
++		else
++#endif
++		    wca[i] = *(p++);
++
++	    /* Rule 1: Were any chars converted to lower? */
++	    p = compl_orig_text;
++	    for (i = 0; i < actual_compl_length; ++i)
+ 	    {
+-		if (was_letter && isupper(compl_orig_text[idx])
+-						      && islower(IObuff[idx]))
++#ifdef FEAT_MBYTE
++		if (has_mbyte)
++		    c = mb_ptr2char_adv(&p);
++		else
++#endif
++		    c = *(p++);
++		if (MB_ISLOWER(c))
+ 		{
+-		    /* Rule 2 is satisfied */
+-		    for (idx = compl_length; idx < len; ++idx)
+-			IObuff[idx] = TOUPPER_LOC(IObuff[idx]);
+-		    break;
++		    has_lower = TRUE;
++		    if (MB_ISUPPER(wca[i]))
++		    {
++			/* Rule 1 is satisfied. */
++			for (i = actual_compl_length; i < actual_len; ++i)
++			    wca[i] = MB_TOLOWER(wca[i]);
++			break;
++		    }
+ 		}
+-		was_letter = isalpha(compl_orig_text[idx]);
+ 	    }
+-	}
+ 
+-	/* Copy the original case of the part we typed */
+-	STRNCPY(IObuff, compl_orig_text, compl_length);
++	    /*
++	     * Rule 2: No lower case, 2nd consecutive letter converted to
++	     * upper case.
++	     */
++	    if (!has_lower)
++	    {
++		p = compl_orig_text;
++		for (i = 0; i < actual_compl_length; ++i)
++		{
++#ifdef FEAT_MBYTE
++		    if (has_mbyte)
++			c = mb_ptr2char_adv(&p);
++		    else
++#endif
++			c = *(p++);
++		    if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i]))
++		    {
++			/* Rule 2 is satisfied. */
++			for (i = actual_compl_length; i < actual_len; ++i)
++			    wca[i] = MB_TOUPPER(wca[i]);
++			break;
++		    }
++		    was_letter = MB_ISLOWER(c) || MB_ISUPPER(c);
++		}
++	    }
++
++	    /* Copy the original case of the part we typed. */
++	    p = compl_orig_text;
++	    for (i = 0; i < actual_compl_length; ++i)
++	    {
++#ifdef FEAT_MBYTE
++		if (has_mbyte)
++		    c = mb_ptr2char_adv(&p);
++		else
++#endif
++		    c = *(p++);
++		if (MB_ISLOWER(c))
++		    wca[i] = MB_TOLOWER(wca[i]);
++		else if (MB_ISUPPER(c))
++		    wca[i] = MB_TOUPPER(wca[i]);
++	    }
++
++	    /*
++	     * Generate encoding specific output from wide character array.
++	     * Multi-byte characters can occupy up to five bytes more than
++	     * ASCII characters, and we also need one byte for NUL, so stay
++	     * six bytes away from the edge of IObuff.
++	     */
++	    p = IObuff;
++	    i = 0;
++	    while (i < actual_len && (p - IObuff + 6) < IOSIZE)
++#ifdef FEAT_MBYTE
++		if (has_mbyte)
++		    p += (*mb_char2bytes)(wca[i++], p);
++		else
++#endif
++		    *(p++) = wca[i++];
++	    *p = NUL;
++
++	    vim_free(wca);
++	}
+ 
+ 	return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
+ 								flags, FALSE);
+@@ -2842,6 +2970,7 @@
+ 			/*
+ 			 * Add the other matches on the line
+ 			 */
++			ptr = buf;
+ 			while (!got_int)
+ 			{
+ 			    /* Find start of the next word.  Skip white
+@@ -2851,7 +2980,7 @@
+ 				break;
+ 			    wstart = ptr;
+ 
+-			    /* Find end of the word and add it. */
++			    /* Find end of the word. */
+ #ifdef FEAT_MBYTE
+ 			    if (has_mbyte)
+ 				/* Japanese words may have characters in
+@@ -2868,9 +2997,12 @@
+ 			    else
+ #endif
+ 				ptr = find_word_end(ptr);
+-			    add_r = ins_compl_add_infercase(wstart,
+-				    (int)(ptr - wstart),
+-				    p_ic, files[i], *dir, 0);
++
++			    /* Add the word. Skip the regexp match. */
++			    if (wstart != regmatch->startp[0])
++				add_r = ins_compl_add_infercase(wstart,
++					(int)(ptr - wstart),
++					p_ic, files[i], *dir, 0);
+ 			}
+ 		    }
+ 		    if (add_r == OK)
+@@ -3032,8 +3164,11 @@
+     p = line + curwin->w_cursor.col;
+     mb_ptr_back(line, p);
+ 
+-    /* Stop completion when the whole word was deleted. */
+-    if ((int)(p - line) - (int)compl_col <= 0)
++    /* Stop completion when the whole word was deleted.  For Omni completion
++     * allow the word to be deleted, we won't match everything. */
++    if ((int)(p - line) - (int)compl_col < 0
++	    || ((int)(p - line) - (int)compl_col == 0
++		&& (ctrl_x_mode & CTRL_X_OMNI) == 0))
+ 	return K_BS;
+ 
+     /* Deleted more than what was used to find matches or didn't finish
+@@ -3250,8 +3385,8 @@
+     if (c != Ctrl_R && vim_is_ctrl_x_key(c))
+ 	edit_submode_extra = NULL;
+ 
+-    /* Ignore end of Select mode mapping */
+-    if (c == K_SELECT)
++    /* Ignore end of Select mode mapping and mouse scroll buttons. */
++    if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP)
+ 	return retval;
+ 
+     /* Set "compl_get_longest" when finding the first matches. */
+@@ -4495,14 +4630,13 @@
+ 	curs_col = curwin->w_cursor.col;
+ 	compl_pending = 0;
+ 
+-	/* if this same ctrl_x_mode has been interrupted use the text from
++	/* If this same ctrl_x_mode has been interrupted use the text from
+ 	 * "compl_startpos" to the cursor as a pattern to add a new word
+ 	 * instead of expand the one before the cursor, in word-wise if
+-	 * "compl_startpos"
+-	 * is not in the same line as the cursor then fix it (the line has
+-	 * been split because it was longer than 'tw').  if SOL is set then
+-	 * skip the previous pattern, a word at the beginning of the line has
+-	 * been inserted, we'll look for that  -- Acevedo. */
++	 * "compl_startpos" is not in the same line as the cursor then fix it
++	 * (the line has been split because it was longer than 'tw').  if SOL
++	 * is set then skip the previous pattern, a word at the beginning of
++	 * the line has been inserted, we'll look for that  -- Acevedo. */
+ 	if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
+ 					    && compl_cont_mode == ctrl_x_mode)
+ 	{
+@@ -5128,10 +5262,7 @@
+     i = 0;
+     for (;;)
+     {
+-	do
+-	    nc = safe_vgetc();
+-	while (nc == K_IGNORE || nc == K_VER_SCROLLBAR
+-						    || nc == K_HOR_SCROLLBAR);
++	nc = plain_vgetc();
+ #ifdef FEAT_CMDL_INFO
+ 	if (!(State & CMDLINE)
+ # ifdef FEAT_MBYTE
+@@ -6313,8 +6444,10 @@
+ {
+     vim_free(last_insert);
+     last_insert = NULL;
++# ifdef FEAT_INS_EXPAND
+     vim_free(compl_orig_text);
+     compl_orig_text = NULL;
++# endif
+ }
+ #endif
+ 
+@@ -7215,6 +7348,8 @@
+ 		p = ml_get_curline();
+ 		if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
+ 		    return TRUE;
++		/* Need to get the line again after cin_islabel(). */
++		p = ml_get_curline();
+ 		if (curwin->w_cursor.col > 2
+ 			&& p[curwin->w_cursor.col - 1] == ':'
+ 			&& p[curwin->w_cursor.col - 2] == ':')
+@@ -7477,7 +7612,7 @@
+      * deleted when ESC is hit.
+      */
+     ++no_mapping;
+-    regname = safe_vgetc();
++    regname = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+     LANGMAP_ADJUST(regname, TRUE);
+ #endif
+@@ -7488,7 +7623,7 @@
+ #ifdef FEAT_CMDL_INFO
+ 	add_to_showcmd_c(literally);
+ #endif
+-	regname = safe_vgetc();
++	regname = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 	LANGMAP_ADJUST(regname, TRUE);
+ #endif
+@@ -7579,7 +7714,7 @@
+      * deleted when ESC is hit.
+      */
+     ++no_mapping;
+-    c = safe_vgetc();
++    c = plain_vgetc();
+     --no_mapping;
+     switch (c)
+     {
+@@ -7998,7 +8133,8 @@
+     /*
+      * 0^D and ^^D: remove all indent.
+      */
+-    if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
++    if (c == Ctrl_D && (lastc == '0' || lastc == '^')
++						  && curwin->w_cursor.col > 0)
+     {
+ 	--curwin->w_cursor.col;
+ 	(void)del_char(FALSE);		/* delete the '^' or '0' */
+@@ -8518,15 +8654,16 @@
+     int		up;
+ {
+     pos_T	tpos;
+-# if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
+-    win_T	*old_curwin;
++# if defined(FEAT_WINDOWS)
++    win_T	*old_curwin = curwin;
++# endif
++# ifdef FEAT_INS_EXPAND
++    int		did_scroll = FALSE;
+ # endif
+ 
+     tpos = curwin->w_cursor;
+ 
+ # if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
+-    old_curwin = curwin;
+-
+     /* Currently the mouse coordinates are only known in the GUI. */
+     if (gui.in_use && mouse_row >= 0 && mouse_col >= 0)
+     {
+@@ -8543,10 +8680,23 @@
+ # endif
+ 	undisplay_dollar();
+ 
+-    if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+-	scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
+-    else
+-	scroll_redraw(up, 3L);
++# ifdef FEAT_INS_EXPAND
++    /* Don't scroll the window in which completion is being done. */
++    if (!pum_visible()
++#  if defined(FEAT_WINDOWS)
++	    || curwin != old_curwin
++#  endif
++	    )
++# endif
++    {
++	if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
++	    scroll_redraw(up, (long)(curwin->w_botline - curwin->w_topline));
++	else
++	    scroll_redraw(up, 3L);
++# ifdef FEAT_INS_EXPAND
++	did_scroll = TRUE;
++# endif
++    }
+ 
+ # if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
+     curwin->w_redr_status = TRUE;
+@@ -8555,6 +8705,17 @@
+     curbuf = curwin->w_buffer;
+ # endif
+ 
++# ifdef FEAT_INS_EXPAND
++    /* The popup menu may overlay the window, need to redraw it.
++     * TODO: Would be more efficient to only redraw the windows that are
++     * overlapped by the popup menu. */
++    if (pum_visible() && did_scroll)
++    {
++	redraw_all_later(NOT_VALID);
++	ins_compl_show_pum();
++    }
++# endif
++
+     if (!equalpos(curwin->w_cursor, tpos))
+     {
+ 	start_arrow(&tpos);
+@@ -9257,7 +9418,7 @@
+      * mode message to be deleted when ESC is hit */
+     ++no_mapping;
+     ++allow_keys;
+-    c = safe_vgetc();
++    c = plain_vgetc();
+     --no_mapping;
+     --allow_keys;
+     if (IS_SPECIAL(c) || mod_mask)	    /* special key */
+@@ -9289,7 +9450,7 @@
+ 	}
+ 	++no_mapping;
+ 	++allow_keys;
+-	cc = safe_vgetc();
++	cc = plain_vgetc();
+ 	--no_mapping;
+ 	--allow_keys;
+ 	if (cc != ESC)
+diff -Naur vim71.orig/src/eval.c vim71/src/eval.c
+--- vim71.orig/src/eval.c	2007-05-07 19:47:32.000000000 +0000
++++ vim71/src/eval.c	2007-12-08 20:34:53.000000000 +0000
+@@ -369,17 +369,17 @@
+ static int ex_let_vars __ARGS((char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars));
+ static char_u *skip_var_list __ARGS((char_u *arg, int *var_count, int *semicolon));
+ static char_u *skip_var_one __ARGS((char_u *arg));
+-static void list_hashtable_vars __ARGS((hashtab_T *ht, char_u *prefix, int empty));
+-static void list_glob_vars __ARGS((void));
+-static void list_buf_vars __ARGS((void));
+-static void list_win_vars __ARGS((void));
++static void list_hashtable_vars __ARGS((hashtab_T *ht, char_u *prefix, int empty, int *first));
++static void list_glob_vars __ARGS((int *first));
++static void list_buf_vars __ARGS((int *first));
++static void list_win_vars __ARGS((int *first));
+ #ifdef FEAT_WINDOWS
+-static void list_tab_vars __ARGS((void));
++static void list_tab_vars __ARGS((int *first));
+ #endif
+-static void list_vim_vars __ARGS((void));
+-static void list_script_vars __ARGS((void));
+-static void list_func_vars __ARGS((void));
+-static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg));
++static void list_vim_vars __ARGS((int *first));
++static void list_script_vars __ARGS((int *first));
++static void list_func_vars __ARGS((int *first));
++static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg, int *first));
+ static char_u *ex_let_one __ARGS((char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op));
+ static int check_changedtick __ARGS((char_u *arg));
+ static char_u *get_lval __ARGS((char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int quiet, int fne_flags));
+@@ -475,6 +475,7 @@
+ static void f_changenr __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_char2nr __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_cindent __ARGS((typval_T *argvars, typval_T *rettv));
++static void f_clearmatches __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_col __ARGS((typval_T *argvars, typval_T *rettv));
+ #if defined(FEAT_INS_EXPAND)
+ static void f_complete __ARGS((typval_T *argvars, typval_T *rettv));
+@@ -529,6 +530,7 @@
+ static void f_getftime __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_getftype __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_getline __ARGS((typval_T *argvars, typval_T *rettv));
++static void f_getmatches __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_getpos __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_getqflist __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_getreg __ARGS((typval_T *argvars, typval_T *rettv));
+@@ -577,7 +579,9 @@
+ static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_match __ARGS((typval_T *argvars, typval_T *rettv));
++static void f_matchadd __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_matcharg __ARGS((typval_T *argvars, typval_T *rettv));
++static void f_matchdelete __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_matchend __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_matchlist __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_matchstr __ARGS((typval_T *argvars, typval_T *rettv));
+@@ -618,6 +622,7 @@
+ static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_setline __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv));
++static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv));
+@@ -672,7 +677,7 @@
+ static void f_writefile __ARGS((typval_T *argvars, typval_T *rettv));
+ 
+ static int list2fpos __ARGS((typval_T *arg, pos_T *posp, int *fnump));
+-static pos_T *var2fpos __ARGS((typval_T *varp, int lnum, int *fnum));
++static pos_T *var2fpos __ARGS((typval_T *varp, int dollar_lnum, int *fnum));
+ static int get_env_len __ARGS((char_u **arg));
+ static int get_id_len __ARGS((char_u **arg));
+ static int get_name_len __ARGS((char_u **arg, char_u **alias, int evaluate, int verbose));
+@@ -699,8 +704,8 @@
+ static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname));
+ static void vars_clear_ext __ARGS((hashtab_T *ht, int free_val));
+ static void delete_var __ARGS((hashtab_T *ht, hashitem_T *hi));
+-static void list_one_var __ARGS((dictitem_T *v, char_u *prefix));
+-static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string));
++static void list_one_var __ARGS((dictitem_T *v, char_u *prefix, int *first));
++static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string, int *first));
+ static void set_var __ARGS((char_u *name, typval_T *varp, int copy));
+ static int var_check_ro __ARGS((int flags, char_u *name));
+ static int var_check_fixed __ARGS((int flags, char_u *name));
+@@ -992,20 +997,20 @@
+     char_u	*value;
+     int		value_len;
+ {
+-    size_t	len;
++    int		len;
+ 
+     if (redir_lval == NULL)
+ 	return;
+ 
+     if (value_len == -1)
+-	len = STRLEN(value);	/* Append the entire string */
++	len = (int)STRLEN(value);	/* Append the entire string */
+     else
+-	len = value_len;	/* Append only "value_len" characters */
++	len = value_len;		/* Append only "value_len" characters */
+ 
+-    if (ga_grow(&redir_ga, (int)len) == OK)
++    if (ga_grow(&redir_ga, len) == OK)
+     {
+ 	mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
+-	redir_ga.ga_len += (int)len;
++	redir_ga.ga_len += len;
+     }
+     else
+ 	var_redir_stop();
+@@ -1313,7 +1318,6 @@
+ {
+     hashitem_T	*hi;
+ 
+-    clear_tv(&vimvars[idx].vv_tv);
+     vimvars[idx].vv_tv = *save_tv;
+     if (vimvars[idx].vv_type == VAR_UNKNOWN)
+     {
+@@ -1357,7 +1361,6 @@
+ 
+     if (p_verbose == 0)
+ 	--emsg_off;
+-    vimvars[VV_VAL].vv_str = NULL;
+     restore_vimvar(VV_VAL, &save_val);
+ 
+     return list;
+@@ -1411,7 +1414,8 @@
+ }
+ 
+ 
+-#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO)
++#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \
++	|| defined(FEAT_COMPL_FUNC) || defined(PROTO)
+ /*
+  * Call some vimL function and return the result in "*rettv".
+  * Uses argv[argc] for the function arguments.
+@@ -1484,6 +1488,7 @@
+     return ret;
+ }
+ 
++# if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO)
+ /*
+  * Call vimL function "func" and return the result as a string.
+  * Returns NULL when calling the function fails.
+@@ -1506,8 +1511,9 @@
+     clear_tv(&rettv);
+     return retval;
+ }
++# endif
+ 
+-#if defined(FEAT_COMPL_FUNC) || defined(PROTO)
++# if defined(FEAT_COMPL_FUNC) || defined(PROTO)
+ /*
+  * Call vimL function "func" and return the result as a number.
+  * Returns -1 when calling the function fails.
+@@ -1530,7 +1536,7 @@
+     clear_tv(&rettv);
+     return retval;
+ }
+-#endif
++# endif
+ 
+ /*
+  * Call vimL function "func" and return the result as a list
+@@ -1556,9 +1562,9 @@
+ 
+     return rettv.vval.v_list;
+ }
+-
+ #endif
+ 
++
+ /*
+  * Save the current function call pointer, and set it to NULL.
+  * Used when executing autocommands and for ":source".
+@@ -1691,6 +1697,7 @@
+     int		semicolon = 0;
+     char_u	op[2];
+     char_u	*argend;
++    int		first = TRUE;
+ 
+     argend = skip_var_list(arg, &var_count, &semicolon);
+     if (argend == NULL)
+@@ -1707,19 +1714,19 @@
+ 	    EMSG(_(e_invarg));
+ 	else if (!ends_excmd(*arg))
+ 	    /* ":let var1 var2" */
+-	    arg = list_arg_vars(eap, arg);
++	    arg = list_arg_vars(eap, arg, &first);
+ 	else if (!eap->skip)
+ 	{
+ 	    /* ":let" */
+-	    list_glob_vars();
+-	    list_buf_vars();
+-	    list_win_vars();
++	    list_glob_vars(&first);
++	    list_buf_vars(&first);
++	    list_win_vars(&first);
+ #ifdef FEAT_WINDOWS
+-	    list_tab_vars();
++	    list_tab_vars(&first);
+ #endif
+-	    list_script_vars();
+-	    list_func_vars();
+-	    list_vim_vars();
++	    list_script_vars(&first);
++	    list_func_vars(&first);
++	    list_vim_vars(&first);
+ 	}
+ 	eap->nextcmd = check_nextcmd(arg);
+     }
+@@ -1924,10 +1931,11 @@
+  * If "empty" is TRUE also list NULL strings as empty strings.
+  */
+     static void
+-list_hashtable_vars(ht, prefix, empty)
++list_hashtable_vars(ht, prefix, empty, first)
+     hashtab_T	*ht;
+     char_u	*prefix;
+     int		empty;
++    int		*first;
+ {
+     hashitem_T	*hi;
+     dictitem_T	*di;
+@@ -1942,7 +1950,7 @@
+ 	    di = HI2DI(hi);
+ 	    if (empty || di->di_tv.v_type != VAR_STRING
+ 					   || di->di_tv.vval.v_string != NULL)
+-		list_one_var(di, prefix);
++		list_one_var(di, prefix, first);
+ 	}
+     }
+ }
+@@ -1951,32 +1959,38 @@
+  * List global variables.
+  */
+     static void
+-list_glob_vars()
++list_glob_vars(first)
++    int *first;
+ {
+-    list_hashtable_vars(&globvarht, (char_u *)"", TRUE);
++    list_hashtable_vars(&globvarht, (char_u *)"", TRUE, first);
+ }
+ 
+ /*
+  * List buffer variables.
+  */
+     static void
+-list_buf_vars()
++list_buf_vars(first)
++    int *first;
+ {
+     char_u	numbuf[NUMBUFLEN];
+ 
+-    list_hashtable_vars(&curbuf->b_vars.dv_hashtab, (char_u *)"b:", TRUE);
++    list_hashtable_vars(&curbuf->b_vars.dv_hashtab, (char_u *)"b:",
++								 TRUE, first);
+ 
+     sprintf((char *)numbuf, "%ld", (long)curbuf->b_changedtick);
+-    list_one_var_a((char_u *)"b:", (char_u *)"changedtick", VAR_NUMBER, numbuf);
++    list_one_var_a((char_u *)"b:", (char_u *)"changedtick", VAR_NUMBER,
++							       numbuf, first);
+ }
+ 
+ /*
+  * List window variables.
+  */
+     static void
+-list_win_vars()
++list_win_vars(first)
++    int *first;
+ {
+-    list_hashtable_vars(&curwin->w_vars.dv_hashtab, (char_u *)"w:", TRUE);
++    list_hashtable_vars(&curwin->w_vars.dv_hashtab,
++						 (char_u *)"w:", TRUE, first);
+ }
+ 
+ #ifdef FEAT_WINDOWS
+@@ -1984,9 +1998,11 @@
+  * List tab page variables.
+  */
+     static void
+-list_tab_vars()
++list_tab_vars(first)
++    int *first;
+ {
+-    list_hashtable_vars(&curtab->tp_vars.dv_hashtab, (char_u *)"t:", TRUE);
++    list_hashtable_vars(&curtab->tp_vars.dv_hashtab,
++						 (char_u *)"t:", TRUE, first);
+ }
+ #endif
+ 
+@@ -1994,39 +2010,44 @@
+  * List Vim variables.
+  */
+     static void
+-list_vim_vars()
++list_vim_vars(first)
++    int *first;
+ {
+-    list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE);
++    list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE, first);
+ }
+ 
+ /*
+  * List script-local variables, if there is a script.
+  */
+     static void
+-list_script_vars()
++list_script_vars(first)
++    int *first;
+ {
+     if (current_SID > 0 && current_SID <= ga_scripts.ga_len)
+-	list_hashtable_vars(&SCRIPT_VARS(current_SID), (char_u *)"s:", FALSE);
++	list_hashtable_vars(&SCRIPT_VARS(current_SID),
++						(char_u *)"s:", FALSE, first);
+ }
+ 
+ /*
+  * List function variables, if there is a function.
+  */
+     static void
+-list_func_vars()
++list_func_vars(first)
++    int *first;
+ {
+     if (current_funccal != NULL)
+ 	list_hashtable_vars(&current_funccal->l_vars.dv_hashtab,
+-						       (char_u *)"l:", FALSE);
++						(char_u *)"l:", FALSE, first);
+ }
+ 
+ /*
+  * List variables in "arg".
+  */
+     static char_u *
+-list_arg_vars(eap, arg)
++list_arg_vars(eap, arg, first)
+     exarg_T	*eap;
+     char_u	*arg;
++    int		*first;
+ {
+     int		error = FALSE;
+     int		len;
+@@ -2083,15 +2104,15 @@
+ 			{
+ 			    switch (*name)
+ 			    {
+-				case 'g': list_glob_vars(); break;
+-				case 'b': list_buf_vars(); break;
+-				case 'w': list_win_vars(); break;
++				case 'g': list_glob_vars(first); break;
++				case 'b': list_buf_vars(first); break;
++				case 'w': list_win_vars(first); break;
+ #ifdef FEAT_WINDOWS
+-				case 't': list_tab_vars(); break;
++				case 't': list_tab_vars(first); break;
+ #endif
+-				case 'v': list_vim_vars(); break;
+-				case 's': list_script_vars(); break;
+-				case 'l': list_func_vars(); break;
++				case 'v': list_vim_vars(first); break;
++				case 's': list_script_vars(first); break;
++				case 'l': list_func_vars(first); break;
+ 				default:
+ 					  EMSG2(_("E738: Can't list variables for %s"), name);
+ 			    }
+@@ -2108,7 +2129,9 @@
+ 			    *arg = NUL;
+ 			    list_one_var_a((char_u *)"",
+ 				    arg == arg_subsc ? name : name_start,
+-				    tv.v_type, s == NULL ? (char_u *)"" : s);
++				    tv.v_type,
++				    s == NULL ? (char_u *)"" : s,
++				    first);
+ 			    *arg = c;
+ 			    vim_free(tf);
+ 			}
+@@ -6105,6 +6128,7 @@
+     /* Only do this once. */
+     want_garbage_collect = FALSE;
+     may_garbage_collect = FALSE;
++    garbage_collect_at_exit = FALSE;
+ 
+     /*
+      * 1. Go through all accessible variables and mark all lists and dicts
+@@ -6681,7 +6705,7 @@
+     dict_T	*d = NULL;
+     typval_T	tvkey;
+     typval_T	tv;
+-    char_u	*key;
++    char_u	*key = NULL;
+     dictitem_T	*item;
+     char_u	*start = skipwhite(*arg + 1);
+     char_u	buf[NUMBUFLEN];
+@@ -6721,20 +6745,24 @@
+ 	    clear_tv(&tvkey);
+ 	    goto failret;
+ 	}
+-	key = get_tv_string_buf_chk(&tvkey, buf);
+-	if (key == NULL || *key == NUL)
++	if (evaluate)
+ 	{
+-	    /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
+-	    if (key != NULL)
+-		EMSG(_(e_emptykey));
+-	    clear_tv(&tvkey);
+-	    goto failret;
++	    key = get_tv_string_buf_chk(&tvkey, buf);
++	    if (key == NULL || *key == NUL)
++	    {
++		/* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
++		if (key != NULL)
++		    EMSG(_(e_emptykey));
++		clear_tv(&tvkey);
++		goto failret;
++	    }
+ 	}
+ 
+ 	*arg = skipwhite(*arg + 1);
+ 	if (eval1(arg, &tv, evaluate) == FAIL)	/* recursive! */
+ 	{
+-	    clear_tv(&tvkey);
++	    if (evaluate)
++		clear_tv(&tvkey);
+ 	    goto failret;
+ 	}
+ 	if (evaluate)
+@@ -6794,7 +6822,7 @@
+  * "numbuf" is used for a number.
+  * Does not put quotes around strings, as ":echo" displays values.
+  * When "copyID" is not NULL replace recursive lists and dicts with "...".
+- * May return NULL;
++ * May return NULL.
+  */
+     static char_u *
+ echo_string(tv, tofree, numbuf, copyID)
+@@ -6879,7 +6907,7 @@
+  * If the memory is allocated "tofree" is set to it, otherwise NULL.
+  * "numbuf" is used for a number.
+  * Puts quotes around strings, so that they can be parsed back by eval().
+- * May return NULL;
++ * May return NULL.
+  */
+     static char_u *
+ tv2string(tv, tofree, numbuf, copyID)
+@@ -7043,6 +7071,7 @@
+     {"changenr",	0, 0, f_changenr},
+     {"char2nr",		1, 1, f_char2nr},
+     {"cindent",		1, 1, f_cindent},
++    {"clearmatches",	0, 0, f_clearmatches},
+     {"col",		1, 1, f_col},
+ #if defined(FEAT_INS_EXPAND)
+     {"complete",	2, 2, f_complete},
+@@ -7082,7 +7111,7 @@
+     {"foldtextresult",	1, 1, f_foldtextresult},
+     {"foreground",	0, 0, f_foreground},
+     {"function",	1, 1, f_function},
+-    {"garbagecollect",	0, 0, f_garbagecollect},
++    {"garbagecollect",	0, 1, f_garbagecollect},
+     {"get",		2, 3, f_get},
+     {"getbufline",	2, 3, f_getbufline},
+     {"getbufvar",	2, 2, f_getbufvar},
+@@ -7099,6 +7128,7 @@
+     {"getftype",	1, 1, f_getftype},
+     {"getline",		1, 2, f_getline},
+     {"getloclist",	1, 1, f_getqflist},
++    {"getmatches",	0, 0, f_getmatches},
+     {"getpos",		1, 1, f_getpos},
+     {"getqflist",	0, 0, f_getqflist},
+     {"getreg",		0, 2, f_getreg},
+@@ -7149,7 +7179,9 @@
+     {"maparg",		1, 3, f_maparg},
+     {"mapcheck",	1, 3, f_mapcheck},
+     {"match",		2, 4, f_match},
++    {"matchadd",	2, 4, f_matchadd},
+     {"matcharg",	1, 1, f_matcharg},
++    {"matchdelete",	1, 1, f_matchdelete},
+     {"matchend",	2, 4, f_matchend},
+     {"matchlist",	2, 4, f_matchlist},
+     {"matchstr",	2, 4, f_matchstr},
+@@ -7190,6 +7222,7 @@
+     {"setcmdpos",	1, 1, f_setcmdpos},
+     {"setline",		2, 2, f_setline},
+     {"setloclist",	2, 3, f_setloclist},
++    {"setmatches",	1, 1, f_setmatches},
+     {"setpos",		2, 2, f_setpos},
+     {"setqflist",	1, 2, f_setqflist},
+     {"setreg",		2, 3, f_setreg},
+@@ -8240,6 +8273,20 @@
+ }
+ 
+ /*
++ * "clearmatches()" function
++ */
++/*ARGSUSED*/
++    static void
++f_clearmatches(argvars, rettv)
++    typval_T	*argvars;
++    typval_T	*rettv;
++{
++#ifdef FEAT_SEARCH_EXTRA
++    clear_matches(curwin);
++#endif
++}
++
++/*
+  * "col(string)" function
+  */
+     static void
+@@ -8682,7 +8729,7 @@
+     static int		fnum = 0;
+     static int		change_start = 0;
+     static int		change_end = 0;
+-    static hlf_T	hlID = 0;
++    static hlf_T	hlID = (hlf_T)0;
+     int			filler_lines;
+     int			col;
+ 
+@@ -9339,15 +9386,16 @@
+ {
+     typval_T	rettv;
+     char_u	*s;
++    int		retval = FAIL;
+ 
+     copy_tv(tv, &vimvars[VV_VAL].vv_tv);
+     s = expr;
+     if (eval1(&s, &rettv, TRUE) == FAIL)
+-	return FAIL;
++	goto theend;
+     if (*s != NUL)  /* check for trailing chars after expr */
+     {
+ 	EMSG2(_(e_invexpr2), s);
+-	return FAIL;
++	goto theend;
+     }
+     if (map)
+     {
+@@ -9366,10 +9414,12 @@
+ 	/* On type error, nothing has been removed; return FAIL to stop the
+ 	 * loop.  The error message was given by get_tv_number_chk(). */
+ 	if (error)
+-	    return FAIL;
++	    goto theend;
+     }
++    retval = OK;
++theend:
+     clear_tv(&vimvars[VV_VAL].vv_tv);
+-    return OK;
++    return retval;
+ }
+ 
+ /*
+@@ -9670,6 +9720,9 @@
+     /* This is postponed until we are back at the toplevel, because we may be
+      * using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]". */
+     want_garbage_collect = TRUE;
++
++    if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
++	garbage_collect_at_exit = TRUE;
+ }
+ 
+ /*
+@@ -9868,18 +9921,24 @@
+ 
+     ++no_mapping;
+     ++allow_keys;
+-    if (argvars[0].v_type == VAR_UNKNOWN)
+-	/* getchar(): blocking wait. */
+-	n = safe_vgetc();
+-    else if (get_tv_number_chk(&argvars[0], &error) == 1)
+-	/* getchar(1): only check if char avail */
+-	n = vpeekc();
+-    else if (error || vpeekc() == NUL)
+-	/* illegal argument or getchar(0) and no char avail: return zero */
+-	n = 0;
+-    else
+-	/* getchar(0) and char avail: return char */
+-	n = safe_vgetc();
++    for (;;)
++    {
++	if (argvars[0].v_type == VAR_UNKNOWN)
++	    /* getchar(): blocking wait. */
++	    n = safe_vgetc();
++	else if (get_tv_number_chk(&argvars[0], &error) == 1)
++	    /* getchar(1): only check if char avail */
++	    n = vpeekc();
++	else if (error || vpeekc() == NUL)
++	    /* illegal argument or getchar(0) and no char avail: return zero */
++	    n = 0;
++	else
++	    /* getchar(0) and char avail: return char */
++	    n = safe_vgetc();
++	if (n == K_IGNORE)
++	    continue;
++	break;
++    }
+     --no_mapping;
+     --allow_keys;
+ 
+@@ -10136,7 +10195,13 @@
+ 	if (mch_isdir(fname))
+ 	    rettv->vval.v_number = 0;
+ 	else
++	{
+ 	    rettv->vval.v_number = (varnumber_T)st.st_size;
++
++	    /* non-perfect check for overflow */
++	    if ((off_t)rettv->vval.v_number != (off_t)st.st_size)
++		rettv->vval.v_number = -2;
++	}
+     }
+     else
+ 	  rettv->vval.v_number = -1;
+@@ -10269,6 +10334,39 @@
+ }
+ 
+ /*
++ * "getmatches()" function
++ */
++/*ARGSUSED*/
++    static void
++f_getmatches(argvars, rettv)
++    typval_T	*argvars;
++    typval_T	*rettv;
++{
++#ifdef FEAT_SEARCH_EXTRA
++    dict_T	*dict;
++    matchitem_T	*cur = curwin->w_match_head;
++
++    rettv->vval.v_number = 0;
++
++    if (rettv_list_alloc(rettv) == OK)
++    {
++	while (cur != NULL)
++	{
++	    dict = dict_alloc();
++	    if (dict == NULL)
++		return;
++	    dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
++	    dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
++	    dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
++	    dict_add_nr_str(dict, "id", (long)cur->id, NULL);
++	    list_append_dict(rettv->vval.v_list, dict);
++	    cur = cur->next;
++	}
++    }
++#endif
++}
++
++/*
+  * "getpos(string)" function
+  */
+     static void
+@@ -10290,7 +10388,8 @@
+ 	    list_append_number(l, (varnumber_T)0);
+ 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
+ 							    : (varnumber_T)0);
+-	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->col + 1
++	list_append_number(l, (fp != NULL)
++		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
+ 							    : (varnumber_T)0);
+ 	list_append_number(l,
+ #ifdef FEAT_VIRTUALEDIT
+@@ -10785,6 +10884,9 @@
+ 	"gui_gtk2",
+ # endif
+ #endif
++#ifdef FEAT_GUI_GNOME
++	"gui_gnome",
++#endif
+ #ifdef FEAT_GUI_MAC
+ 	"gui_mac",
+ #endif
+@@ -11471,14 +11573,12 @@
+     char_u	*xp_arg = NULL;
+ 
+     rettv->v_type = VAR_STRING;
++    rettv->vval.v_string = NULL;
+ 
+ #ifdef NO_CONSOLE_INPUT
+     /* While starting up, there is no place to enter text. */
+     if (no_console_input())
+-    {
+-	rettv->vval.v_string = NULL;
+ 	return;
+-    }
+ #endif
+ 
+     cmd_silent = FALSE;		/* Want to see the prompt. */
+@@ -12439,6 +12539,44 @@
+ }
+ 
+ /*
++ * "matchadd()" function
++ */
++    static void
++f_matchadd(argvars, rettv)
++    typval_T	*argvars;
++    typval_T	*rettv;
++{
++#ifdef FEAT_SEARCH_EXTRA
++    char_u	buf[NUMBUFLEN];
++    char_u	*grp = get_tv_string_buf_chk(&argvars[0], buf);	/* group */
++    char_u	*pat = get_tv_string_buf_chk(&argvars[1], buf);	/* pattern */
++    int		prio = 10;	/* default priority */
++    int		id = -1;
++    int		error = FALSE;
++
++    rettv->vval.v_number = -1;
++
++    if (grp == NULL || pat == NULL)
++	return;
++    if (argvars[2].v_type != VAR_UNKNOWN)
++    {
++	prio = get_tv_number_chk(&argvars[2], &error);
++	if (argvars[3].v_type != VAR_UNKNOWN)
++	    id = get_tv_number_chk(&argvars[3], &error);
++    }
++    if (error == TRUE)
++	return;
++    if (id >= 1 && id <= 3)
++    {
++	EMSGN("E798: ID is reserved for \":match\": %ld", id);
++	return;
++    }
++
++    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
++#endif
++}
++
++/*
+  * "matcharg()" function
+  */
+     static void
+@@ -12449,20 +12587,42 @@
+     if (rettv_list_alloc(rettv) == OK)
+     {
+ #ifdef FEAT_SEARCH_EXTRA
+-	int	mi = get_tv_number(&argvars[0]);
++	int	    id = get_tv_number(&argvars[0]);
++	matchitem_T *m;
+ 
+-	if (mi >= 1 && mi <= 3)
++	if (id >= 1 && id <= 3)
+ 	{
+-	    list_append_string(rettv->vval.v_list,
+-				 syn_id2name(curwin->w_match_id[mi - 1]), -1);
+-	    list_append_string(rettv->vval.v_list,
+-					     curwin->w_match_pat[mi - 1], -1);
++	    if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
++	    {
++		list_append_string(rettv->vval.v_list,
++						syn_id2name(m->hlg_id), -1);
++		list_append_string(rettv->vval.v_list, m->pattern, -1);
++	    }
++	    else
++	    {
++		list_append_string(rettv->vval.v_list, NUL, -1);
++		list_append_string(rettv->vval.v_list, NUL, -1);
++	    }
+ 	}
+ #endif
+     }
+ }
+ 
+ /*
++ * "matchdelete()" function
++ */
++    static void
++f_matchdelete(argvars, rettv)
++    typval_T	*argvars;
++    typval_T	*rettv;
++{
++#ifdef FEAT_SEARCH_EXTRA
++    rettv->vval.v_number = match_delete(curwin,
++				       (int)get_tv_number(&argvars[0]), TRUE);
++#endif
++}
++
++/*
+  * "matchend()" function
+  */
+     static void
+@@ -13680,7 +13840,7 @@
+ 	    }
+ 	    /* Shorten "remain". */
+ 	    if (*q != NUL)
+-		STRCPY(remain, q - 1);
++		mch_memmove(remain, q - 1, STRLEN(q - 1) + 1);
+ 	    else
+ 	    {
+ 		vim_free(remain);
+@@ -13919,6 +14079,8 @@
+     /* If 'n' flag is used: restore cursor position. */
+     if (flags & SP_NOMOVE)
+ 	curwin->w_cursor = save_cursor;
++    else
++	curwin->w_set_curswant = TRUE;
+ theend:
+     p_ws = save_p_ws;
+ 
+@@ -14498,6 +14660,66 @@
+ }
+ 
+ /*
++ * "setmatches()" function
++ */
++    static void
++f_setmatches(argvars, rettv)
++    typval_T	*argvars;
++    typval_T	*rettv;
++{
++#ifdef FEAT_SEARCH_EXTRA
++    list_T	*l;
++    listitem_T	*li;
++    dict_T	*d;
++
++    rettv->vval.v_number = -1;
++    if (argvars[0].v_type != VAR_LIST)
++    {
++	EMSG(_(e_listreq));
++	return;
++    }
++    if ((l = argvars[0].vval.v_list) != NULL)
++    {
++
++	/* To some extent make sure that we are dealing with a list from
++	 * "getmatches()". */
++	li = l->lv_first;
++	while (li != NULL)
++	{
++	    if (li->li_tv.v_type != VAR_DICT
++		    || (d = li->li_tv.vval.v_dict) == NULL)
++	    {
++		EMSG(_(e_invarg));
++		return;
++	    }
++	    if (!(dict_find(d, (char_u *)"group", -1) != NULL
++			&& dict_find(d, (char_u *)"pattern", -1) != NULL
++			&& dict_find(d, (char_u *)"priority", -1) != NULL
++			&& dict_find(d, (char_u *)"id", -1) != NULL))
++	    {
++		EMSG(_(e_invarg));
++		return;
++	    }
++	    li = li->li_next;
++	}
++
++	clear_matches(curwin);
++	li = l->lv_first;
++	while (li != NULL)
++	{
++	    d = li->li_tv.vval.v_dict;
++	    match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
++		    get_dict_string(d, (char_u *)"pattern", FALSE),
++		    (int)get_dict_number(d, (char_u *)"priority"),
++		    (int)get_dict_number(d, (char_u *)"id"));
++	    li = li->li_next;
++	}
++	rettv->vval.v_number = 0;
++    }
++#endif
++}
++
++/*
+  * "setpos()" function
+  */
+ /*ARGSUSED*/
+@@ -14785,6 +15007,10 @@
+ 
+     p1 = tv2string(&(*(listitem_T **)s1)->li_tv, &tofree1, numbuf1, 0);
+     p2 = tv2string(&(*(listitem_T **)s2)->li_tv, &tofree2, numbuf2, 0);
++    if (p1 == NULL)
++	p1 = (char_u *)"";
++    if (p2 == NULL)
++	p2 = (char_u *)"";
+     if (item_compare_ic)
+ 	res = STRICMP(p1, p2);
+     else
+@@ -15274,7 +15500,8 @@
+ 
+     rettv->v_type = VAR_STRING;
+     rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 0);
+-    if (tofree == NULL)
++    /* Make a copy if we have a value but it's not in allocate memory. */
++    if (rettv->vval.v_string != NULL && tofree == NULL)
+ 	rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
+ }
+ 
+@@ -15599,7 +15826,7 @@
+     FILE	*fd;
+ 
+     if (check_restricted() || check_secure())
+-	return;
++	goto done;
+ 
+     if (argvars[1].v_type != VAR_UNKNOWN)
+     {
+@@ -15610,7 +15837,7 @@
+ 	if ((infile = vim_tempname('i')) == NULL)
+ 	{
+ 	    EMSG(_(e_notmp));
+-	    return;
++	    goto done;
+ 	}
+ 
+ 	fd = mch_fopen((char *)infile, WRITEBIN);
+@@ -16497,9 +16724,9 @@
+  * Returns NULL when there is an error.
+  */
+     static pos_T *
+-var2fpos(varp, lnum, fnum)
++var2fpos(varp, dollar_lnum, fnum)
+     typval_T	*varp;
+-    int		lnum;		/* TRUE when $ is last line */
++    int		dollar_lnum;	/* TRUE when $ is last line */
+     int		*fnum;		/* set to fnum for '0, 'A, etc. */
+ {
+     char_u		*name;
+@@ -16512,6 +16739,7 @@
+ 	list_T		*l;
+ 	int		len;
+ 	int		error = FALSE;
++	listitem_T	*li;
+ 
+ 	l = varp->vval.v_list;
+ 	if (l == NULL)
+@@ -16527,6 +16755,14 @@
+ 	if (error)
+ 	    return NULL;
+ 	len = (long)STRLEN(ml_get(pos.lnum));
++
++	/* We accept "$" for the column number: last column. */
++	li = list_find(l, 1L);
++	if (li != NULL && li->li_tv.v_type == VAR_STRING
++		&& li->li_tv.vval.v_string != NULL
++		&& STRCMP(li->li_tv.vval.v_string, "$") == 0)
++	    pos.col = len + 1;
++
+ 	/* Accept a position up to the NUL after the line. */
+ 	if (pos.col == 0 || (int)pos.col > len + 1)
+ 	    return NULL;	/* invalid column number */
+@@ -16559,7 +16795,7 @@
+     pos.coladd = 0;
+ #endif
+ 
+-    if (name[0] == 'w' && lnum)
++    if (name[0] == 'w' && dollar_lnum)
+     {
+ 	pos.col = 0;
+ 	if (name[1] == '0')		/* "w0": first visible line */
+@@ -16577,7 +16813,7 @@
+     }
+     else if (name[0] == '$')		/* last column or line */
+     {
+-	if (lnum)
++	if (dollar_lnum)
+ 	{
+ 	    pos.lnum = curbuf->b_ml.ml_line_count;
+ 	    pos.col = 0;
+@@ -17798,9 +18034,10 @@
+  * List the value of one internal variable.
+  */
+     static void
+-list_one_var(v, prefix)
++list_one_var(v, prefix, first)
+     dictitem_T	*v;
+     char_u	*prefix;
++    int		*first;
+ {
+     char_u	*tofree;
+     char_u	*s;
+@@ -17808,18 +18045,21 @@
+ 
+     s = echo_string(&v->di_tv, &tofree, numbuf, ++current_copyID);
+     list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
+-						s == NULL ? (char_u *)"" : s);
++					 s == NULL ? (char_u *)"" : s, first);
+     vim_free(tofree);
+ }
+ 
+     static void
+-list_one_var_a(prefix, name, type, string)
++list_one_var_a(prefix, name, type, string, first)
+     char_u	*prefix;
+     char_u	*name;
+     int		type;
+     char_u	*string;
++    int		*first;  /* when TRUE clear rest of screen and set to FALSE */
+ {
+-    msg_attr(prefix, 0);    /* don't use msg(), it overwrites "v:statusmsg" */
++    /* don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" */
++    msg_start();
++    msg_puts(prefix);
+     if (name != NULL)	/* "a:" vars don't have a name stored */
+ 	msg_puts(name);
+     msg_putchar(' ');
+@@ -17847,6 +18087,11 @@
+ 
+     if (type == VAR_FUNC)
+ 	msg_puts((char_u *)"()");
++    if (*first)
++    {
++	msg_clr_eos();
++	*first = FALSE;
++    }
+ }
+ 
+ /*
+@@ -19136,6 +19381,28 @@
+ 	goto theend;
+     }
+ 
++    /* Check if the name is a Funcref.  If so, use the value. */
++    if (lv.ll_exp_name != NULL)
++    {
++	len = (int)STRLEN(lv.ll_exp_name);
++	name = deref_func_name(lv.ll_exp_name, &len);
++	if (name == lv.ll_exp_name)
++	    name = NULL;
++    }
++    else
++    {
++	len = (int)(end - *pp);
++	name = deref_func_name(*pp, &len);
++	if (name == *pp)
++	    name = NULL;
++    }
++    if (name != NULL)
++    {
++	name = vim_strsave(name);
++	*pp = end;
++	goto theend;
++    }
++
+     if (lv.ll_exp_name != NULL)
+     {
+ 	len = (int)STRLEN(lv.ll_exp_name);
+@@ -19969,6 +20236,7 @@
+ 		char_u	buf[MSG_BUF_LEN];
+ 		char_u	numbuf2[NUMBUFLEN];
+ 		char_u	*tofree;
++		char_u	*s;
+ 
+ 		msg_puts((char_u *)"(");
+ 		for (i = 0; i < argcount; ++i)
+@@ -19979,10 +20247,13 @@
+ 			msg_outnum((long)argvars[i].vval.v_number);
+ 		    else
+ 		    {
+-			trunc_string(tv2string(&argvars[i], &tofree,
+-					      numbuf2, 0), buf, MSG_BUF_CLEN);
+-			msg_puts(buf);
+-			vim_free(tofree);
++			s = tv2string(&argvars[i], &tofree, numbuf2, 0);
++			if (s != NULL)
++			{
++			    trunc_string(s, buf, MSG_BUF_CLEN);
++			    msg_puts(buf);
++			    vim_free(tofree);
++			}
+ 		    }
+ 		}
+ 		msg_puts((char_u *)")");
+@@ -20060,14 +20331,18 @@
+ 	    char_u	buf[MSG_BUF_LEN];
+ 	    char_u	numbuf2[NUMBUFLEN];
+ 	    char_u	*tofree;
++	    char_u	*s;
+ 
+ 	    /* The value may be very long.  Skip the middle part, so that we
+ 	     * have some idea how it starts and ends. smsg() would always
+ 	     * truncate it at the end. */
+-	    trunc_string(tv2string(fc.rettv, &tofree, numbuf2, 0),
+-							   buf, MSG_BUF_CLEN);
+-	    smsg((char_u *)_("%s returning %s"), sourcing_name, buf);
+-	    vim_free(tofree);
++	    s = tv2string(fc.rettv, &tofree, numbuf2, 0);
++	    if (s != NULL)
++	    {
++		trunc_string(s, buf, MSG_BUF_CLEN);
++		smsg((char_u *)_("%s returning %s"), sourcing_name, buf);
++		vim_free(tofree);
++	    }
+ 	}
+ 	msg_puts((char_u *)"\n");   /* don't overwrite this either */
+ 
+@@ -21034,14 +21309,27 @@
+ 	*usedlen += 2;
+ 	s = get_past_head(*fnamep);
+ 	while (tail > s && after_pathsep(s, tail))
+-	    --tail;
++	    mb_ptr_back(*fnamep, tail);
+ 	*fnamelen = (int)(tail - *fnamep);
+ #ifdef VMS
+ 	if (*fnamelen > 0)
+ 	    *fnamelen += 1; /* the path separator is part of the path */
+ #endif
+-	while (tail > s && !after_pathsep(s, tail))
+-	    mb_ptr_back(*fnamep, tail);
++	if (*fnamelen == 0)
++	{
++	    /* Result is empty.  Turn it into "." to make ":cd %:h" work. */
++	    p = vim_strsave((char_u *)".");
++	    if (p == NULL)
++		return -1;
++	    vim_free(*bufp);
++	    *bufp = *fnamep = tail = p;
++	    *fnamelen = 1;
++	}
++	else
++	{
++	    while (tail > s && !after_pathsep(s, tail))
++		mb_ptr_back(*fnamep, tail);
++	}
+     }
+ 
+     /* ":8" - shortname  */
+diff -Naur vim71.orig/src/ex_cmds.c vim71/src/ex_cmds.c
+--- vim71.orig/src/ex_cmds.c	2007-05-07 19:41:01.000000000 +0000
++++ vim71/src/ex_cmds.c	2007-12-08 20:34:53.000000000 +0000
+@@ -408,7 +408,11 @@
+ 		goto sortend;
+ 	    }
+ 	    *s = NUL;
+-	    regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
++	    /* Use last search pattern if sort pattern is empty. */
++	    if (s == p + 1 && last_search_pat() != NULL)
++		regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
++	    else
++		regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
+ 	    if (regmatch.regprog == NULL)
+ 		goto sortend;
+ 	    p = s;		/* continue after the regexp */
+@@ -1770,7 +1774,8 @@
+ 	 * overwrite a user's viminfo file after a "su root", with a
+ 	 * viminfo file that the user can't read.
+ 	 */
+-	st_old.st_dev = st_old.st_ino = 0;
++	st_old.st_dev = 0;
++	st_old.st_ino = 0;
+ 	st_old.st_mode = 0600;
+ 	if (mch_stat((char *)fname, &st_old) == 0
+ 		&& getuid() != ROOT_UID
+@@ -2912,22 +2917,35 @@
+ }
+ 
+ /*
+- * Check if a buffer is read-only.  Ask for overruling in a dialog.
+- * Return TRUE and give an error message when the buffer is readonly.
++ * Check if a buffer is read-only (either 'readonly' option is set or file is
++ * read-only). Ask for overruling in a dialog. Return TRUE and give an error
++ * message when the buffer is readonly.
+  */
+     static int
+ check_readonly(forceit, buf)
+     int		*forceit;
+     buf_T	*buf;
+ {
+-    if (!*forceit && buf->b_p_ro)
++    struct stat	st;
++
++    /* Handle a file being readonly when the 'readonly' option is set or when
++     * the file exists and permissions are read-only.
++     * We will send 0777 to check_file_readonly(), as the "perm" variable is
++     * important for device checks but not here. */
++    if (!*forceit && (buf->b_p_ro
++		|| (mch_stat((char *)buf->b_ffname, &st) >= 0
++		    && check_file_readonly(buf->b_ffname, 0777))))
+     {
+ #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ 	if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL)
+ 	{
+ 	    char_u	buff[IOSIZE];
+ 
+-	    dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
++	    if (buf->b_p_ro)
++		dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
++		    buf->b_fname);
++	    else
++		dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"),
+ 		    buf->b_fname);
+ 
+ 	    if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES)
+@@ -2941,9 +2959,14 @@
+ 	}
+ 	else
+ #endif
++	if (buf->b_p_ro)
+ 	    EMSG(_(e_readonly));
++	else
++	    EMSG2(_("E505: \"%s\" is read-only (add ! to override)"),
++		    buf->b_fname);
+ 	return TRUE;
+     }
++
+     return FALSE;
+ }
+ 
+@@ -2952,7 +2975,7 @@
+  * 'fnum' is the number of the file, if zero use ffname/sfname.
+  *
+  * Return 1 for "normal" error, 2 for "not written" error, 0 for success
+- * -1 for succesfully opening another file.
++ * -1 for successfully opening another file.
+  * 'lnum' is the line number for the cursor in the new file (if non-zero).
+  */
+     int
+@@ -3367,7 +3390,7 @@
+ 		 * was in this window (or another window).  If not used
+ 		 * before, reset the local window options to the global
+ 		 * values.  Also restores old folding stuff. */
+-		get_winopts(buf);
++		get_winopts(curbuf);
+ #ifdef FEAT_SPELL
+ 		did_get_winopts = TRUE;
+ #endif
+@@ -3562,9 +3585,20 @@
+ 	curwin_init();
+ 
+ #ifdef FEAT_FOLDING
+-	/* It's like all lines in the buffer changed.  Need to update
+-	 * automatic folding. */
++	/* It's possible that all lines in the buffer changed.  Need to update
++	 * automatic folding for all windows where it's used. */
++# ifdef FEAT_WINDOWS
++	{
++	    win_T	    *win;
++	    tabpage_T	    *tp;
++
++	    FOR_ALL_TAB_WINDOWS(tp, win)
++		if (win->w_buffer == curbuf)
++		    foldUpdateAll(win);
++	}
++# else
+ 	foldUpdateAll(curwin);
++# endif
+ #endif
+ 
+ 	/* Change directories when the 'acd' option is set. */
+@@ -3649,8 +3683,8 @@
+ #ifdef FEAT_SPELL
+     /* If the window options were changed may need to set the spell language.
+      * Can only do this after the buffer has been properly setup. */
+-    if (did_get_winopts && curwin->w_p_spell && *buf->b_p_spl != NUL)
+-	did_set_spelllang(buf);
++    if (did_get_winopts && curwin->w_p_spell && *curbuf->b_p_spl != NUL)
++	did_set_spelllang(curbuf);
+ #endif
+ 
+     if (command == NULL)
+@@ -3754,7 +3788,7 @@
+ 	    workshop_file_opened((char *)curbuf->b_ffname, curbuf->b_p_ro);
+ # endif
+ # ifdef FEAT_NETBEANS_INTG
+-	if (usingNetbeans & ((flags & ECMD_SET_HELP) != ECMD_SET_HELP))
++	if (usingNetbeans && ((flags & ECMD_SET_HELP) != ECMD_SET_HELP))
+ 	    netbeans_file_opened(curbuf);
+ # endif
+     }
+@@ -4294,6 +4328,7 @@
+ 	do_error = TRUE;
+ 	do_print = FALSE;
+ 	do_count = FALSE;
++	do_number = FALSE;
+ 	do_ic = 0;
+     }
+     while (*cmd)
+@@ -4464,7 +4499,7 @@
+ 	     *
+ 	     * The new text is built up in new_start[].  It has some extra
+ 	     * room to avoid using alloc()/free() too often.  new_start_len is
+-	     * the lenght of the allocated memory at new_start.
++	     * the length of the allocated memory at new_start.
+ 	     *
+ 	     * Make a copy of the old line, so it won't be taken away when
+ 	     * updating the screen or handling a multi-line match.  The "old_"
+@@ -4635,7 +4670,7 @@
+ #endif
+ 			    ++no_mapping;	/* don't map this key */
+ 			    ++allow_keys;	/* allow special keys */
+-			    i = safe_vgetc();
++			    i = plain_vgetc();
+ 			    --allow_keys;
+ 			    --no_mapping;
+ 
+@@ -4850,7 +4885,8 @@
+ 			    ++line2;
+ 			    /* move the cursor to the new line, like Vi */
+ 			    ++curwin->w_cursor.lnum;
+-			    STRCPY(new_start, p1 + 1);	/* copy the rest */
++			    /* copy the rest */
++			    mch_memmove(new_start, p1 + 1, STRLEN(p1 + 1) + 1);
+ 			    p1 = new_start - 1;
+ 			}
+ 		    }
+@@ -6351,9 +6387,9 @@
+ 	for (i = 0; i < ga.ga_len; ++i)
+ 	{
+ 	    s = ((char_u **)ga.ga_data)[i];
+-	    if (STRNCMP(s, "help-tags", 9) == 0)
++	    if (STRNCMP(s, "help-tags\t", 10) == 0)
+ 		/* help-tags entry was added in formatted form */
+-		fprintf(fd_tags, (char *)s);
++		fputs((char *)s, fd_tags);
+ 	    else
+ 	    {
+ 		fprintf(fd_tags, "%s\t/*", s);
+diff -Naur vim71.orig/src/ex_docmd.c vim71/src/ex_docmd.c
+--- vim71.orig/src/ex_docmd.c	2007-05-07 19:49:38.000000000 +0000
++++ vim71/src/ex_docmd.c	2007-12-08 20:34:53.000000000 +0000
+@@ -133,6 +133,7 @@
+ static void	get_flags __ARGS((exarg_T *eap));
+ #if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_TCL) \
+ 	|| !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME)
++# define HAVE_EX_SCRIPT_NI
+ static void	ex_script_ni __ARGS((exarg_T *eap));
+ #endif
+ static char_u	*invalid_range __ARGS((exarg_T *eap));
+@@ -666,7 +667,7 @@
+ 		if (ex_pressedreturn)
+ 		{
+ 		    /* go up one line, to overwrite the ":<CR>" line, so the
+-		     * output doensn't contain empty lines. */
++		     * output doesn't contain empty lines. */
+ 		    msg_row = prev_msg_row;
+ 		    if (prev_msg_row == Rows - 1)
+ 			msg_row--;
+@@ -1741,7 +1742,9 @@
+ 	}
+ 
+ 	/* ignore comment and empty lines */
+-	if (*ea.cmd == '"' || *ea.cmd == NUL)
++	if (*ea.cmd == '"')
++	    goto doend;
++	if (*ea.cmd == NUL)
+ 	{
+ 	    ex_pressedreturn = TRUE;
+ 	    goto doend;
+@@ -2118,7 +2121,11 @@
+ #ifdef FEAT_USR_CMDS
+ 	    !USER_CMDIDX(ea.cmdidx) &&
+ #endif
+-	    cmdnames[ea.cmdidx].cmd_func == ex_ni);
++	    (cmdnames[ea.cmdidx].cmd_func == ex_ni
++#ifdef HAVE_EX_SCRIPT_NI
++	     || cmdnames[ea.cmdidx].cmd_func == ex_script_ni
++#endif
++	     ));
+ 
+ #ifndef FEAT_EVAL
+     /*
+@@ -2756,7 +2763,7 @@
+ 
+     /*
+      * Isolate the command and search for it in the command table.
+-     * Exeptions:
++     * Exceptions:
+      * - the 'k' command can directly be followed by any character.
+      * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
+      *	    but :sre[wind] is another command, as are :scrip[tnames],
+@@ -2957,6 +2964,57 @@
+ #endif
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
++static struct cmdmod
++{
++    char	*name;
++    int		minlen;
++    int		has_count;  /* :123verbose  :3tab */
++} cmdmods[] = {
++    {"aboveleft", 3, FALSE},
++    {"belowright", 3, FALSE},
++    {"botright", 2, FALSE},
++    {"browse", 3, FALSE},
++    {"confirm", 4, FALSE},
++    {"hide", 3, FALSE},
++    {"keepalt", 5, FALSE},
++    {"keepjumps", 5, FALSE},
++    {"keepmarks", 3, FALSE},
++    {"leftabove", 5, FALSE},
++    {"lockmarks", 3, FALSE},
++    {"rightbelow", 6, FALSE},
++    {"sandbox", 3, FALSE},
++    {"silent", 3, FALSE},
++    {"tab", 3, TRUE},
++    {"topleft", 2, FALSE},
++    {"verbose", 4, TRUE},
++    {"vertical", 4, FALSE},
++};
++
++/*
++ * Return length of a command modifier (including optional count).
++ * Return zero when it's not a modifier.
++ */
++    int
++modifier_len(cmd)
++    char_u	*cmd;
++{
++    int		i, j;
++    char_u	*p = cmd;
++
++    if (VIM_ISDIGIT(*cmd))
++	p = skipwhite(skipdigits(cmd));
++    for (i = 0; i < sizeof(cmdmods) / sizeof(struct cmdmod); ++i)
++    {
++	for (j = 0; p[j] != NUL; ++j)
++	    if (p[j] != cmdmods[i].name[j])
++		break;
++	if (!isalpha(p[j]) && j >= cmdmods[i].minlen
++					&& (p == cmd || cmdmods[i].has_count))
++	    return j + (p - cmd);
++    }
++    return 0;
++}
++
+ /*
+  * Return > 0 if an Ex command "name" exists.
+  * Return 2 if there is an exact match.
+@@ -2971,30 +3029,6 @@
+     int		i;
+     int		j;
+     char_u	*p;
+-    static struct cmdmod
+-    {
+-	char	*name;
+-	int	minlen;
+-    } cmdmods[] = {
+-	{"aboveleft", 3},
+-	{"belowright", 3},
+-	{"botright", 2},
+-	{"browse", 3},
+-	{"confirm", 4},
+-	{"hide", 3},
+-	{"keepalt", 5},
+-	{"keepjumps", 5},
+-	{"keepmarks", 3},
+-	{"leftabove", 5},
+-	{"lockmarks", 3},
+-	{"rightbelow", 6},
+-	{"sandbox", 3},
+-	{"silent", 3},
+-	{"tab", 3},
+-	{"topleft", 2},
+-	{"verbose", 4},
+-	{"vertical", 4},
+-    };
+ 
+     /* Check command modifiers. */
+     for (i = 0; i < sizeof(cmdmods) / sizeof(struct cmdmod); ++i)
+@@ -3276,39 +3310,65 @@
+ 
+     if (ea.argt & XFILE)
+     {
+-	int in_quote = FALSE;
+-	char_u *bow = NULL;	/* Beginning of word */
++	int	c;
++	int	in_quote = FALSE;
++	char_u	*bow = NULL;	/* Beginning of word */
+ 
+ 	/*
+ 	 * Allow spaces within back-quotes to count as part of the argument
+ 	 * being expanded.
+ 	 */
+ 	xp->xp_pattern = skipwhite(arg);
+-	for (p = xp->xp_pattern; *p; )
++	p = xp->xp_pattern;
++	while (*p != NUL)
+ 	{
+-	    if (*p == '\\' && p[1] != NUL)
++#ifdef FEAT_MBYTE
++	    if (has_mbyte)
++		c = mb_ptr2char(p);
++	    else
++#endif
++		c = *p;
++	    if (c == '\\' && p[1] != NUL)
+ 		++p;
++	    else if (c == '`')
++	    {
++		if (!in_quote)
++		{
++		    xp->xp_pattern = p;
++		    bow = p + 1;
++		}
++		in_quote = !in_quote;
++	    }
+ #ifdef SPACE_IN_FILENAME
+-	    else if (vim_iswhite(*p) && (!(ea.argt & NOSPC) || usefilter))
++	    else if (!vim_isfilec_or_wc(c)
++					 && (!(ea.argt & NOSPC) || usefilter))
+ #else
+-	    else if (vim_iswhite(*p))
++	    else if (!vim_isfilec_or_wc(c))
+ #endif
+ 	    {
+-		p = skipwhite(p);
++		while (*p != NUL)
++		{
++#ifdef FEAT_MBYTE
++		    if (has_mbyte)
++			c = mb_ptr2char(p);
++		    else
++#endif
++			c = *p;
++		    if (c == '`' || vim_isfilec_or_wc(c))
++			break;
++#ifdef FEAT_MBYTE
++		    if (has_mbyte)
++			len = (*mb_ptr2len)(p);
++		    else
++#endif
++			len = 1;
++		    mb_ptr_adv(p);
++		}
+ 		if (in_quote)
+ 		    bow = p;
+ 		else
+ 		    xp->xp_pattern = p;
+-		--p;
+-	    }
+-	    else if (*p == '`')
+-	    {
+-		if (!in_quote)
+-		{
+-		    xp->xp_pattern = p;
+-		    bow = p + 1;
+-		}
+-		in_quote = !in_quote;
++		p -= len;
+ 	    }
+ 	    mb_ptr_adv(p);
+ 	}
+@@ -3401,14 +3461,13 @@
+ 	case CMD_windo:
+ 	    return arg;
+ 
+-#ifdef FEAT_SEARCH_EXTRA
++#ifdef FEAT_CMDL_COMPL
++# ifdef FEAT_SEARCH_EXTRA
+ 	case CMD_match:
+ 	    if (*arg == NUL || !ends_excmd(*arg))
+ 	    {
+-		/* Dummy call to clear variables. */
+-		set_context_in_highlight_cmd(xp, (char_u *)"link n");
+-		xp->xp_context = EXPAND_HIGHLIGHT;
+-		xp->xp_pattern = arg;
++		/* also complete "None" */
++		set_context_in_echohl_cmd(xp, arg);
+ 		arg = skipwhite(skiptowhite(arg));
+ 		if (*arg != NUL)
+ 		{
+@@ -3417,9 +3476,8 @@
+ 		}
+ 	    }
+ 	    return find_nextcmd(arg);
+-#endif
++# endif
+ 
+-#ifdef FEAT_CMDL_COMPL
+ /*
+  * All completion for the +cmdline_compl feature goes here.
+  */
+@@ -3617,8 +3675,7 @@
+ 	    break;
+ 
+ 	case CMD_echohl:
+-	    xp->xp_context = EXPAND_HIGHLIGHT;
+-	    xp->xp_pattern = arg;
++	    set_context_in_echohl_cmd(xp, arg);
+ 	    break;
+ #endif
+ 	case CMD_highlight:
+@@ -3997,8 +4054,7 @@
+ 	eap->errmsg = (char_u *)N_("E319: Sorry, the command is not available in this version");
+ }
+ 
+-#if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_TCL) \
+-	|| !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME)
++#ifdef HAVE_EX_SCRIPT_NI
+ /*
+  * Function called for script command which is Not Implemented.  NI!
+  * Skips over ":perl <<EOF" constructs.
+@@ -4376,7 +4432,7 @@
+ 			    || vim_strchr(eap->arg, '~') != NULL)
+ 		    {
+ 			expand_env_esc(eap->arg, NameBuff, MAXPATHL,
+-								 TRUE, NULL);
++							    TRUE, TRUE, NULL);
+ 			has_wildcards = mch_has_wildcard(NameBuff);
+ 			p = NameBuff;
+ 		    }
+@@ -4492,7 +4548,8 @@
+ 	    if (eap->argt & (USECTRLV | XFILE))
+ 		++p;		/* skip CTRL-V and next char */
+ 	    else
+-		STRCPY(p, p + 1);	/* remove CTRL-V and skip next char */
++				/* remove CTRL-V and skip next char */
++		mch_memmove(p, p + 1, STRLEN(p));
+ 	    if (*p == NUL)		/* stop at NUL after CTRL-V */
+ 		break;
+ 	}
+@@ -6650,7 +6707,7 @@
+  * The list should be allocated using alloc(), as should each item in the
+  * list. This function takes over responsibility for freeing the list.
+  *
+- * XXX The list is made into the arggument list. This is freed using
++ * XXX The list is made into the argument list. This is freed using
+  * FreeWild(), which does a series of vim_free() calls, unless the two defines
+  * __EMX__ and __ALWAYS_HAS_TRAILING_NUL_POINTER are set. In this case, a
+  * routine _fnexplodefree() is used. This may cause problems, but as the drop
+@@ -7768,7 +7825,7 @@
+ 	if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged()
+ 							     && !eap->forceit)
+ 	{
+-	    EMSG(_("E747: Cannot change directory, buffer is modifed (add ! to override)"));
++	    EMSG(_("E747: Cannot change directory, buffer is modified (add ! to override)"));
+ 	    return;
+ 	}
+ 
+@@ -8399,21 +8456,17 @@
+ 		    || *arg == '"')
+ 	    {
+ 		redir_reg = *arg++;
+-		if (*arg == '>' && arg[1] == '>')
++		if (*arg == '>' && arg[1] == '>')  /* append */
+ 		    arg += 2;
+-		else if ((*arg == NUL || (*arg == '>' && arg[1] == NUL)) &&
+-			 (islower(redir_reg)
+-# ifdef FEAT_CLIPBOARD
+-			    || redir_reg == '*'
+-			    || redir_reg == '+'
+-# endif
+-			    || redir_reg == '"'))
++		else
+ 		{
++		    /* Can use both "@a" and "@a>". */
+ 		    if (*arg == '>')
+ 			arg++;
+-
+-		    /* make register empty */
+-		    write_reg_contents(redir_reg, (char_u *)"", -1, FALSE);
++		    /* Make register empty when not using @A- at Z and the
++		     * command is valid. */
++		    if (*arg == NUL && !isupper(redir_reg))
++			write_reg_contents(redir_reg, (char_u *)"", -1, FALSE);
+ 		}
+ 	    }
+ 	    if (*arg != NUL)
+@@ -9368,7 +9421,7 @@
+     if (src > srcstart && src[-1] == '\\')
+     {
+ 	*usedlen = 0;
+-	STRCPY(src - 1, src);		/* remove backslash */
++	mch_memmove(src - 1, src, STRLEN(src) + 1);	/* remove backslash */
+ 	return NULL;
+     }
+ 
+@@ -10816,12 +10869,13 @@
+     exarg_T	*eap;
+ {
+     char_u	*p;
++    char_u	*g = NULL;
+     char_u	*end;
+     int		c;
+-    int		mi;
++    int		id;
+ 
+     if (eap->line2 <= 3)
+-	mi = eap->line2 - 1;
++	id = eap->line2;
+     else
+     {
+ 	EMSG(e_invcmd);
+@@ -10830,13 +10884,7 @@
+ 
+     /* First clear any old pattern. */
+     if (!eap->skip)
+-    {
+-	vim_free(curwin->w_match[mi].regprog);
+-	curwin->w_match[mi].regprog = NULL;
+-	vim_free(curwin->w_match_pat[mi]);
+-	curwin->w_match_pat[mi] = NULL;
+-	redraw_later(SOME_VALID);	/* always need a redraw */
+-    }
++	match_delete(curwin, id, FALSE);
+ 
+     if (ends_excmd(*eap->arg))
+ 	end = eap->arg;
+@@ -10847,15 +10895,7 @@
+     {
+ 	p = skiptowhite(eap->arg);
+ 	if (!eap->skip)
+-	{
+-	    curwin->w_match_id[mi] = syn_namen2id(eap->arg,
+-							 (int)(p - eap->arg));
+-	    if (curwin->w_match_id[mi] == 0)
+-	    {
+-		EMSG2(_(e_nogroup), eap->arg);
+-		return;
+-	    }
+-	}
++	    g = vim_strnsave(eap->arg, (int)(p - eap->arg));
+ 	p = skipwhite(p);
+ 	if (*p == NUL)
+ 	{
+@@ -10879,14 +10919,8 @@
+ 
+ 	    c = *end;
+ 	    *end = NUL;
+-	    curwin->w_match[mi].regprog = vim_regcomp(p + 1, RE_MAGIC);
+-	    if (curwin->w_match[mi].regprog == NULL)
+-	    {
+-		EMSG2(_(e_invarg2), p);
+-		*end = c;
+-		return;
+-	    }
+-	    curwin->w_match_pat[mi] = vim_strsave(p + 1);
++	    match_add(curwin, g, p + 1, 10, id);
++	    vim_free(g);
+ 	    *end = c;
+ 	}
+     }
+diff -Naur vim71.orig/src/ex_eval.c vim71/src/ex_eval.c
+--- vim71.orig/src/ex_eval.c	2007-05-07 19:47:50.000000000 +0000
++++ vim71/src/ex_eval.c	2007-12-08 20:34:53.000000000 +0000
+@@ -1551,7 +1551,7 @@
+ 		}
+ 		save_cpo  = p_cpo;
+ 		p_cpo = (char_u *)"";
+-		regmatch.regprog = vim_regcomp(pat, TRUE);
++		regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ 		regmatch.rm_ic = FALSE;
+ 		if (end != NULL)
+ 		    *end = save_char;
+@@ -2269,9 +2269,18 @@
+ has_loop_cmd(p)
+     char_u	*p;
+ {
+-    p = skipwhite(p);
+-    while (*p == ':')
+-	p = skipwhite(p + 1);
++    int		len;
++
++    /* skip modifiers, white space and ':' */
++    for (;;)
++    {
++	while (*p == ' ' || *p == '\t' || *p == ':')
++	    ++p;
++	len = modifier_len(p);
++	if (len == 0)
++	    break;
++	p += len;
++    }
+     if ((p[0] == 'w' && p[1] == 'h')
+ 	    || (p[0] == 'f' && p[1] == 'o' && p[2] == 'r'))
+ 	return TRUE;
+diff -Naur vim71.orig/src/ex_getln.c vim71/src/ex_getln.c
+--- vim71.orig/src/ex_getln.c	2007-05-07 19:47:23.000000000 +0000
++++ vim71/src/ex_getln.c	2007-12-08 20:34:53.000000000 +0000
+@@ -268,7 +268,9 @@
+     {
+ 	xpc.xp_context = ccline.xp_context;
+ 	xpc.xp_pattern = ccline.cmdbuff;
++# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ 	xpc.xp_arg = ccline.xp_arg;
++# endif
+     }
+ #endif
+ 
+@@ -484,7 +486,8 @@
+ 	if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu)
+ 	{
+ 	    /* Hitting <Down> after "emenu Name.": complete submenu */
+-	    if (ccline.cmdbuff[ccline.cmdpos - 1] == '.' && c == K_DOWN)
++	    if (c == K_DOWN && ccline.cmdpos > 0
++				  && ccline.cmdbuff[ccline.cmdpos - 1] == '.')
+ 		c = p_wc;
+ 	    else if (c == K_UP)
+ 	    {
+@@ -533,9 +536,11 @@
+ 	    upseg[3] = PATHSEP;
+ 	    upseg[4] = NUL;
+ 
+-	    if (ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP
+-		    && c == K_DOWN
+-		    && (ccline.cmdbuff[ccline.cmdpos - 2] != '.'
++	    if (c == K_DOWN
++		    && ccline.cmdpos > 0
++		    && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP
++		    && (ccline.cmdpos < 3
++			|| ccline.cmdbuff[ccline.cmdpos - 2] != '.'
+ 			|| ccline.cmdbuff[ccline.cmdpos - 3] != '.'))
+ 	    {
+ 		/* go down a directory */
+@@ -636,7 +641,7 @@
+ 	{
+ 	    ++no_mapping;
+ 	    ++allow_keys;
+-	    c = safe_vgetc();
++	    c = plain_vgetc();
+ 	    --no_mapping;
+ 	    --allow_keys;
+ 	    /* CTRL-\ e doesn't work when obtaining an expression. */
+@@ -730,8 +735,8 @@
+ 	    /* In Ex mode a backslash escapes a newline. */
+ 	    if (exmode_active
+ 		    && c != ESC
+-		    && ccline.cmdpos > 0
+ 		    && ccline.cmdpos == ccline.cmdlen
++		    && ccline.cmdpos > 0
+ 		    && ccline.cmdbuff[ccline.cmdpos - 1] == '\\')
+ 	    {
+ 		if (c == K_KENTER)
+@@ -1086,11 +1091,11 @@
+ #endif
+ 		putcmdline('"', TRUE);
+ 		++no_mapping;
+-		i = c = safe_vgetc();	/* CTRL-R <char> */
++		i = c = plain_vgetc();	/* CTRL-R <char> */
+ 		if (i == Ctrl_O)
+ 		    i = Ctrl_R;		/* CTRL-R CTRL-O == CTRL-R CTRL-R */
+ 		if (i == Ctrl_R)
+-		    c = safe_vgetc();	/* CTRL-R CTRL-R <char> */
++		    c = plain_vgetc();	/* CTRL-R CTRL-R <char> */
+ 		--no_mapping;
+ #ifdef FEAT_EVAL
+ 		/*
+@@ -1181,10 +1186,10 @@
+ 	case K_LEFT:
+ 	case K_S_LEFT:
+ 	case K_C_LEFT:
++		if (ccline.cmdpos == 0)
++		    goto cmdline_not_changed;
+ 		do
+ 		{
+-		    if (ccline.cmdpos == 0)
+-			break;
+ 		    --ccline.cmdpos;
+ #ifdef FEAT_MBYTE
+ 		    if (has_mbyte)	/* move to first byte of char */
+@@ -1193,7 +1198,8 @@
+ #endif
+ 		    ccline.cmdspos -= cmdline_charsize(ccline.cmdpos);
+ 		}
+-		while ((c == K_S_LEFT || c == K_C_LEFT
++		while (ccline.cmdpos > 0
++			&& (c == K_S_LEFT || c == K_C_LEFT
+ 			       || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
+ 			&& ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
+ #ifdef FEAT_MBYTE
+@@ -2090,11 +2096,11 @@
+     garray_T	line_ga;
+     char_u	*pend;
+     int		startcol = 0;
+-    int		c1;
++    int		c1 = 0;
+     int		escaped = FALSE;	/* CTRL-V typed */
+     int		vcol = 0;
+     char_u	*p;
+-    int		prev_char = 0;
++    int		prev_char;
+ 
+     /* Switch cursor on now.  This avoids that it happens after the "\n", which
+      * confuses the system function that computes tabstops. */
+@@ -2147,6 +2153,7 @@
+ 
+ 	/* Get one character at a time.  Don't use inchar(), it can't handle
+ 	 * special characters. */
++	prev_char = c1;
+ 	c1 = vgetc();
+ 
+ 	/*
+@@ -2204,7 +2211,6 @@
+ redraw:
+ 		/* redraw the line */
+ 		msg_col = startcol;
+-		windgoto(msg_row, msg_col);
+ 		vcol = 0;
+ 		for (p = (char_u *)line_ga.ga_data;
+ 			  p < (char_u *)line_ga.ga_data + line_ga.ga_len; ++p)
+@@ -2223,6 +2229,7 @@
+ 		    }
+ 		}
+ 		msg_clr_eos();
++		windgoto(msg_row, msg_col);
+ 		continue;
+ 	    }
+ 
+@@ -2268,7 +2275,6 @@
+ 	if (IS_SPECIAL(c1))
+ 	    c1 = '?';
+ 	((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
+-	prev_char = c1;
+ 	if (c1 == '\n')
+ 	    msg_putchar('\n');
+ 	else if (c1 == TAB)
+@@ -3311,6 +3317,10 @@
+  * Return a pointer to alloced memory containing the new string.
+  * Return NULL for failure.
+  *
++ * "orig" is the originally expanded string, copied to allocated memory.  It
++ * should either be kept in orig_save or freed.  When "mode" is WILD_NEXT or
++ * WILD_PREV "orig" should be NULL.
++ *
+  * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode"
+  * is WILD_EXPAND_FREE or WILD_ALL.
+  *
+@@ -3344,6 +3354,7 @@
+     char_u	*ss = NULL;
+     static int	findex;
+     static char_u *orig_save = NULL;	/* kept value of orig */
++    int		orig_saved = FALSE;
+     int		i;
+     long_u	len;
+     int		non_suf_match;		/* number without matching suffix */
+@@ -3395,7 +3406,7 @@
+ 	    return NULL;
+     }
+ 
+-/* free old names */
++    /* free old names */
+     if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
+     {
+ 	FreeWild(xp->xp_numfiles, xp->xp_files);
+@@ -3412,6 +3423,7 @@
+     {
+ 	vim_free(orig_save);
+ 	orig_save = orig;
++	orig_saved = TRUE;
+ 
+ 	/*
+ 	 * Do the expansion.
+@@ -3536,6 +3548,10 @@
+     if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
+ 	ExpandCleanup(xp);
+ 
++    /* Free "orig" if it wasn't stored in "orig_save". */
++    if (!orig_saved)
++	vim_free(orig);
++
+     return ss;
+ }
+ 
+@@ -4148,13 +4164,19 @@
+ 
+ #ifdef FEAT_EVAL
+     if (ccline.cmdfirstc == '=')
++    {
++# ifdef FEAT_CMDL_COMPL
+ 	/* pass CMD_SIZE because there is no real command */
+ 	set_context_for_expression(xp, str, CMD_SIZE);
++# endif
++    }
+     else if (ccline.input_fn)
+     {
+ 	xp->xp_context = ccline.xp_context;
+ 	xp->xp_pattern = ccline.cmdbuff;
++# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ 	xp->xp_arg = ccline.xp_arg;
++# endif
+     }
+     else
+ #endif
+@@ -4295,10 +4317,11 @@
+ 			    && pat[i + 1] == '\\'
+ 			    && pat[i + 2] == '\\'
+ 			    && pat[i + 3] == ' ')
+-			STRCPY(pat + i, pat + i + 3);
++			mch_memmove(pat + i, pat + i + 3,
++						     STRLEN(pat + i + 3) + 1);
+ 		    if (xp->xp_backslash == XP_BS_ONE
+ 			    && pat[i + 1] == ' ')
+-			STRCPY(pat + i, pat + i + 1);
++			mch_memmove(pat + i, pat + i + 1, STRLEN(pat + i));
+ 		}
+ 	}
+ 
+@@ -4502,6 +4525,12 @@
+     if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS)
+ 	sort_strings(*file, *num_file);
+ 
++#ifdef FEAT_CMDL_COMPL
++    /* Reset the variables used for special highlight names expansion, so that
++     * they don't show up when getting normal highlight names by ID. */
++    reset_expand_highlight();
++#endif
++
+     return OK;
+ }
+ 
+@@ -4535,7 +4564,7 @@
+     pat = vim_strsave(filepat);
+     for (i = 0; pat[i]; ++i)
+ 	if (pat[i] == '\\' && pat[i + 1] == ' ')
+-	    STRCPY(pat + i, pat + i + 1);
++	    mch_memmove(pat + i, pat + i + 1, STRLEN(pat + i));
+ 
+     flags |= EW_FILE | EW_EXEC;
+ 
+@@ -5907,7 +5936,7 @@
+ 
+ # ifdef FEAT_AUTOCMD
+     /* Don't execute autocommands while creating the window. */
+-    ++autocmd_block;
++    block_autocmds();
+ # endif
+     /* don't use a new tab page */
+     cmdmod.tab = 0;
+@@ -5916,6 +5945,9 @@
+     if (win_split((int)p_cwh, WSP_BOT) == FAIL)
+     {
+ 	beep_flush();
++# ifdef FEAT_AUTOCMD
++	unblock_autocmds();
++# endif
+ 	return K_IGNORE;
+     }
+     cmdwin_type = ccline.cmdfirstc;
+@@ -5938,7 +5970,7 @@
+ 
+ # ifdef FEAT_AUTOCMD
+     /* Do execute autocommands for setting the filetype (load syntax). */
+-    --autocmd_block;
++    unblock_autocmds();
+ # endif
+ 
+     /* Showing the prompt may have set need_wait_return, reset it. */
+@@ -6092,7 +6124,7 @@
+ 
+ # ifdef FEAT_AUTOCMD
+ 	/* Don't execute autocommands while deleting the window. */
+-	++autocmd_block;
++	block_autocmds();
+ # endif
+ 	wp = curwin;
+ 	bp = curbuf;
+@@ -6104,7 +6136,7 @@
+ 	win_size_restore(&winsizes);
+ 
+ # ifdef FEAT_AUTOCMD
+-	--autocmd_block;
++	unblock_autocmds();
+ # endif
+     }
+ 
+diff -Naur vim71.orig/src/feature.h vim71/src/feature.h
+--- vim71.orig/src/feature.h	2007-05-07 19:33:19.000000000 +0000
++++ vim71/src/feature.h	2007-12-08 20:34:51.000000000 +0000
+@@ -673,7 +673,7 @@
+ # define ESC_CHG_TO_ENG_MODE		/* if defined, when ESC pressed,
+ 					 * turn to english mode
+ 					 */
+-# if !defined(FEAT_XFONTSET) && defined(HAVE_X11)
++# if !defined(FEAT_XFONTSET) && defined(HAVE_X11) && !defined(HAVE_GTK2)
+ #  define FEAT_XFONTSET			/* Hangul input requires xfontset */
+ # endif
+ # if defined(FEAT_XIM) && !defined(LINT)
+diff -Naur vim71.orig/src/fileio.c vim71/src/fileio.c
+--- vim71.orig/src/fileio.c	2007-05-10 11:29:44.000000000 +0000
++++ vim71/src/fileio.c	2007-12-08 20:34:53.000000000 +0000
+@@ -44,6 +44,10 @@
+ /* Is there any system that doesn't have access()? */
+ #define USE_MCH_ACCESS
+ 
++#if defined(sun) && defined(S_ISCHR)
++# define OPEN_CHR_FILES
++static int is_dev_fd_file(char_u *fname);
++#endif
+ #ifdef FEAT_MBYTE
+ static char_u *next_fenc __ARGS((char_u **pp));
+ # ifdef FEAT_EVAL
+@@ -406,6 +410,10 @@
+ # ifdef S_ISSOCK
+ 		      && !S_ISSOCK(perm)	    /* ... or socket */
+ # endif
++# ifdef OPEN_CHR_FILES
++		      && !(S_ISCHR(perm) && is_dev_fd_file(fname))
++			/* ... or a character special file named /dev/fd/<n> */
++# endif
+ 						)
+ 	{
+ 	    if (S_ISDIR(perm))
+@@ -424,7 +432,7 @@
+ 	 */
+ 	if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
+ 	{
+-	    filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option"), 0);
++	    filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
+ 	    msg_end();
+ 	    msg_scroll = msg_save;
+ 	    return FAIL;
+@@ -646,6 +654,7 @@
+ 	curbuf->b_start_eol = TRUE;
+ #ifdef FEAT_MBYTE
+ 	curbuf->b_p_bomb = FALSE;
++	curbuf->b_start_bomb = FALSE;
+ #endif
+     }
+ 
+@@ -904,7 +913,10 @@
+ 	file_rewind = FALSE;
+ #ifdef FEAT_MBYTE
+ 	if (set_options)
++	{
+ 	    curbuf->b_p_bomb = FALSE;
++	    curbuf->b_start_bomb = FALSE;
++	}
+ 	conv_error = 0;
+ #endif
+     }
+@@ -1353,7 +1365,10 @@
+ 		    size -= blen;
+ 		    mch_memmove(ptr, ptr + blen, (size_t)size);
+ 		    if (set_options)
++		    {
+ 			curbuf->b_p_bomb = TRUE;
++			curbuf->b_start_bomb = TRUE;
++		    }
+ 		}
+ 
+ 		if (fio_flags == FIO_UCSBOM)
+@@ -2265,6 +2280,13 @@
+ 	    }
+ #  endif
+ # endif
++# ifdef OPEN_CHR_FILES
++	    if (S_ISCHR(perm))			    /* or character special */
++	    {
++		STRCAT(IObuff, _("[character special]"));
++		c = TRUE;
++	    }
++# endif
+ #endif
+ 	    if (curbuf->b_p_ro)
+ 	    {
+@@ -2464,6 +2486,25 @@
+     return OK;
+ }
+ 
++#ifdef OPEN_CHR_FILES
++/*
++ * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
++ * which is the name of files used for process substitution output by
++ * some shells on some operating systems, e.g., bash on SunOS.
++ * Do not accept "/dev/fd/[012]", opening these may hang Vim.
++ */
++    static int
++is_dev_fd_file(fname)
++    char_u	*fname;
++{
++    return (STRNCMP(fname, "/dev/fd/", 8) == 0
++	    && VIM_ISDIGIT(fname[8])
++	    && *skipdigits(fname + 9) == NUL
++	    && (fname[9] != NUL
++		|| (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
++}
++#endif
++
+ #ifdef FEAT_MBYTE
+ 
+ /*
+@@ -2734,6 +2775,32 @@
+ #endif
+ 
+ /*
++ * Return TRUE if a file appears to be read-only from the file permissions.
++ */
++    int
++check_file_readonly(fname, perm)
++    char_u	*fname;		/* full path to file */
++    int		perm;		/* known permissions on file */
++{
++#ifndef USE_MCH_ACCESS
++    int	    fd = 0;
++#endif
++
++    return (
++#ifdef USE_MCH_ACCESS
++# ifdef UNIX
++	(perm & 0222) == 0 ||
++# endif
++	mch_access((char *)fname, W_OK)
++#else
++	(fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
++					? TRUE : (close(fd), FALSE)
++#endif
++	);
++}
++
++
++/*
+  * buf_write() - write to file "fname" lines "start" through "end"
+  *
+  * We do our own buffering here because fwrite() is so slow.
+@@ -3142,7 +3209,8 @@
+      * Get information about original file (if there is one).
+      */
+ #if defined(UNIX) && !defined(ARCHIE)
+-    st_old.st_dev = st_old.st_ino = 0;
++    st_old.st_dev = 0;
++    st_old.st_ino = 0;
+     perm = -1;
+     if (mch_stat((char *)fname, &st_old) < 0)
+ 	newfile = TRUE;
+@@ -3219,17 +3287,8 @@
+ 	 * Check if the file is really writable (when renaming the file to
+ 	 * make a backup we won't discover it later).
+ 	 */
+-	file_readonly = (
+-# ifdef USE_MCH_ACCESS
+-#  ifdef UNIX
+-		    (perm & 0222) == 0 ||
+-#  endif
+-		    mch_access((char *)fname, W_OK)
+-# else
+-		    (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
+-						   ? TRUE : (close(fd), FALSE)
+-# endif
+-		    );
++	file_readonly = check_file_readonly(fname, (int)perm);
++
+ 	if (!forceit && file_readonly)
+ 	{
+ 	    if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
+@@ -5495,6 +5554,8 @@
+ }
+ #endif
+ 
++#if defined(FEAT_VIMINFO) || defined(FEAT_BROWSE) || \
++    defined(FEAT_QUICKFIX) || defined(PROTO)
+ /*
+  * Try to find a shortname by comparing the fullname with the current
+  * directory.
+@@ -5548,6 +5609,7 @@
+ 	p = NULL;
+     return p;
+ }
++#endif
+ 
+ /*
+  * Shorten filenames for all buffers.
+@@ -7107,6 +7169,7 @@
+ 
+ static event_T	last_event;
+ static int	last_group;
++static int	autocmd_blocked = 0;	/* block all autocmds */
+ 
+ /*
+  * Show the autocommands for one AutoPat.
+@@ -8396,7 +8459,7 @@
+      * Quickly return if there are no autocommands for this event or
+      * autocommands are blocked.
+      */
+-    if (first_autopat[(int)event] == NULL || autocmd_block > 0)
++    if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
+ 	goto BYPASS_AU;
+ 
+     /*
+@@ -8710,6 +8773,40 @@
+     return retval;
+ }
+ 
++# ifdef FEAT_EVAL
++static char_u	*old_termresponse = NULL;
++# endif
++
++/*
++ * Block triggering autocommands until unblock_autocmd() is called.
++ * Can be used recursively, so long as it's symmetric.
++ */
++    void
++block_autocmds()
++{
++# ifdef FEAT_EVAL
++    /* Remember the value of v:termresponse. */
++    if (autocmd_blocked == 0)
++	old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
++# endif
++    ++autocmd_blocked;
++}
++
++    void
++unblock_autocmds()
++{
++    --autocmd_blocked;
++
++# ifdef FEAT_EVAL
++    /* When v:termresponse was set while autocommands were blocked, trigger
++     * the autocommands now.  Esp. useful when executing a shell command
++     * during startup (vimdiff). */
++    if (autocmd_blocked == 0
++		      && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
++	apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
++# endif
++}
++
+ /*
+  * Find next autocommand pattern that matches.
+  */
+diff -Naur vim71.orig/src/fold.c vim71/src/fold.c
+--- vim71.orig/src/fold.c	2007-05-07 19:46:32.000000000 +0000
++++ vim71/src/fold.c	2007-12-08 20:34:53.000000000 +0000
+@@ -858,7 +858,14 @@
+ 	    || foldmethodIsDiff(wp)
+ #endif
+ 	    || foldmethodIsSyntax(wp))
++    {
++	int save_got_int = got_int;
++
++	/* reset got_int here, otherwise it won't work */
++	got_int = FALSE;
+ 	foldUpdateIEMS(wp, top, bot);
++	got_int |= save_got_int;
++    }
+ }
+ 
+ /* foldUpdateAll() {{{2 */
+diff -Naur vim71.orig/src/getchar.c vim71/src/getchar.c
+--- vim71.orig/src/getchar.c	2007-05-07 19:18:20.000000000 +0000
++++ vim71/src/getchar.c	2007-12-08 20:34:53.000000000 +0000
+@@ -253,8 +253,9 @@
+ 	return;
+     }
+     else if (buf->bh_index != 0)
+-	STRCPY(buf->bh_first.b_next->b_str,
+-				 buf->bh_first.b_next->b_str + buf->bh_index);
++	mch_memmove(buf->bh_first.b_next->b_str,
++		    buf->bh_first.b_next->b_str + buf->bh_index,
++		    STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
+     buf->bh_index = 0;
+ 
+     if (buf->bh_space >= (int)slen)
+@@ -1596,8 +1597,16 @@
+ 		continue;
+ 	    }
+ #endif
+-
+ #ifdef FEAT_GUI
++	    /* Handle focus event here, so that the caller doesn't need to
++	     * know about it.  Return K_IGNORE so that we loop once (needed if
++	     * 'lazyredraw' is set). */
++	    if (c == K_FOCUSGAINED || c == K_FOCUSLOST)
++	    {
++		ui_focus_change(c == K_FOCUSGAINED);
++		c = K_IGNORE;
++	    }
++
+ 	    /* Translate K_CSI to CSI.  The special key is only used to avoid
+ 	     * it being recognized as the start of a special key. */
+ 	    if (c == K_CSI)
+@@ -1741,6 +1750,22 @@
+ }
+ 
+ /*
++ * Like safe_vgetc(), but loop to handle K_IGNORE.
++ * Also ignore scrollbar events.
++ */
++    int
++plain_vgetc()
++{
++    int c;
++
++    do
++    {
++	c = safe_vgetc();
++    } while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
++    return c;
++}
++
++/*
+  * Check if a character is available, such that vgetc() will not block.
+  * If the next character is a special character or multi-byte, the returned
+  * character is not valid!.
+diff -Naur vim71.orig/src/globals.h vim71/src/globals.h
+--- vim71.orig/src/globals.h	2007-05-07 19:44:26.000000000 +0000
++++ vim71/src/globals.h	2007-12-08 20:34:52.000000000 +0000
+@@ -301,13 +301,17 @@
+ #endif
+ 
+ #ifdef FEAT_EVAL
+-/* Garbage collection can only take place when we are sure there are no Lists
++/*
++ * Garbage collection can only take place when we are sure there are no Lists
+  * or Dictionaries being used internally.  This is flagged with
+  * "may_garbage_collect" when we are at the toplevel.
+  * "want_garbage_collect" is set by the garbagecollect() function, which means
+- * we do garbage collection before waiting for a char at the toplevel. */
++ * we do garbage collection before waiting for a char at the toplevel.
++ * "garbage_collect_at_exit" indicates garbagecollect(1) was called.
++ */
+ EXTERN int	may_garbage_collect INIT(= FALSE);
+ EXTERN int	want_garbage_collect INIT(= FALSE);
++EXTERN int	garbage_collect_at_exit INIT(= FALSE);
+ 
+ /* ID of script being sourced or was sourced to define the current function. */
+ EXTERN scid_T	current_SID INIT(= 0);
+@@ -362,7 +366,6 @@
+ EXTERN int	autocmd_busy INIT(= FALSE);	/* Is apply_autocmds() busy? */
+ EXTERN int	autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
+ EXTERN int	autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */
+-EXTERN int	autocmd_block INIT(= 0);	/* block all autocmds */
+ EXTERN int	modified_was_set;		/* did ":set modified" */
+ EXTERN int	did_filetype INIT(= FALSE);	/* FileType event found */
+ EXTERN int	keep_filetype INIT(= FALSE);	/* value for did_filetype when
+@@ -801,7 +804,7 @@
+ EXTERN int (*mb_char2bytes) __ARGS((int c, char_u *buf)) INIT(= latin_char2bytes);
+ EXTERN int (*mb_ptr2cells) __ARGS((char_u *p)) INIT(= latin_ptr2cells);
+ EXTERN int (*mb_char2cells) __ARGS((int c)) INIT(= latin_char2cells);
+-EXTERN int (*mb_off2cells) __ARGS((unsigned off)) INIT(= latin_off2cells);
++EXTERN int (*mb_off2cells) __ARGS((unsigned off, unsigned max_off)) INIT(= latin_off2cells);
+ EXTERN int (*mb_ptr2char) __ARGS((char_u *p)) INIT(= latin_ptr2char);
+ EXTERN int (*mb_head_off) __ARGS((char_u *base, char_u *p)) INIT(= latin_head_off);
+ 
+diff -Naur vim71.orig/src/gui.c vim71/src/gui.c
+--- vim71.orig/src/gui.c	2007-05-07 19:50:55.000000000 +0000
++++ vim71/src/gui.c	2007-12-08 20:34:53.000000000 +0000
+@@ -1080,7 +1080,8 @@
+ 		cur_width = gui.char_width;
+ 	    }
+ #ifdef FEAT_MBYTE
+-	    if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col) > 1)
++	    if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col,
++				    LineOffset[gui.row] + screen_Columns) > 1)
+ 	    {
+ 		/* Double wide character. */
+ 		if (shape_table[idx].shape != SHAPE_VER)
+@@ -1159,7 +1160,7 @@
+ #endif
+ 
+ # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
+- 	|| defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC))
++	|| defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC))
+     if (gui_has_tabline())
+ 	text_area_y += gui.tabline_height;
+ #endif
+@@ -4213,7 +4214,19 @@
+ #endif
+ 	    )
+     {
+-	redraw_win_later(wp, VALID);
++	int type = VALID;
++
++#ifdef FEAT_INS_EXPAND
++	if (pum_visible())
++	{
++	    type = NOT_VALID;
++	    wp->w_lines_valid = 0;
++	}
++#endif
++	/* Don't set must_redraw here, it may cause the popup menu to
++	 * disappear when losing focus after a scrollbar drag. */
++	if (wp->w_redr_type < type)
++	    wp->w_redr_type = type;
+ 	updateWindow(wp);   /* update window, status line, and cmdline */
+     }
+ 
+@@ -4518,7 +4531,18 @@
+     xim_set_focus(in_focus);
+ # endif
+ 
+-    ui_focus_change(in_focus);
++    /* Put events in the input queue only when allowed.
++     * ui_focus_change() isn't called directly, because it invokes
++     * autocommands and that must not happen asynchronously. */
++    if (!hold_gui_events)
++    {
++	char_u  bytes[3];
++
++	bytes[0] = CSI;
++	bytes[1] = KS_EXTRA;
++	bytes[2] = in_focus ? (int)KE_FOCUSGAINED : (int)KE_FOCUSLOST;
++	add_to_input_buf(bytes, 3);
++    }
+ #endif
+ }
+ 
+@@ -5117,7 +5141,7 @@
+ 		p = vim_strsave_escaped(fnames[i], (char_u *)"\\ \t\"|");
+ # endif
+ 		if (p != NULL)
+-		    add_to_input_buf(p, (int)STRLEN(p));
++		    add_to_input_buf_csi(p, (int)STRLEN(p));
+ 		vim_free(p);
+ 		vim_free(fnames[i]);
+ 	    }
+diff -Naur vim71.orig/src/gui_gtk.c vim71/src/gui_gtk.c
+--- vim71.orig/src/gui_gtk.c	2007-05-10 08:37:37.000000000 +0000
++++ vim71/src/gui_gtk.c	2007-12-08 20:34:51.000000000 +0000
+@@ -53,8 +53,8 @@
+ # ifdef bindtextdomain
+ #  undef bindtextdomain
+ # endif
+-# ifdef bindtextdomain_codeset
+-#  undef bindtextdomain_codeset
++# ifdef bind_textdomain_codeset
++#  undef bind_textdomain_codeset
+ # endif
+ # if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS)
+ #  define ENABLE_NLS	/* so the texts in the dialog boxes are translated */
+@@ -1630,11 +1630,14 @@
+  */
+ /*ARGSUSED*/
+     static int
+-dlg_key_press_event(GtkWidget * widget, GdkEventKey * event, CancelData *data)
++dlg_key_press_event(GtkWidget *widget, GdkEventKey *event, CancelData *data)
+ {
+-    /* Ignore hitting Enter when there is no default button. */
+-    if (data->ignore_enter && event->keyval == GDK_Return)
++    /* Ignore hitting Enter (or Space) when there is no default button. */
++    if (data->ignore_enter && (event->keyval == GDK_Return
++						     || event->keyval == ' '))
+ 	return TRUE;
++    else    /* A different key was pressed, return to normal behavior */
++	data->ignore_enter = FALSE;
+ 
+     if (event->keyval != GDK_Escape && event->keyval != GDK_Return)
+ 	return FALSE;
+@@ -2224,6 +2227,13 @@
+ {
+     DialogInfo *di = (DialogInfo *)data;
+ 
++    /* Ignore hitting Enter (or Space) when there is no default button. */
++    if (di->ignore_enter && (event->keyval == GDK_Return
++						     || event->keyval == ' '))
++	return TRUE;
++    else    /* A different key was pressed, return to normal behavior */
++	di->ignore_enter = FALSE;
++
+     /* Close the dialog when hitting "Esc". */
+     if (event->keyval == GDK_Escape)
+     {
+diff -Naur vim71.orig/src/gui_gtk_x11.c vim71/src/gui_gtk_x11.c
+--- vim71.orig/src/gui_gtk_x11.c	2007-05-10 08:37:49.000000000 +0000
++++ vim71/src/gui_gtk_x11.c	2007-12-08 20:34:53.000000000 +0000
+@@ -36,8 +36,8 @@
+ # ifdef bindtextdomain
+ #  undef bindtextdomain
+ # endif
+-# ifdef bindtextdomain_codeset
+-#  undef bindtextdomain_codeset
++# ifdef bind_textdomain_codeset
++#  undef bind_textdomain_codeset
+ # endif
+ # if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS)
+ #  define ENABLE_NLS	/* so the texts in the dialog boxes are translated */
+@@ -813,10 +813,15 @@
+     if (blink_state == BLINK_NONE)
+ 	gui_mch_start_blink();
+ 
+-    /* make sure keyboard input goes to the draw area (if this is focus for a window) */
++    /* make sure keyboard input goes to the draw area (if this is focus for a
++     * window) */
+     if (widget != gui.drawarea)
+ 	gtk_widget_grab_focus(gui.drawarea);
+ 
++    /* make sure the input buffer is read */
++    if (gtk_main_level() > 0)
++	gtk_main_quit();
++
+     return TRUE;
+ }
+ 
+@@ -829,6 +834,10 @@
+     if (blink_state != BLINK_NONE)
+ 	gui_mch_stop_blink();
+ 
++    /* make sure the input buffer is read */
++    if (gtk_main_level() > 0)
++	gtk_main_quit();
++
+     return TRUE;
+ }
+ 
+@@ -2188,8 +2197,10 @@
+     escaped_filename = vim_strsave_escaped(filename, escape_chars);
+     if (escaped_filename == NULL)
+ 	return FALSE;
+-    mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename, NULL);
++    mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename,
++									NULL);
+     vim_free(escaped_filename);
++
+     /*
+      * Use a reasonable hardcoded set of 'sessionoptions' flags to avoid
+      * unpredictable effects when the session is saved automatically.  Also,
+@@ -2199,7 +2210,7 @@
+      */
+     save_ssop_flags = ssop_flags;
+     ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS
+-		  |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE);
++		  |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE|SSOP_TABPAGES);
+ 
+     do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session");
+     failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL);
+@@ -3212,8 +3223,9 @@
+ 	{
+ 	    if (clicked_page == 0)
+ 	    {
+-		/* Click after all tabs moves to next tab page. */
+-		if (send_tabline_event(0) && gtk_main_level() > 0)
++		/* Click after all tabs moves to next tab page.  When "x" is
++		 * small guess it's the left button. */
++		if (send_tabline_event(x < 50 ? -1 : 0) && gtk_main_level() > 0)
+ 		    gtk_main_quit();
+ 	    }
+ #ifndef HAVE_GTK2
+@@ -4032,6 +4044,8 @@
+ 	unsigned int	w, h;
+ 	int		x = 0;
+ 	int		y = 0;
++	guint		pixel_width;
++	guint		pixel_height;
+ 
+ 	mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
+ 
+@@ -4043,12 +4057,31 @@
+ 		p_window = h - 1;
+ 	    Rows = h;
+ 	}
++
++	pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width);
++	pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height);
++
++#ifdef HAVE_GTK2
++	pixel_width  += get_menu_tool_width();
++	pixel_height += get_menu_tool_height();
++#endif
++
+ 	if (mask & (XValue | YValue))
++	{
++	    int w, h;
++	    gui_mch_get_screen_dimensions(&w, &h);
++	    h += p_ghr + get_menu_tool_height();
++	    w += get_menu_tool_width();
++	    if (mask & XNegative)
++		x += w - pixel_width;
++	    if (mask & YNegative)
++		y += h - pixel_height;
+ #ifdef HAVE_GTK2
+ 	    gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
+ #else
+ 	    gtk_widget_set_uposition(gui.mainwin, x, y);
+ #endif
++	}
+ 	vim_free(gui.geom);
+ 	gui.geom = NULL;
+ 
+@@ -4059,14 +4092,6 @@
+ 	 */
+ 	if (gtk_socket_id != 0  &&  (mask & WidthValue || mask & HeightValue))
+ 	{
+-	    guint pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width);
+-	    guint pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height);
+-
+-#ifdef HAVE_GTK2
+-	    pixel_width  += get_menu_tool_width();
+-	    pixel_height += get_menu_tool_height();
+-#endif
+-
+ 	    update_window_manager_hints(pixel_width, pixel_height);
+ 	    init_window_hints_state = 1;
+ 	    g_timeout_add(1000, check_startup_plug_hints, NULL);
+diff -Naur vim71.orig/src/gui_xmebw.c vim71/src/gui_xmebw.c
+--- vim71.orig/src/gui_xmebw.c	2007-05-07 19:30:49.000000000 +0000
++++ vim71/src/gui_xmebw.c	2007-12-08 20:34:53.000000000 +0000
+@@ -395,11 +395,15 @@
+ 
+     /* Create the "highlight" pixmap. */
+     color[4].pixel = eb->primitive.bottom_shadow_color;
++#ifdef XpmAllocColor /* SGI doesn't have it */
+     attr.valuemask = XpmColorSymbols | XpmCloseness | XpmAllocColor;
++    attr.alloc_color = alloc_color;
++#else
++    attr.valuemask = XpmColorSymbols | XpmCloseness;
++#endif
+     attr.closeness = 65535;	/* accuracy isn't crucial */
+     attr.colorsymbols = color;
+     attr.numsymbols = XtNumber(color);
+-    attr.alloc_color = alloc_color;
+ 
+     status = XpmCreatePixmapFromData(dpy, root, data, &pix, NULL, &attr);
+     XpmFreeAttributes(&attr);
+diff -Naur vim71.orig/src/if_cscope.c vim71/src/if_cscope.c
+--- vim71.orig/src/if_cscope.c	2007-03-11 14:29:57.000000000 +0000
++++ vim71/src/if_cscope.c	2007-12-08 20:34:51.000000000 +0000
+@@ -24,11 +24,6 @@
+     /* not UNIX, must be WIN32 */
+ # include "vimio.h"
+ # include <fcntl.h>
+-# include <process.h>
+-# define STDIN_FILENO    0
+-# define STDOUT_FILENO   1
+-# define STDERR_FILENO   2
+-# define pipe(fds) _pipe(fds, 256, O_TEXT|O_NOINHERIT)
+ #endif
+ #include "if_cscope.h"
+ 
+@@ -65,7 +60,7 @@
+ static char *	    cs_parse_results __ARGS((int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search));
+ static char *	    cs_pathcomponents __ARGS((char *path));
+ static void	    cs_print_tags_priv __ARGS((char **, char **, int));
+-static int	    cs_read_prompt __ARGS((int ));
++static int	    cs_read_prompt __ARGS((int));
+ static void	    cs_release_csp __ARGS((int, int freefnpp));
+ static int	    cs_reset __ARGS((exarg_T *eap));
+ static char *	    cs_resolve_file __ARGS((int, char *));
+@@ -73,6 +68,8 @@
+ 
+ 
+ static csinfo_T	    csinfo[CSCOPE_MAX_CONNECTIONS];
++static int	    eap_arg_len;    /* length of eap->arg, set in
++				       cs_lookup_cmd() */
+ static cscmd_T	    cs_cmds[] =
+ {
+     { "add",	cs_add,
+@@ -260,14 +257,7 @@
+ 
+     if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
+ 	return TRUE;
+-
+-    if ((int)strlen(p) > size)
+-    {
+-	strncpy((char *)buf, p, size - 1);
+-	buf[size] = '\0';
+-    }
+-    else
+-	(void)strcpy((char *)buf, p);
++    vim_strncpy(buf, (char_u *)p, size - 1);
+ 
+     return FALSE;
+ } /* cs_fgets */
+@@ -386,7 +376,7 @@
+  * PRIVATE: cs_add
+  *
+  * add cscope database or a directory name (to look for cscope.out)
+- * the the cscope connection list
++ * to the cscope connection list
+  *
+  * MAXPATHL 256
+  */
+@@ -509,7 +499,7 @@
+ #if defined(UNIX)
+     else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
+ #else
+-	/* substitute define S_ISREG from os_unix.h */
++	/* WIN32 - substitute define S_ISREG from os_unix.h */
+     else if (((statbuf.st_mode) & S_IFMT) == S_IFREG)
+ #endif
+     {
+@@ -722,17 +712,32 @@
+ cs_create_connection(i)
+     int i;
+ {
+-    int to_cs[2], from_cs[2], len;
+-    char *prog, *cmd, *ppath = NULL;
+-#ifndef UNIX
+-    int in_save, out_save, err_save;
+-    long_i ph;
+-# ifdef FEAT_GUI
+-    HWND activewnd = NULL;
+-    HWND consolewnd = NULL;
++#ifdef UNIX
++    int		to_cs[2], from_cs[2];
++#endif
++    int		len;
++    char	*prog, *cmd, *ppath = NULL;
++#ifdef WIN32
++    int		fd;
++    SECURITY_ATTRIBUTES sa;
++    PROCESS_INFORMATION pi;
++    STARTUPINFO si;
++    BOOL	pipe_stdin = FALSE, pipe_stdout = FALSE;
++    HANDLE	stdin_rd, stdout_rd;
++    HANDLE	stdout_wr, stdin_wr;
++    BOOL	created;
++# ifdef __BORLANDC__
++#  define OPEN_OH_ARGTYPE long
++# else
++#  if (_MSC_VER >= 1300)
++#   define OPEN_OH_ARGTYPE intptr_t
++#  else
++#   define OPEN_OH_ARGTYPE long
++#  endif
+ # endif
+ #endif
+ 
++#if defined(UNIX)
+     /*
+      * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
+      * from_cs[0] and writes to to_cs[1].
+@@ -753,18 +758,12 @@
+ 	return CSCOPE_FAILURE;
+     }
+ 
+-#if defined(UNIX)
+     switch (csinfo[i].pid = fork())
+     {
+     case -1:
+ 	(void)EMSG(_("E622: Could not fork for cscope"));
+ 	goto err_closing;
+     case 0:				/* child: run cscope. */
+-#else
+-	in_save = dup(STDIN_FILENO);
+-	out_save = dup(STDOUT_FILENO);
+-	err_save = dup(STDERR_FILENO);
+-#endif
+ 	if (dup2(to_cs[0], STDIN_FILENO) == -1)
+ 	    PERROR("cs_create_connection 1");
+ 	if (dup2(from_cs[1], STDOUT_FILENO) == -1)
+@@ -773,15 +772,32 @@
+ 	    PERROR("cs_create_connection 3");
+ 
+ 	/* close unused */
+-#if defined(UNIX)
+ 	(void)close(to_cs[1]);
+ 	(void)close(from_cs[0]);
+ #else
+-	/* On win32 we must close opposite ends because we are the parent */
+-	(void)close(to_cs[0]);
+-	to_cs[0] = -1;
+-	(void)close(from_cs[1]);
+-	from_cs[1] = -1;
++	/* WIN32 */
++	/* Create pipes to communicate with cscope */
++	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
++	sa.bInheritHandle = TRUE;
++	sa.lpSecurityDescriptor = NULL;
++
++	if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
++		|| !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0)))
++	{
++	    (void)EMSG(_("E566: Could not create cscope pipes"));
++err_closing:
++	    if (pipe_stdin)
++	    {
++		CloseHandle(stdin_rd);
++		CloseHandle(stdin_wr);
++	    }
++	    if (pipe_stdout)
++	    {
++		CloseHandle(stdout_rd);
++		CloseHandle(stdout_wr);
++	    }
++	    return CSCOPE_FAILURE;
++	}
+ #endif
+ 	/* expand the cscope exec for env var's */
+ 	if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL)
+@@ -789,6 +805,7 @@
+ #ifdef UNIX
+ 	    return CSCOPE_FAILURE;
+ #else
++	    /* WIN32 */
+ 	    goto err_closing;
+ #endif
+ 	}
+@@ -805,6 +822,7 @@
+ #ifdef UNIX
+ 		return CSCOPE_FAILURE;
+ #else
++		/* WIN32 */
+ 		goto err_closing;
+ #endif
+ 	    }
+@@ -823,6 +841,7 @@
+ #ifdef UNIX
+ 	    return CSCOPE_FAILURE;
+ #else
++	    /* WIN32 */
+ 	    goto err_closing;
+ #endif
+ 	}
+@@ -831,6 +850,7 @@
+ #if defined(UNIX)
+ 	(void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
+ #else
++	/* WIN32 */
+ 	(void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
+ #endif
+ 	if (csinfo[i].ppath != NULL)
+@@ -856,60 +876,6 @@
+ 	exit(127);
+ 	/* NOTREACHED */
+     default:	/* parent. */
+-#else
+-# ifdef FEAT_GUI
+-	activewnd = GetForegroundWindow(); /* on win9x cscope steals focus */
+-	/* Dirty hack to hide annoying console window */
+-	if (AllocConsole())
+-	{
+-	    char *title;
+-	    title = (char *)alloc(1024);
+-	    if (title == NULL)
+-		FreeConsole();
+-	    else
+-	    {
+-		GetConsoleTitle(title, 1024); /* save for future restore */
+-		SetConsoleTitle(
+-		    "GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS");
+-		Sleep(40); /* as stated in MS KB we must wait 40 ms */
+-		consolewnd = FindWindow(NULL,
+-			"GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS");
+-		if (consolewnd != NULL)
+-		    ShowWindow(consolewnd, SW_HIDE);
+-		SetConsoleTitle(title);
+-		vim_free(title);
+-	    }
+-	}
+-# endif
+-	/* May be use &shell, &shellquote etc */
+-# ifdef __BORLANDC__
+-	/* BCC 5.5 uses a different function name for spawnlp */
+-	ph = (long_i)spawnlp(P_NOWAIT, prog, cmd, NULL);
+-# else
+-	ph = (long_i)_spawnlp(_P_NOWAIT, prog, cmd, NULL);
+-# endif
+-	vim_free(prog);
+-	vim_free(cmd);
+-# ifdef FEAT_GUI
+-	/* Dirty hack part two */
+-	if (activewnd != NULL)
+-	    /* restoring focus */
+-	    SetForegroundWindow(activewnd);
+-	if (consolewnd != NULL)
+-	    FreeConsole();
+-
+-# endif
+-	if (ph == -1)
+-	{
+-	    PERROR(_("cs_create_connection exec failed"));
+-	    (void)EMSG(_("E623: Could not spawn cscope process"));
+-	    goto err_closing;
+-	}
+-	/* else */
+-	csinfo[i].pid = 0;
+-	csinfo[i].hProc = (HANDLE)ph;
+-
+-#endif /* !UNIX */
+ 	/*
+ 	 * Save the file descriptors for later duplication, and
+ 	 * reopen as streams.
+@@ -919,22 +885,54 @@
+ 	if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
+ 	    PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
+ 
+-#if defined(UNIX)
+ 	/* close unused */
+ 	(void)close(to_cs[0]);
+ 	(void)close(from_cs[1]);
+ 
+ 	break;
+     }
++
+ #else
+-	/* restore stdhandles */
+-    dup2(in_save, STDIN_FILENO);
+-    dup2(out_save, STDOUT_FILENO);
+-    dup2(err_save, STDERR_FILENO);
+-    close(in_save);
+-    close(out_save);
+-    close(err_save);
+-#endif
++    /* WIN32 */
++    /* Create a new process to run cscope and use pipes to talk with it */
++    GetStartupInfo(&si);
++    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
++    si.wShowWindow = SW_HIDE;  /* Hide child application window */
++    si.hStdOutput = stdout_wr;
++    si.hStdError  = stdout_wr;
++    si.hStdInput  = stdin_rd;
++    created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
++							NULL, NULL, &si, &pi);
++    vim_free(prog);
++    vim_free(cmd);
++
++    if (!created)
++    {
++	PERROR(_("cs_create_connection exec failed"));
++	(void)EMSG(_("E623: Could not spawn cscope process"));
++	goto err_closing;
++    }
++    /* else */
++    csinfo[i].pid = pi.dwProcessId;
++    csinfo[i].hProc = pi.hProcess;
++    CloseHandle(pi.hThread);
++
++    /* TODO - tidy up after failure to create files on pipe handles. */
++    if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
++						      _O_TEXT|_O_APPEND)) < 0)
++	    || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
++	PERROR(_("cs_create_connection: fdopen for to_fp failed"));
++    if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
++						      _O_TEXT|_O_RDONLY)) < 0)
++	    || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
++	PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
++
++    /* Close handles for file descriptors inherited by the cscope process */
++    CloseHandle(stdin_rd);
++    CloseHandle(stdout_wr);
++
++#endif /* !UNIX */
++
+     return CSCOPE_SUCCESS;
+ } /* cs_create_connection */
+ 
+@@ -966,7 +964,7 @@
+     }
+ 
+     pat = opt + strlen(opt) + 1;
+-    if (pat == NULL || (pat != NULL && pat[0] == '\0'))
++    if (pat >= (char *)eap->arg + eap_arg_len)
+     {
+ 	cs_usage_msg(Find);
+ 	return FALSE;
+@@ -1317,7 +1315,7 @@
+ #else
+ 	    /* compare pathnames first */
+ 	    && ((fullpathcmp(csinfo[j].fname, fname, FALSE) & FPC_SAME)
+-		/* if not Windows 9x, test index file atributes too */
++		/* if not Windows 9x, test index file attributes too */
+ 		|| (!mch_windows95()
+ 		    && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
+ 		    && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
+@@ -1401,6 +1399,9 @@
+     if (eap->arg == NULL)
+ 	return NULL;
+ 
++    /* Store length of eap->arg before it gets modified by strtok(). */
++    eap_arg_len = STRLEN(eap->arg);
++
+     if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
+ 	return NULL;
+ 
+@@ -2099,8 +2100,8 @@
+ /*
+  * PRIVATE: cs_release_csp
+  *
+- * does the actual free'ing for the cs ptr with an optional flag of whether
+- * or not to free the filename.  called by cs_kill and cs_reset.
++ * Does the actual free'ing for the cs ptr with an optional flag of whether
++ * or not to free the filename.  Called by cs_kill and cs_reset.
+  */
+     static void
+ cs_release_csp(i, freefnpp)
+@@ -2118,10 +2119,13 @@
+ 	(void)fputs("q\n", csinfo[i].to_fp);
+ 	(void)fflush(csinfo[i].to_fp);
+     }
+-    /* give cscope chance to exit normally */
+-    if (csinfo[i].hProc != NULL
+-	    && WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
+-	TerminateProcess(csinfo[i].hProc, 0);
++    if (csinfo[i].hProc != NULL)
++    {
++	/* Give cscope a chance to exit normally */
++	if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
++	    TerminateProcess(csinfo[i].hProc, 0);
++	CloseHandle(csinfo[i].hProc);
++    }
+ #endif
+ 
+     if (csinfo[i].fr_fp != NULL)
+@@ -2195,7 +2199,7 @@
+ 	    cs_add_common(dblist[i], pplist[i], fllist[i]);
+ 	    if (p_csverbose)
+ 	    {
+-		/* dont' use smsg_attr because want to display
++		/* don't use smsg_attr() because we want to display the
+ 		 * connection number in the same line as
+ 		 * "Added cscope database..."
+ 		 */
+@@ -2304,6 +2308,21 @@
+     return CSCOPE_SUCCESS;
+ } /* cs_show */
+ 
++
++/*
++ * PUBLIC: cs_end
++ *
++ * Only called when VIM exits to quit any cscope sessions.
++ */
++    void
++cs_end()
++{
++    int i;
++
++    for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
++	cs_release_csp(i, TRUE);
++}
++
+ #endif	/* FEAT_CSCOPE */
+ 
+ /* the end */
+diff -Naur vim71.orig/src/if_cscope.h vim71/src/if_cscope.h
+--- vim71.orig/src/if_cscope.h	2005-06-30 17:14:22.000000000 +0000
++++ vim71/src/if_cscope.h	2007-12-08 20:34:51.000000000 +0000
+@@ -72,7 +72,7 @@
+     ino_t	    st_ino;	/* inode number of cscope db */
+ #else
+ # if defined(WIN32)
+-    int	    pid;	/* Can't get pid so set it to 0 ;) */
++    DWORD	    pid;	/* PID of the connected cscope process. */
+     HANDLE	    hProc;	/* cscope process handle */
+     DWORD	    nVolume;	/* Volume serial number, instead of st_dev */
+     DWORD	    nIndexHigh;	/* st_ino has no meaning in the Windows */
+diff -Naur vim71.orig/src/if_mzsch.c vim71/src/if_mzsch.c
+--- vim71.orig/src/if_mzsch.c	2007-05-12 11:13:47.000000000 +0000
++++ vim71/src/if_mzsch.c	2007-12-08 20:34:50.000000000 +0000
+@@ -308,6 +308,8 @@
+ static Scheme_Config *(*dll_scheme_current_config)(void);
+ static Scheme_Object *(*dll_scheme_char_string_to_byte_string)
+     (Scheme_Object *s);
++static Scheme_Object *(*dll_scheme_char_string_to_path)
++    (Scheme_Object *s);
+ # endif
+ 
+ /* arrays are imported directly */
+@@ -398,6 +400,8 @@
+ #  define scheme_current_config dll_scheme_current_config
+ #  define scheme_char_string_to_byte_string \
+     dll_scheme_char_string_to_byte_string
++#  define scheme_char_string_to_path \
++    dll_scheme_char_string_to_path
+ # endif
+ 
+ typedef struct
+@@ -498,6 +502,8 @@
+     {"scheme_current_config", (void **)&dll_scheme_current_config},
+     {"scheme_char_string_to_byte_string",
+ 	(void **)&dll_scheme_char_string_to_byte_string},
++    {"scheme_char_string_to_path",
++	(void **)&dll_scheme_char_string_to_path},
+ # endif
+     {NULL, NULL}};
+ 
+@@ -773,7 +779,14 @@
+ #ifdef MZSCHEME_COLLECTS
+     /* setup 'current-library-collection-paths' parameter */
+     scheme_set_param(scheme_config, MZCONFIG_COLLECTION_PATHS,
+-	    scheme_make_pair(scheme_make_string(MZSCHEME_COLLECTS),
++	    scheme_make_pair(
++# if MZSCHEME_VERSION_MAJOR >= 299
++		scheme_char_string_to_path(
++		    scheme_byte_string_to_char_string(
++			scheme_make_byte_string(MZSCHEME_COLLECTS))),
++# else
++		scheme_make_string(MZSCHEME_COLLECTS),
++# endif
+ 		scheme_null));
+ #endif
+ #ifdef HAVE_SANDBOX
+diff -Naur vim71.orig/src/if_perl.xs vim71/src/if_perl.xs
+--- vim71.orig/src/if_perl.xs	2006-08-16 12:45:15.000000000 +0000
++++ vim71/src/if_perl.xs	2007-12-08 20:34:53.000000000 +0000
+@@ -40,6 +40,28 @@
+ #    define PERL_SUBVERSION SUBVERSION
+ #endif
+ 
++/*
++ * Quoting Jan Dubois of Active State:
++ *    ActivePerl build 822 still identifies itself as 5.8.8 but already
++ *    contains many of the changes from the upcoming Perl 5.8.9 release.
++ *
++ * The changes include addition of two symbols (Perl_sv_2iv_flags,
++ * Perl_newXS_flags) not present in earlier releases.
++ *
++ * Jan Dubois suggested the following guarding scheme.
++ *
++ * Active State defined ACTIVEPERL_VERSION as a string in versions before
++ * 5.8.8; and so the comparison to 822 below needs to be guarded.
++ */
++#if (PERL_REVISION == 5) && (PERL_VERSION == 8) && (PERL_SUBVERSION >= 8)
++# if (ACTIVEPERL_VERSION >= 822) || (PERL_SUBVERSION >= 9)
++#  define PERL589_OR_LATER
++# endif
++#endif
++#if (PERL_REVISION == 5) && (PERL_VERSION >= 9)
++# define PERL589_OR_LATER
++#endif
++
+ #ifndef pTHX
+ #    define pTHX void
+ #    define pTHX_
+@@ -109,6 +131,10 @@
+ # else
+ #  define Perl_sv_catpvn dll_Perl_sv_catpvn
+ # endif
++#ifdef PERL589_OR_LATER
++#  define Perl_sv_2iv_flags dll_Perl_sv_2iv_flags
++#  define Perl_newXS_flags dll_Perl_newXS_flags
++#endif
+ # define Perl_sv_free dll_Perl_sv_free
+ # define Perl_sv_isa dll_Perl_sv_isa
+ # define Perl_sv_magic dll_Perl_sv_magic
+@@ -192,6 +218,10 @@
+ #else
+ static void (*Perl_sv_catpvn)(pTHX_ SV*, const char*, STRLEN);
+ #endif
++#ifdef PERL589_OR_LATER
++static IV (*Perl_sv_2iv_flags)(pTHX_ SV* sv, I32 flags);
++static CV * (*Perl_newXS_flags)(pTHX_ const char *name, XSUBADDR_t subaddr, const char *const filename, const char *const proto, U32 flags);
++#endif
+ static void (*Perl_sv_free)(pTHX_ SV*);
+ static int (*Perl_sv_isa)(pTHX_ SV*, const char*);
+ static void (*Perl_sv_magic)(pTHX_ SV*, SV*, int, const char*, I32);
+@@ -267,6 +297,10 @@
+ #else
+     {"Perl_sv_2pv", (PERL_PROC*)&Perl_sv_2pv},
+ #endif
++#ifdef PERL589_OR_LATER
++    {"Perl_sv_2iv_flags", (PERL_PROC*)&Perl_sv_2iv_flags},
++    {"Perl_newXS_flags", (PERL_PROC*)&Perl_newXS_flags},
++#endif
+     {"Perl_sv_bless", (PERL_PROC*)&Perl_sv_bless},
+ #if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+     {"Perl_sv_catpvn_flags", (PERL_PROC*)&Perl_sv_catpvn_flags},
+@@ -411,13 +445,13 @@
+     char *next;
+     char *token = (char *)s;
+ 
+-    while ((next = strchr(token, '\n')))
++    while ((next = strchr(token, '\n')) && !got_int)
+     {
+ 	*next++ = '\0';			/* replace \n with \0 */
+ 	msg_attr((char_u *)token, attr);
+ 	token = next;
+     }
+-    if (*token)
++    if (*token && !got_int)
+ 	msg_attr((char_u *)token, attr);
+ }
+ 
+diff -Naur vim71.orig/src/if_ruby.c vim71/src/if_ruby.c
+--- vim71.orig/src/if_ruby.c	2007-05-12 09:54:12.000000000 +0000
++++ vim71/src/if_ruby.c	2007-12-08 20:34:51.000000000 +0000
+@@ -789,7 +789,7 @@
+     return get_buffer_line(curbuf, curwin->w_cursor.lnum);
+ }
+ 
+-static VALUE set_current_line(VALUE str)
++static VALUE set_current_line(VALUE self, VALUE str)
+ {
+     return set_buffer_line(curbuf, curwin->w_cursor.lnum, str);
+ }
+diff -Naur vim71.orig/src/keymap.h vim71/src/keymap.h
+--- vim71.orig/src/keymap.h	2006-08-22 11:38:38.000000000 +0000
++++ vim71/src/keymap.h	2007-12-08 20:34:51.000000000 +0000
+@@ -254,6 +254,8 @@
+     , KE_DROP		/* DnD data is available */
+     , KE_CURSORHOLD	/* CursorHold event */
+     , KE_NOP		/* doesn't do something */
++    , KE_FOCUSGAINED	/* focus gained */
++    , KE_FOCUSLOST	/* focus lost */
+ };
+ 
+ /*
+@@ -445,6 +447,8 @@
+ #define K_CMDWIN	TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
+ 
+ #define K_DROP		TERMCAP2KEY(KS_EXTRA, KE_DROP)
++#define K_FOCUSGAINED	TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
++#define K_FOCUSLOST	TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
+ 
+ #define K_CURSORHOLD	TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
+ 
+diff -Naur vim71.orig/src/macros.h vim71/src/macros.h
+--- vim71.orig/src/macros.h	2007-05-07 19:38:22.000000000 +0000
++++ vim71/src/macros.h	2007-12-08 20:34:51.000000000 +0000
+@@ -54,10 +54,12 @@
+ 
+ /*
+  * toupper() and tolower() that use the current locale.
+- * On some systems toupper()/tolower() only work on lower/uppercase characters
++ * On some systems toupper()/tolower() only work on lower/uppercase
++ * characters, first use islower() or isupper() then.
+  * Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the
+  * range 0 - 255.  toupper()/tolower() on some systems can't handle others.
+- * Note: for UTF-8 use utf_toupper() and utf_tolower().
++ * Note: It is often better to use MB_TOLOWER() and MB_TOUPPER(), because many
++ * toupper() and tolower() implementations only work for ASCII.
+  */
+ #ifdef MSWIN
+ #  define TOUPPER_LOC(c)	toupper_tab[(c) & 255]
+diff -Naur vim71.orig/src/main.aap vim71/src/main.aap
+--- vim71.orig/src/main.aap	2007-05-07 19:46:43.000000000 +0000
++++ vim71/src/main.aap	2007-12-08 20:34:52.000000000 +0000
+@@ -56,9 +56,16 @@
+     config {virtual} auto/config.h auto/config.aap :
+                          auto/configure.aap configure.aap
+                          config.arg config.h.in config.aap.in
++        # Use "uname -a" to detect the architecture of the system.
++        @ok, uname = redir_system('uname -a', 0)
++        @if string.find(uname, "i386") >= 0:
++        @   arch = "i386"
++        @else:
++        @   arch = "ppc"
++        :print Building for $arch system
+         :sys CONFIG_STATUS=auto/config.status
+                 ./configure.aap `file2string("config.arg")`
+-                    --with-mac-arch=ppc
++                    --with-mac-arch=$arch
+                     --cache-file=auto/config.cache
+ 
+     # Configure arguments: create an empty "config.arg" file when its missing
+@@ -1167,7 +1174,7 @@
+         :symlink `os.getcwd()`/../runtime $RESDIR/vim/runtime
+ # TODO: Create the vimtutor application.
+ 
+-gui_bundle {virtual}: $(RESDIR) bundle-dir bundle-executable bundle-info
++gui_bundle {virtual}: $(RESDIR) bundle-dir bundle-executable bundle-info \
+                         bundle-resource bundle-language
+ 
+ bundle-dir {virtual}: $(APPDIR)/Contents $(VIMTARGET)
+@@ -1187,7 +1194,7 @@
+         :sys m4 $(M4FLAGSX) infplist.xml > $(APPDIR)/Contents/Info.plist
+ 
+ bundle-resource {virtual}: bundle-dir bundle-rsrc
+-    :copy {force} $(RSRC_DIR)/*.icns $(RESDIR)
++        :copy {force} $(RSRC_DIR)/*.icns $(RESDIR)
+ 
+ ### Classic resources
+ # Resource fork (in the form of a .rsrc file) for Classic Vim (Mac OS 9)
+diff -Naur vim71.orig/src/main.c vim71/src/main.c
+--- vim71.orig/src/main.c	2007-05-07 19:38:44.000000000 +0000
++++ vim71/src/main.c	2007-12-08 20:34:52.000000000 +0000
+@@ -954,7 +954,8 @@
+     int		cmdwin;	    /* TRUE when working in the command-line window */
+     int		noexmode;   /* TRUE when return on entering Ex mode */
+ {
+-    oparg_T	oa;	/* operator arguments */
++    oparg_T	oa;				/* operator arguments */
++    int		previous_got_int = FALSE;	/* "got_int" was TRUE */
+ 
+ #if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+     /* Setup to catch a terminating error from the X server.  Just ignore
+@@ -1015,12 +1016,32 @@
+ 		need_fileinfo = FALSE;
+ 	    }
+ 	}
+-	if (got_int && !global_busy)
++
++	/* Reset "got_int" now that we got back to the main loop.  Except when
++	 * inside a ":g/pat/cmd" command, then the "got_int" needs to abort
++	 * the ":g" command.
++	 * For ":g/pat/vi" we reset "got_int" when used once.  When used
++	 * a second time we go back to Ex mode and abort the ":g" command. */
++	if (got_int)
+ 	{
+-	    if (!quit_more)
+-		(void)vgetc();		/* flush all buffers */
+-	    got_int = FALSE;
++	    if (noexmode && global_busy && !exmode_active && previous_got_int)
++	    {
++		/* Typed two CTRL-C in a row: go back to ex mode as if "Q" was
++		 * used and keep "got_int" set, so that it aborts ":g". */
++		exmode_active = EXMODE_NORMAL;
++		State = NORMAL;
++	    }
++	    else if (!global_busy || !exmode_active)
++	    {
++		if (!quit_more)
++		    (void)vgetc();		/* flush all buffers */
++		got_int = FALSE;
++	    }
++	    previous_got_int = TRUE;
+ 	}
++	else
++	    previous_got_int = FALSE;
++
+ 	if (!exmode_active)
+ 	    msg_scroll = FALSE;
+ 	quit_more = FALSE;
+@@ -1309,6 +1330,13 @@
+ #ifdef FEAT_NETBEANS_INTG
+     netbeans_end();
+ #endif
++#ifdef FEAT_CSCOPE
++    cs_end();
++#endif
++#ifdef FEAT_EVAL
++    if (garbage_collect_at_exit)
++	garbage_collect();
++#endif
+ 
+     mch_exit(exitval);
+ }
+@@ -1360,8 +1388,7 @@
+ 	p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
+ 	if (p != NULL && *p != NUL)
+ 	{
+-	    STRCPY(NameBuff, p);
+-	    STRCAT(NameBuff, "/lang");
++	    vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
+ 	    bindtextdomain(VIMPACKAGE, (char *)NameBuff);
+ 	}
+ 	if (mustfree)
+@@ -3632,7 +3659,13 @@
+ 	mainerr_arg_missing((char_u *)filev[-1]);
+     if (mch_dirname(cwd, MAXPATHL) != OK)
+ 	return NULL;
+-    if ((p = vim_strsave_escaped_ext(cwd, PATH_ESC_CHARS, '\\', TRUE)) == NULL)
++    if ((p = vim_strsave_escaped_ext(cwd,
++#ifdef BACKSLASH_IN_FILENAME
++		    "",  /* rem_backslash() will tell what chars to escape */
++#else
++		    PATH_ESC_CHARS,
++#endif
++		    '\\', TRUE)) == NULL)
+ 	return NULL;
+     ga_init2(&ga, 1, 100);
+     ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
+diff -Naur vim71.orig/src/mbyte.c vim71/src/mbyte.c
+--- vim71.orig/src/mbyte.c	2007-05-07 19:47:09.000000000 +0000
++++ vim71/src/mbyte.c	2007-12-08 20:34:51.000000000 +0000
+@@ -1310,20 +1310,26 @@
+ /*
+  * mb_off2cells() function pointer.
+  * Return number of display cells for char at ScreenLines[off].
+- * Caller must make sure "off" and "off + 1" are valid!
++ * We make sure that the offset used is less than "max_off".
+  */
+ /*ARGSUSED*/
+     int
+-latin_off2cells(off)
++latin_off2cells(off, max_off)
+     unsigned	off;
++    unsigned	max_off;
+ {
+     return 1;
+ }
+ 
+     int
+-dbcs_off2cells(off)
++dbcs_off2cells(off, max_off)
+     unsigned	off;
++    unsigned	max_off;
+ {
++    /* never check beyond end of the line */
++    if (off >= max_off)
++	return 1;
++
+     /* Number of cells is equal to number of bytes, except for euc-jp when
+      * the first byte is 0x8e. */
+     if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+@@ -1332,10 +1338,11 @@
+ }
+ 
+     int
+-utf_off2cells(off)
++utf_off2cells(off, max_off)
+     unsigned	off;
++    unsigned	max_off;
+ {
+-    return ScreenLines[off + 1] == 0 ? 2 : 1;
++    return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1;
+ }
+ 
+ /*
+@@ -2320,7 +2327,7 @@
+ 		/* Single byte: first check normally, then with ignore case. */
+ 		if (s1[i] != s2[i])
+ 		{
+-		    cdiff = TOLOWER_LOC(s1[i]) - TOLOWER_LOC(s2[i]);
++		    cdiff = MB_TOLOWER(s1[i]) - MB_TOLOWER(s2[i]);
+ 		    if (cdiff != 0)
+ 			return cdiff;
+ 		}
+@@ -2899,12 +2906,8 @@
+     if (composing_hangul)
+ 	return TRUE;
+ #endif
+-    if (enc_dbcs != 0)
+-	return dbcs_off2cells(LineOffset[row] + col) > 1;
+-    if (enc_utf8)
+-	return (col + 1 < Columns
+-		&& ScreenLines[LineOffset[row] + col + 1] == 0);
+-    return FALSE;
++    return (*mb_off2cells)(LineOffset[row] + col,
++					LineOffset[row] + screen_Columns) > 1;
+ }
+ 
+ # if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \
+diff -Naur vim71.orig/src/message.c vim71/src/message.c
+--- vim71.orig/src/message.c	2007-05-07 19:31:59.000000000 +0000
++++ vim71/src/message.c	2007-12-08 20:34:53.000000000 +0000
+@@ -828,7 +828,7 @@
+ 		_("Messages maintainer: Bram Moolenaar <Bram at vim.org>"),
+ 		hl_attr(HLF_T));
+ 
+-    for (p = first_msg_hist; p != NULL; p = p->next)
++    for (p = first_msg_hist; p != NULL && !got_int; p = p->next)
+ 	if (p->msg != NULL)
+ 	    msg_attr(p->msg, p->attr);
+ 
+@@ -944,6 +944,7 @@
+ 		c = K_IGNORE;
+ 	    }
+ #endif
++
+ 	    /*
+ 	     * Allow scrolling back in the messages.
+ 	     * Also accept scroll-down commands when messages fill the screen,
+@@ -1840,9 +1841,10 @@
+     char_u	*sb_str = str;
+     int		sb_col = msg_col;
+     int		wrap;
++    int		did_last_char;
+ 
+     did_wait_return = FALSE;
+-    while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
++    while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL)
+     {
+ 	/*
+ 	 * We are at the end of the screen line when:
+@@ -1878,7 +1880,7 @@
+ 		/* output postponed text */
+ 		t_puts(&t_col, t_s, s, attr);
+ 
+-	    /* When no more prompt an no more room, truncate here */
++	    /* When no more prompt and no more room, truncate here */
+ 	    if (msg_no_more && lines_left == 0)
+ 		break;
+ 
+@@ -1909,7 +1911,10 @@
+ 		else
+ #endif
+ 		    msg_screen_putchar(*s++, attr);
++		did_last_char = TRUE;
+ 	    }
++	    else
++		did_last_char = FALSE;
+ 
+ 	    if (p_more)
+ 		/* store text for scrolling back */
+@@ -1927,7 +1932,8 @@
+ 	     * If screen is completely filled and 'more' is set then wait
+ 	     * for a character.
+ 	     */
+-	    --lines_left;
++	    if (lines_left > 0)
++		--lines_left;
+ 	    if (p_more && lines_left == 0 && State != HITRETURN
+ 					    && !msg_no_more && !exmode_active)
+ 	    {
+@@ -1943,11 +1949,7 @@
+ 
+ 	    /* When we displayed a char in last column need to check if there
+ 	     * is still more. */
+-	    if (*s >= ' '
+-#ifdef FEAT_RIGHTLEFT
+-		    && !cmdmsg_rl
+-#endif
+-	       )
++	    if (did_last_char)
+ 		continue;
+ 	}
+ 
+@@ -2234,7 +2236,7 @@
+ {
+     msgchunk_T	*mp;
+ 
+-    /* Only show somethign if there is more than one line, otherwise it looks
++    /* Only show something if there is more than one line, otherwise it looks
+      * weird, typing a command without output results in one line. */
+     mp = msg_sb_start(last_msgchunk);
+     if (mp == NULL || mp->sb_prev == NULL)
+@@ -2622,7 +2624,7 @@
+ 		}
+ 	    }
+ 
+-	    if (scroll < 0 || (scroll == 0 && mp_last != NULL))
++	    if (scroll <= 0)
+ 	    {
+ 		/* displayed the requested text, more prompt again */
+ 		screen_fill((int)Rows - 1, (int)Rows, 0,
+@@ -2848,6 +2850,15 @@
+     }
+     else if (State == HITRETURN || State == SETWSIZE)
+     {
++	if (msg_row == Rows - 1)
++	{
++	    /* Avoid drawing the "hit-enter" prompt below the previous one,
++	     * overwrite it.  Esp. useful when regaining focus and a
++	     * FocusGained autocmd exists but didn't draw anything. */
++	    msg_didout = FALSE;
++	    msg_col = 0;
++	    msg_clr_eos();
++	}
+ 	hit_return_msg();
+ 	msg_row = Rows - 1;
+     }
+@@ -3456,11 +3467,11 @@
+ 		    /* advance to next hotkey and set default hotkey */
+ #ifdef FEAT_MBYTE
+ 		    if (has_mbyte)
+-			hotkp += (*mb_ptr2len)(hotkp);
++			hotkp += STRLEN(hotkp);
+ 		    else
+ #endif
+ 			++hotkp;
+-		    (void)copy_char(r + 1, hotkp, TRUE);
++		    hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL;
+ 		    if (dfltbutton)
+ 			--dfltbutton;
+ 
+@@ -3493,7 +3504,7 @@
+ 			*msgp++ = (dfltbutton == 1) ? ']' : ')';
+ 
+ 			/* redefine hotkey */
+-			(void)copy_char(r, hotkp, TRUE);
++			hotkp[copy_char(r, hotkp, TRUE)] = NUL;
+ 		    }
+ 		}
+ 		else
+@@ -3519,8 +3530,6 @@
+ 	    *msgp++ = ':';
+ 	    *msgp++ = ' ';
+ 	    *msgp = NUL;
+-	    mb_ptr_adv(hotkp);
+-	    *hotkp = NUL;
+ 	}
+ 	else
+ 	{
+@@ -3555,8 +3564,9 @@
+ 	    msgp = confirm_msg + 1 + STRLEN(message);
+ 	    hotkp = hotk;
+ 
+-	    /* define first default hotkey */
+-	    (void)copy_char(buttons, hotkp, TRUE);
++	    /* Define first default hotkey.  Keep the hotkey string NUL
++	     * terminated to avoid reading past the end. */
++	    hotkp[copy_char(buttons, hotkp, TRUE)] = NUL;
+ 
+ 	    /* Remember where the choices start, displaying starts here when
+ 	     * "hotkp" typed at the more prompt. */
+diff -Naur vim71.orig/src/misc1.c vim71/src/misc1.c
+--- vim71.orig/src/misc1.c	2007-05-07 19:49:03.000000000 +0000
++++ vim71/src/misc1.c	2007-12-08 20:34:52.000000000 +0000
+@@ -90,7 +90,7 @@
+  */
+     int
+ set_indent(size, flags)
+-    int		size;
++    int		size;		    /* measured in spaces */
+     int		flags;
+ {
+     char_u	*p;
+@@ -98,12 +98,14 @@
+     char_u	*oldline;
+     char_u	*s;
+     int		todo;
+-    int		ind_len;
++    int		ind_len;	    /* measured in characters */
+     int		line_len;
+     int		doit = FALSE;
+-    int		ind_done;
++    int		ind_done = 0;	    /* measured in spaces */
+     int		tab_pad;
+     int		retval = FALSE;
++    int		orig_char_len = -1; /* number of initial whitespace chars when
++				       'et' and 'pi' are both set */
+ 
+     /*
+      * First check if there is anything to do and compute the number of
+@@ -116,8 +118,10 @@
+     /* Calculate the buffer size for the new indent, and check to see if it
+      * isn't already set */
+ 
+-    /* if 'expandtab' isn't set: use TABs */
+-    if (!curbuf->b_p_et)
++    /* if 'expandtab' isn't set: use TABs; if both 'expandtab' and
++     * 'preserveindent' are set count the number of characters at the
++     * beginning of the line to be copied */
++    if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi))
+     {
+ 	/* If 'preserveindent' is set then reuse as much as possible of
+ 	 * the existing indent structure for the new indent */
+@@ -148,9 +152,14 @@
+ 		++p;
+ 	    }
+ 
++	    /* Set initial number of whitespace chars to copy if we are
++	     * preserving indent but expandtab is set */
++	    if (curbuf->b_p_et)
++		orig_char_len = ind_len;
++
+ 	    /* Fill to next tabstop with a tab, if possible */
+ 	    tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+-	    if (todo >= tab_pad)
++	    if (todo >= tab_pad && orig_char_len == -1)
+ 	    {
+ 		doit = TRUE;
+ 		todo -= tab_pad;
+@@ -193,13 +202,42 @@
+     else
+ 	p = skipwhite(p);
+     line_len = (int)STRLEN(p) + 1;
+-    newline = alloc(ind_len + line_len);
+-    if (newline == NULL)
+-	return FALSE;
++
++    /* If 'preserveindent' and 'expandtab' are both set keep the original
++     * characters and allocate accordingly.  We will fill the rest with spaces
++     * after the if (!curbuf->b_p_et) below. */
++    if (orig_char_len != -1)
++    {
++	newline = alloc(orig_char_len + size - ind_done + line_len);
++	if (newline == NULL)
++	    return FALSE;
++	todo = size - ind_done;
++	ind_len = orig_char_len + todo;    /* Set total length of indent in
++					    * characters, which may have been
++					    * undercounted until now  */
++	p = oldline;
++	s = newline;
++	while (orig_char_len > 0)
++	{
++	    *s++ = *p++;
++	    orig_char_len--;
++	}
++	/* Skip over any additional white space (useful when newindent is less
++	 * than old) */
++	while (vim_iswhite(*p))
++	    (void)*p++;
++
++    }
++    else
++    {
++	todo = size;
++	newline = alloc(ind_len + line_len);
++	if (newline == NULL)
++	    return FALSE;
++	s = newline;
++    }
+ 
+     /* Put the characters in the new line. */
+-    s = newline;
+-    todo = size;
+     /* if 'expandtab' isn't set: use TABs */
+     if (!curbuf->b_p_et)
+     {
+@@ -1320,8 +1358,8 @@
+ 	    newindent += (int)curbuf->b_p_sw;
+ 	}
+ #endif
+-	/* Copy the indent only if expand tab is disabled */
+-	if (curbuf->b_p_ci && !curbuf->b_p_et)
++	/* Copy the indent */
++	if (curbuf->b_p_ci)
+ 	{
+ 	    (void)copy_indent(newindent, saved_line);
+ 
+@@ -3468,9 +3506,38 @@
+ #endif
+ 
+ /*
++ * Call expand_env() and store the result in an allocated string.
++ * This is not very memory efficient, this expects the result to be freed
++ * again soon.
++ */
++    char_u *
++expand_env_save(src)
++    char_u	*src;
++{
++    return expand_env_save_opt(src, FALSE);
++}
++
++/*
++ * Idem, but when "one" is TRUE handle the string as one file name, only
++ * expand "~" at the start.
++ */
++    char_u *
++expand_env_save_opt(src, one)
++    char_u	*src;
++    int		one;
++{
++    char_u	*p;
++
++    p = alloc(MAXPATHL);
++    if (p != NULL)
++	expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL);
++    return p;
++}
++
++/*
+  * Expand environment variable with path name.
+  * "~/" is also expanded, using $HOME.	For Unix "~user/" is expanded.
+- * Skips over "\ ", "\~" and "\$".
++ * Skips over "\ ", "\~" and "\$" (not for Win32 though).
+  * If anything fails no expansion is done and dst equals src.
+  */
+     void
+@@ -3479,15 +3546,16 @@
+     char_u	*dst;		/* where to put the result */
+     int		dstlen;		/* maximum length of the result */
+ {
+-    expand_env_esc(src, dst, dstlen, FALSE, NULL);
++    expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL);
+ }
+ 
+     void
+-expand_env_esc(srcp, dst, dstlen, esc, startstr)
++expand_env_esc(srcp, dst, dstlen, esc, one, startstr)
+     char_u	*srcp;		/* input string e.g. "$HOME/vim.hlp" */
+     char_u	*dst;		/* where to put the result */
+     int		dstlen;		/* maximum length of the result */
+     int		esc;		/* escape spaces in expanded variables */
++    int		one;		/* "srcp" is one file name */
+     char_u	*startstr;	/* start again after this (can be NULL) */
+ {
+     char_u	*src;
+@@ -3728,6 +3796,8 @@
+ 	{
+ 	    /*
+ 	     * Recognize the start of a new name, for '~'.
++	     * Don't do this when "one" is TRUE, to avoid expanding "~" in
++	     * ":edit foo ~ foo".
+ 	     */
+ 	    at_start = FALSE;
+ 	    if (src[0] == '\\' && src[1] != NUL)
+@@ -3735,7 +3805,7 @@
+ 		*dst++ = *src++;
+ 		--dstlen;
+ 	    }
+-	    else if (src[0] == ' ' || src[0] == ',')
++	    else if ((src[0] == ' ' || src[0] == ',') && !one)
+ 		at_start = TRUE;
+ 	    *dst++ = *src++;
+ 	    --dstlen;
+@@ -4032,23 +4102,6 @@
+ }
+ 
+ /*
+- * Call expand_env() and store the result in an allocated string.
+- * This is not very memory efficient, this expects the result to be freed
+- * again soon.
+- */
+-    char_u *
+-expand_env_save(src)
+-    char_u	*src;
+-{
+-    char_u	*p;
+-
+-    p = alloc(MAXPATHL);
+-    if (p != NULL)
+-	expand_env(src, p, MAXPATHL);
+-    return p;
+-}
+-
+-/*
+  * Our portable version of setenv.
+  */
+     void
+@@ -4786,7 +4839,7 @@
+ static int	cin_iswhileofdo __ARGS((char_u *, linenr_T, int));
+ static int	cin_iswhileofdo_end __ARGS((int terminated, int	ind_maxparen, int ind_maxcomment));
+ static int	cin_isbreak __ARGS((char_u *));
+-static int	cin_is_cpp_baseclass __ARGS((char_u *line, colnr_T *col));
++static int	cin_is_cpp_baseclass __ARGS((colnr_T *col));
+ static int	get_baseclass_amount __ARGS((int col, int ind_maxparen, int ind_maxcomment, int ind_cpp_baseclass));
+ static int	cin_ends_in __ARGS((char_u *, char_u *, char_u *));
+ static int	cin_skip2pos __ARGS((pos_T *trypos));
+@@ -5551,13 +5604,13 @@
+  * This is a lot of guessing.  Watch out for "cond ? func() : foo".
+  */
+     static int
+-cin_is_cpp_baseclass(line, col)
+-    char_u	*line;
++cin_is_cpp_baseclass(col)
+     colnr_T	*col;	    /* return: column to align with */
+ {
+     char_u	*s;
+     int		class_or_struct, lookfor_ctor_init, cpp_base_class;
+     linenr_T	lnum = curwin->w_cursor.lnum;
++    char_u	*line = ml_get_curline();
+ 
+     *col = 0;
+ 
+@@ -5585,7 +5638,8 @@
+      */
+     while (lnum > 1)
+     {
+-	s = skipwhite(ml_get(lnum - 1));
++	line = ml_get(lnum - 1);
++	s = skipwhite(line);
+ 	if (*s == '#' || *s == NUL)
+ 	    break;
+ 	while (*s != NUL)
+@@ -5602,7 +5656,8 @@
+ 	--lnum;
+     }
+ 
+-    s = cin_skipcomment(ml_get(lnum));
++    line = ml_get(lnum);
++    s = cin_skipcomment(line);
+     for (;;)
+     {
+ 	if (*s == NUL)
+@@ -5610,7 +5665,10 @@
+ 	    if (lnum == curwin->w_cursor.lnum)
+ 		break;
+ 	    /* Continue in the cursor line. */
+-	    s = cin_skipcomment(ml_get(++lnum));
++	    line = ml_get(++lnum);
++	    s = cin_skipcomment(line);
++	    if (*s == NUL)
++		continue;
+ 	}
+ 
+ 	if (s[0] == ':')
+@@ -7079,7 +7137,7 @@
+ 		n = FALSE;
+ 		if (lookfor != LOOKFOR_TERM && ind_cpp_baseclass > 0)
+ 		{
+-		    n = cin_is_cpp_baseclass(l, &col);
++		    n = cin_is_cpp_baseclass(&col);
+ 		    l = ml_get_curline();
+ 		}
+ 		if (n)
+@@ -7670,7 +7728,7 @@
+ 		n = FALSE;
+ 		if (ind_cpp_baseclass != 0 && theline[0] != '{')
+ 		{
+-		    n = cin_is_cpp_baseclass(l, &col);
++		    n = cin_is_cpp_baseclass(&col);
+ 		    l = ml_get_curline();
+ 		}
+ 		if (n)
+@@ -8596,7 +8654,7 @@
+     for (p = buf + wildoff; p < s; ++p)
+ 	if (rem_backslash(p))
+ 	{
+-	    STRCPY(p, p + 1);
++	    mch_memmove(p, p + 1, STRLEN(p));
+ 	    --e;
+ 	    --s;
+ 	}
+@@ -8897,7 +8955,7 @@
+     for (p = buf + wildoff; p < s; ++p)
+ 	if (rem_backslash(p))
+ 	{
+-	    STRCPY(p, p + 1);
++	    mch_memmove(p, p + 1, STRLEN(p));
+ 	    --e;
+ 	    --s;
+ 	}
+@@ -9096,7 +9154,7 @@
+ 	     */
+ 	    if (vim_strpbrk(p, (char_u *)"$~") != NULL)
+ 	    {
+-		p = expand_env_save(p);
++		p = expand_env_save_opt(p, TRUE);
+ 		if (p == NULL)
+ 		    p = pat[i];
+ #ifdef UNIX
+diff -Naur vim71.orig/src/misc2.c vim71/src/misc2.c
+--- vim71.orig/src/misc2.c	2007-05-07 19:49:26.000000000 +0000
++++ vim71/src/misc2.c	2007-12-08 20:34:53.000000000 +0000
+@@ -964,7 +964,6 @@
+ {
+     buf_T	*buf, *nextbuf;
+     static int	entered = FALSE;
+-    win_T	*win;
+ 
+     /* When we cause a crash here it is caught and Vim tries to exit cleanly.
+      * Don't try freeing everything again. */
+@@ -972,15 +971,17 @@
+ 	return;
+     entered = TRUE;
+ 
+-    ++autocmd_block;	    /* don't want to trigger autocommands here */
++# ifdef FEAT_AUTOCMD
++    block_autocmds();	    /* don't want to trigger autocommands here */
++# endif
+ 
+-#ifdef FEAT_WINDOWS
++# ifdef FEAT_WINDOWS
+     /* close all tabs and windows */
+     if (first_tabpage->tp_next != NULL)
+ 	do_cmdline_cmd((char_u *)"tabonly!");
+     if (firstwin != lastwin)
+ 	do_cmdline_cmd((char_u *)"only!");
+-#endif
++# endif
+ 
+ # if defined(FEAT_SPELL)
+     /* Free all spell info. */
+@@ -1031,27 +1032,41 @@
+     free_regexp_stuff();
+     free_tag_stuff();
+     free_cd_dir();
++# ifdef FEAT_EVAL
+     set_expr_line(NULL);
++# endif
++# ifdef FEAT_DIFF
+     diff_clear(curtab);
++# endif
+     clear_sb_text();	      /* free any scrollback text */
+ 
+     /* Free some global vars. */
+     vim_free(username);
++# ifdef FEAT_CLIPBOARD
+     vim_free(clip_exclude_prog);
++# endif
+     vim_free(last_cmdline);
++# ifdef FEAT_CMDHIST
+     vim_free(new_last_cmdline);
++# endif
+     set_keep_msg(NULL, 0);
+     vim_free(ff_expand_buffer);
+ 
+     /* Clear cmdline history. */
+     p_hi = 0;
++# ifdef FEAT_CMDHIST
+     init_history();
++# endif
+ 
+ #ifdef FEAT_QUICKFIX
+-    qf_free_all(NULL);
+-    /* Free all location lists */
+-    FOR_ALL_WINDOWS(win)
+-	qf_free_all(win);
++    {
++	win_T	*win;
++
++	qf_free_all(NULL);
++	/* Free all location lists */
++	FOR_ALL_WINDOWS(win)
++	    qf_free_all(win);
++    }
+ #endif
+ 
+     /* Close all script inputs. */
+@@ -5922,7 +5937,11 @@
+ {
+     if (emsg_not_now())
+ 	return TRUE;		/* no error messages at the moment */
++#ifdef HAVE_STDARG_H
++    vim_snprintf((char *)IObuff, IOSIZE, (char *)s, a1, a2);
++#else
+     vim_snprintf((char *)IObuff, IOSIZE, (char *)s, (long_u)a1, (long_u)a2);
++#endif
+     return emsg(IObuff);
+ }
+ 
+diff -Naur vim71.orig/src/normal.c vim71/src/normal.c
+--- vim71.orig/src/normal.c	2007-05-07 19:34:39.000000000 +0000
++++ vim71/src/normal.c	2007-12-08 20:34:53.000000000 +0000
+@@ -690,13 +690,20 @@
+ 		ca.count0 = ca.count0 * 10 + (c - '0');
+ 	    if (ca.count0 < 0)	    /* got too large! */
+ 		ca.count0 = 999999999L;
++#ifdef FEAT_EVAL
++	    /* Set v:count here, when called from main() and not a stuffed
++	     * command, so that v:count can be used in an expression mapping
++	     * right after the count. */
++	    if (toplevel && stuff_empty())
++		set_vcount(ca.count0, ca.count0 == 0 ? 1 : ca.count0);
++#endif
+ 	    if (ctrl_w)
+ 	    {
+ 		++no_mapping;
+ 		++allow_keys;		/* no mapping for nchar, but keys */
+ 	    }
+ 	    ++no_zero_mapping;		/* don't map zero here */
+-	    c = safe_vgetc();
++	    c = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 	    LANGMAP_ADJUST(c, TRUE);
+ #endif
+@@ -721,7 +728,7 @@
+ 	    ca.count0 = 0;
+ 	    ++no_mapping;
+ 	    ++allow_keys;		/* no mapping for nchar, but keys */
+-	    c = safe_vgetc();		/* get next character */
++	    c = plain_vgetc();		/* get next character */
+ #ifdef FEAT_LANGMAP
+ 	    LANGMAP_ADJUST(c, TRUE);
+ #endif
+@@ -889,13 +896,18 @@
+ 
+ 	++no_mapping;
+ 	++allow_keys;		/* no mapping for nchar, but allow key codes */
++#ifdef FEAT_AUTOCMD
++	/* Don't generate a CursorHold event here, most commands can't handle
++	 * it, e.g., nv_replace(), nv_csearch(). */
++	did_cursorhold = TRUE;
++#endif
+ 	if (ca.cmdchar == 'g')
+ 	{
+ 	    /*
+ 	     * For 'g' get the next character now, so that we can check for
+ 	     * "gr", "g'" and "g`".
+ 	     */
+-	    ca.nchar = safe_vgetc();
++	    ca.nchar = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 	    LANGMAP_ADJUST(ca.nchar, TRUE);
+ #endif
+@@ -952,7 +964,7 @@
+ 		im_set_active(TRUE);
+ #endif
+ 
+-	    *cp = safe_vgetc();
++	    *cp = plain_vgetc();
+ 
+ 	    if (langmap_active)
+ 	    {
+@@ -1040,7 +1052,7 @@
+ 		}
+ 		if (c > 0)
+ 		{
+-		    c = safe_vgetc();
++		    c = plain_vgetc();
+ 		    if (c != Ctrl_N && c != Ctrl_G)
+ 			vungetc(c);
+ 		    else
+@@ -1059,7 +1071,7 @@
+ 	    while (enc_utf8 && lang && (c = vpeekc()) > 0
+ 				 && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1))
+ 	    {
+-		c = safe_vgetc();
++		c = plain_vgetc();
+ 		if (!utf_iscomposing(c))
+ 		{
+ 		    vungetc(c);		/* it wasn't, put it back */
+@@ -3755,7 +3767,8 @@
+     extra_len = (int)STRLEN(p);
+     overflow = old_len + extra_len - SHOWCMD_COLS;
+     if (overflow > 0)
+-	STRCPY(showcmd_buf, showcmd_buf + overflow);
++	mch_memmove(showcmd_buf, showcmd_buf + overflow,
++						      old_len - overflow + 1);
+     STRCAT(showcmd_buf, p);
+ 
+     if (char_avail())
+@@ -4558,7 +4571,7 @@
+ #endif
+ 	    ++no_mapping;
+ 	    ++allow_keys;   /* no mapping for nchar, but allow key codes */
+-	    nchar = safe_vgetc();
++	    nchar = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 	    LANGMAP_ADJUST(nchar, TRUE);
+ #endif
+@@ -4916,7 +4929,7 @@
+     case 'u':	/* "zug" and "zuw": undo "zg" and "zw" */
+ 		++no_mapping;
+ 		++allow_keys;   /* no mapping for nchar, but allow key codes */
+-		nchar = safe_vgetc();
++		nchar = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 		LANGMAP_ADJUST(nchar, TRUE);
+ #endif
+@@ -6379,7 +6392,7 @@
+      */
+     else if (cap->nchar == 'p' || cap->nchar == 'P')
+     {
+-	if (!checkclearopq(cap->oap))
++	if (!checkclearop(cap->oap))
+ 	{
+ 	    prep_redo_cmd(cap);
+ 	    do_put(cap->oap->regname,
+@@ -6662,6 +6675,13 @@
+     else
+ 	had_ctrl_v = NUL;
+ 
++    /* Abort if the character is a special key. */
++    if (IS_SPECIAL(cap->nchar))
++    {
++	clearopbeep(cap->oap);
++	return;
++    }
++
+ #ifdef FEAT_VISUAL
+     /* Visual mode "r" */
+     if (VIsual_active)
+@@ -6688,11 +6708,9 @@
+     }
+ #endif
+ 
+-    /*
+-     * Check for a special key or not enough characters to replace.
+-     */
++    /* Abort if not enough characters to replace. */
+     ptr = ml_get_cursor();
+-    if (IS_SPECIAL(cap->nchar) || STRLEN(ptr) < (unsigned)cap->count1
++    if (STRLEN(ptr) < (unsigned)cap->count1
+ #ifdef FEAT_MBYTE
+ 	    || (has_mbyte && mb_charlen(ptr) < cap->count1)
+ #endif
+@@ -8353,7 +8371,7 @@
+ 	n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP);
+ 
+     /* Don't leave the cursor on the NUL past a line */
+-    if (curwin->w_cursor.col && gchar_cursor() == NUL)
++    if (n != FAIL && curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
+     {
+ 	--curwin->w_cursor.col;
+ 	cap->oap->inclusive = TRUE;
+diff -Naur vim71.orig/src/ops.c vim71/src/ops.c
+--- vim71.orig/src/ops.c	2007-05-07 19:33:47.000000000 +0000
++++ vim71/src/ops.c	2007-12-08 20:34:53.000000000 +0000
+@@ -927,15 +927,16 @@
+     int		name;
+     int		copy;	/* make a copy, if FALSE make register empty. */
+ {
+-    static struct yankreg	*reg;
+-    int				i;
++    struct yankreg	*reg;
++    int			i;
+ 
+ #ifdef FEAT_CLIPBOARD
+     /* When Visual area changed, may have to update selection.  Obtain the
+      * selection too. */
+-    if (name == '*' && clip_star.available && clip_isautosel())
++    if (name == '*' && clip_star.available)
+     {
+-	clip_update_selection();
++	if (clip_isautosel())
++	    clip_update_selection();
+ 	may_get_selection(name);
+     }
+ #endif
+@@ -966,7 +967,7 @@
+ }
+ 
+ /*
+- * Put "reg" into register "name".  Free any previous contents.
++ * Put "reg" into register "name".  Free any previous contents and "reg".
+  */
+     void
+ put_register(name, reg)
+@@ -976,6 +977,7 @@
+     get_yank_register(name, 0);
+     free_yank_all();
+     *y_current = *(struct yankreg *)reg;
++    vim_free(reg);
+ 
+ # ifdef FEAT_CLIPBOARD
+     /* Send text written to clipboard register to the clipboard. */
+@@ -2477,7 +2479,7 @@
+ 
+ 	/*
+ 	 * Spaces and tabs in the indent may have changed to other spaces and
+-	 * tabs.  Get the starting column again and correct the lenght.
++	 * tabs.  Get the starting column again and correct the length.
+ 	 * Don't do this when "$" used, end-of-line will have changed.
+ 	 */
+ 	block_prep(oap, &bd2, oap->start.lnum, TRUE);
+@@ -2534,7 +2536,9 @@
+ #ifdef FEAT_VISUALEXTRA
+     long		offset;
+     linenr_T		linenr;
+-    long		ins_len, pre_textlen = 0;
++    long		ins_len;
++    long		pre_textlen = 0;
++    long		pre_indent = 0;
+     char_u		*firstline;
+     char_u		*ins_text, *newp, *oldp;
+     struct block_def	bd;
+@@ -2579,7 +2583,9 @@
+ 						    || gchar_cursor() == NUL))
+ 	    coladvance_force(getviscol());
+ # endif
+-	pre_textlen = (long)STRLEN(ml_get(oap->start.lnum));
++	firstline = ml_get(oap->start.lnum);
++	pre_textlen = (long)STRLEN(firstline);
++	pre_indent = (long)(skipwhite(firstline) - firstline);
+ 	bd.textcol = curwin->w_cursor.col;
+     }
+ #endif
+@@ -2598,13 +2604,22 @@
+      */
+     if (oap->block_mode && oap->start.lnum != oap->end.lnum)
+     {
++	/* Auto-indenting may have changed the indent.  If the cursor was past
++	 * the indent, exclude that indent change from the inserted text. */
+ 	firstline = ml_get(oap->start.lnum);
+-	/*
+-	 * Subsequent calls to ml_get() flush the firstline data - take a
+-	 * copy of the required bit.
+-	 */
+-	if ((ins_len = (long)STRLEN(firstline) - pre_textlen) > 0)
++	if (bd.textcol > (colnr_T)pre_indent)
++	{
++	    long new_indent = (long)(skipwhite(firstline) - firstline);
++
++	    pre_textlen += new_indent - pre_indent;
++	    bd.textcol += new_indent - pre_indent;
++	}
++
++	ins_len = (long)STRLEN(firstline) - pre_textlen;
++	if (ins_len > 0)
+ 	{
++	    /* Subsequent calls to ml_get() flush the firstline data - take a
++	     * copy of the inserted text.  */
+ 	    if ((ins_text = alloc_check((unsigned)(ins_len + 1))) != NULL)
+ 	    {
+ 		vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len);
+@@ -3404,7 +3419,9 @@
+ 
+ #ifdef FEAT_VIRTUALEDIT
+ 	col += curwin->w_cursor.coladd;
+-	if (ve_flags == VE_ALL && curwin->w_cursor.coladd > 0)
++	if (ve_flags == VE_ALL
++		&& (curwin->w_cursor.coladd > 0
++		    || endcol2 == curwin->w_cursor.col))
+ 	{
+ 	    if (dir == FORWARD && c == NUL)
+ 		++col;
+diff -Naur vim71.orig/src/option.c vim71/src/option.c
+--- vim71.orig/src/option.c	2007-05-01 11:26:10.000000000 +0000
++++ vim71/src/option.c	2007-12-08 20:34:53.000000000 +0000
+@@ -427,6 +427,8 @@
+ #define P_NOGLOB       0x100000L/* do not use local value for global vimrc */
+ #define P_NFNAME       0x200000L/* only normal file name chars allowed */
+ #define P_INSECURE     0x400000L/* option was set from a modeline */
++#define P_PRI_MKRC     0x800000L/* priority for :mkvimrc (setting option has
++				   side effects) */
+ 
+ #define ISK_LATIN1  (char_u *)"@,48-57,_,192-255"
+ 
+@@ -773,6 +775,8 @@
+ 			    {(char_u *)0L, (char_u *)0L}
+ #endif
+ 			    },
++			    /* P_PRI_MKRC isn't needed here, optval_default()
++			     * always returns TRUE for 'compatible' */
+     {"compatible",  "cp",   P_BOOL|P_RALL,
+ 			    (char_u *)&p_cp, PV_NONE,
+ 			    {(char_u *)TRUE, (char_u *)FALSE}},
+@@ -1515,7 +1519,7 @@
+ 			    {(char_u *)0L, (char_u *)0L}
+ #endif
+ 			    },
+-    {"keymap",	    "kmp",  P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME,
++    {"keymap",	    "kmp",  P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME|P_PRI_MKRC,
+ #ifdef FEAT_KEYMAP
+ 			    (char_u *)&p_keymap, PV_KMAP,
+ 			    {(char_u *)"", (char_u *)0L}
+@@ -1836,7 +1840,7 @@
+     {"paragraphs",  "para", P_STRING|P_VI_DEF,
+ 			    (char_u *)&p_para, PV_NONE,
+ 			    {(char_u *)"IPLPPPQPP LIpplpipbp", (char_u *)0L}},
+-    {"paste",	    NULL,   P_BOOL|P_VI_DEF,
++    {"paste",	    NULL,   P_BOOL|P_VI_DEF|P_PRI_MKRC,
+ 			    (char_u *)&p_paste, PV_NONE,
+ 			    {(char_u *)FALSE, (char_u *)0L}},
+     {"pastetoggle", "pt",   P_STRING|P_VI_DEF,
+@@ -4628,7 +4632,7 @@
+ 				    if ((!(flags & P_COMMA) || *s != ',')
+ 					    && vim_strchr(s + 1, *s) != NULL)
+ 				    {
+-					STRCPY(s, s + 1);
++					mch_memmove(s, s + 1, STRLEN(s));
+ 					--s;
+ 				    }
+ 			    }
+@@ -4992,7 +4996,7 @@
+      * For 'spellsuggest' expand after "file:".
+      */
+     expand_env_esc(val, NameBuff, MAXPATHL,
+-	    (char_u **)options[opt_idx].var == &p_tags,
++	    (char_u **)options[opt_idx].var == &p_tags, FALSE,
+ #ifdef FEAT_SPELL
+ 	    (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" :
+ #endif
+@@ -6348,7 +6352,7 @@
+ 		errmsg = check_stl_option(p_ruf);
+ 	}
+ 	/* check 'statusline' only if it doesn't start with "%!" */
+-	else if (varp != &p_stl || s[0] != '%' || s[1] != '!')
++	else if (varp == &p_ruf || s[0] != '%' || s[1] != '!')
+ 	    errmsg = check_stl_option(s);
+ 	if (varp == &p_ruf && errmsg == NULL)
+ 	    comp_col();
+@@ -7118,6 +7122,11 @@
+     /* when 'endofline' is changed, redraw the window title */
+     else if ((int *)varp == &curbuf->b_p_eol)
+ 	need_maketitle = TRUE;
++#ifdef FEAT_MBYTE
++    /* when 'bomb' is changed, redraw the window title */
++    else if ((int *)varp == &curbuf->b_p_bomb)
++	need_maketitle = TRUE;
++#endif
+ #endif
+ 
+     /* when 'bin' is set also set some other options */
+@@ -7815,6 +7824,8 @@
+ 	    errmsg = e_positive;
+ 	    p_ch = 1;
+ 	}
++	if (p_ch > Rows - min_rows() + 1)
++	    p_ch = Rows - min_rows() + 1;
+ 
+ 	/* Only compute the new window layout when startup has been
+ 	 * completed. Otherwise the frame sizes may be wrong. */
+@@ -8219,6 +8230,25 @@
+ 	    varp = get_varp(&options[opt_idx]);
+ 	    if (varp != NULL)	/* hidden option is not changed */
+ 	    {
++		if (number == 0 && string != NULL)
++		{
++		    int index;
++
++		    /* Either we are given a string or we are setting option
++		     * to zero. */
++		    for (index = 0; string[index] == '0'; ++index)
++			;
++		    if (string[index] != NUL || index == 0)
++		    {
++			/* There's another character after zeros or the string
++			 * is empty.  In both cases, we are trying to set a
++			 * num option using a string. */
++			EMSG3(_("E521: Number required: &%s = '%s'"),
++								name, string);
++			return;     /* do nothing as we hit an error */
++
++		    }
++		}
+ 		if (flags & P_NUM)
+ 		    (void)set_num_option(opt_idx, varp, number,
+ 							  NULL, 0, opt_flags);
+@@ -8511,13 +8541,20 @@
+     char_u		*varp_local = NULL;	/* fresh value */
+     char		*cmd;
+     int			round;
++    int			pri;
+ 
+     /*
+      * The options that don't have a default (terminal name, columns, lines)
+      * are never written.  Terminal options are also not written.
++     * Do the loop over "options[]" twice: once for options with the
++     * P_PRI_MKRC flag and once without.
+      */
+-    for (p = &options[0]; !istermoption(p); p++)
+-	if (!(p->flags & P_NO_MKRC) && !istermoption(p))
++    for (pri = 1; pri >= 0; --pri)
++    {
++      for (p = &options[0]; !istermoption(p); p++)
++	if (!(p->flags & P_NO_MKRC)
++		&& !istermoption(p)
++		&& ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0)))
+ 	{
+ 	    /* skip global option when only doing locals */
+ 	    if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL))
+@@ -8613,6 +8650,7 @@
+ 		}
+ 	    }
+ 	}
++    }
+     return OK;
+ }
+ 
+@@ -8715,6 +8753,8 @@
+     char	*name;
+     int		value;
+ {
++    if (value < 0)	/* global/local option using global value */
++	return OK;
+     if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0
+ 	    || put_eol(fd) < 0)
+ 	return FAIL;
+@@ -10585,6 +10625,8 @@
+     buf->b_start_ffc = *buf->b_p_ff;
+     buf->b_start_eol = buf->b_p_eol;
+ #ifdef FEAT_MBYTE
++    buf->b_start_bomb = buf->b_p_bomb;
++
+     /* Only use free/alloc when necessary, they take time. */
+     if (buf->b_start_fenc == NULL
+ 			     || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0)
+@@ -10598,13 +10640,17 @@
+ /*
+  * Return TRUE if 'fileformat' and/or 'fileencoding' has a different value
+  * from when editing started (save_file_ff() called).
+- * Also when 'endofline' was changed and 'binary' is set.
++ * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was
++ * changed and 'binary' is not set.
+  * Don't consider a new, empty buffer to be changed.
+  */
+     int
+ file_ff_differs(buf)
+     buf_T	*buf;
+ {
++    /* In a buffer that was never loaded the options are not valid. */
++    if (buf->b_flags & BF_NEVERLOADED)
++	return FALSE;
+     if ((buf->b_flags & BF_NEW)
+ 	    && buf->b_ml.ml_line_count == 1
+ 	    && *ml_get_buf(buf, (linenr_T)1, FALSE) == NUL)
+@@ -10614,6 +10660,8 @@
+     if (buf->b_p_bin && buf->b_start_eol != buf->b_p_eol)
+ 	return TRUE;
+ #ifdef FEAT_MBYTE
++    if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb)
++	return TRUE;
+     if (buf->b_start_fenc == NULL)
+ 	return (*buf->b_p_fenc != NUL);
+     return (STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0);
+diff -Naur vim71.orig/src/os_unix.c vim71/src/os_unix.c
+--- vim71.orig/src/os_unix.c	2007-05-09 19:41:58.000000000 +0000
++++ vim71/src/os_unix.c	2007-12-08 20:34:53.000000000 +0000
+@@ -310,7 +310,7 @@
+ }
+ 
+ /*
+- * mch_inchar(): low level input funcion.
++ * mch_inchar(): low level input function.
+  * Get a characters from the keyboard.
+  * Return the number of characters that are available.
+  * If wtime == 0 do not wait for characters.
+@@ -753,7 +753,8 @@
+     if (signal_stack != NULL)
+     {
+ # ifdef HAVE_SIGALTSTACK
+-#  ifdef __APPLE__
++#  if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
++		|| MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
+ 	/* missing prototype.  Adding it to osdef?.h.in doesn't work, because
+ 	 * "struct sigaltstack" needs to be declared. */
+ 	extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
+@@ -1566,18 +1567,19 @@
+ #ifdef FEAT_XCLIPBOARD
+     if (xterm_dpy != NULL && x11_window != 0)
+     {
+-	/* Checked it already. */
+-	if (x11_display_from == XD_XTERM)
+-	    return OK;
+-
+-	/*
+-	 * If the X11 display was opened here before, for the window where Vim
+-	 * was started, close that one now to avoid a memory leak.
+-	 */
+-	if (x11_display_from == XD_HERE && x11_display != NULL)
+-	    XCloseDisplay(x11_display);
+-	x11_display = xterm_dpy;
+-	x11_display_from = XD_XTERM;
++	/* We may have checked it already, but Gnome terminal can move us to
++	 * another window, so we need to check every time. */
++	if (x11_display_from != XD_XTERM)
++	{
++	    /*
++	     * If the X11 display was opened here before, for the window where
++	     * Vim was started, close that one now to avoid a memory leak.
++	     */
++	    if (x11_display_from == XD_HERE && x11_display != NULL)
++		XCloseDisplay(x11_display);
++	    x11_display = xterm_dpy;
++	    x11_display_from = XD_XTERM;
++	}
+ 	if (test_x11_window(x11_display) == FAIL)
+ 	{
+ 	    /* probably bad $WINDOWID */
+@@ -2420,7 +2422,7 @@
+ /*
+  * Set the case of the file name, if it already exists.  This will cause the
+  * file name to remain exactly the same.
+- * Only required for file systems where case is ingored and preserved.
++ * Only required for file systems where case is ignored and preserved.
+  */
+ /*ARGSUSED*/
+     void
+@@ -2499,7 +2501,13 @@
+     if (stat((char *)name, &statb))
+ #endif
+ 	return -1;
++#ifdef __INTERIX
++    /* The top bit makes the value negative, which means the file doesn't
++     * exist.  Remove the bit, we don't use it. */
++    return statb.st_mode & ~S_ADDACE;
++#else
+     return statb.st_mode;
++#endif
+ }
+ 
+ /*
+@@ -4646,7 +4654,7 @@
+ 	ret = poll(fds, nfd, towait);
+ # ifdef FEAT_MZSCHEME
+ 	if (ret == 0 && mzquantum_used)
+-	    /* MzThreads scheduling is required and timeout occured */
++	    /* MzThreads scheduling is required and timeout occurred */
+ 	    finished = FALSE;
+ # endif
+ 
+@@ -4794,7 +4802,7 @@
+ #endif
+ # ifdef FEAT_MZSCHEME
+ 	if (ret == 0 && mzquantum_used)
+-	    /* loop if MzThreads must be scheduled and timeout occured */
++	    /* loop if MzThreads must be scheduled and timeout occurred */
+ 	    finished = FALSE;
+ # endif
+ 
+@@ -5184,7 +5192,7 @@
+ 	{
+ 	    /* When using system() always add extra quotes, because the shell
+ 	     * is started twice.  Otherwise put a backslash before special
+-	     * characters, except insice ``. */
++	     * characters, except inside ``. */
+ #ifdef USE_SYSTEM
+ 	    STRCAT(command, " \"");
+ 	    STRCAT(command, pat[i]);
+@@ -5668,7 +5676,7 @@
+ 	    /* gpm library tries to handling TSTP causes
+ 	     * problems. Anyways, we close connection to Gpm whenever
+ 	     * we are going to suspend or starting an external process
+-	     * so we should'nt  have problem with this
++	     * so we shouldn't  have problem with this
+ 	     */
+ 	    signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+ 	    return 1; /* succeed */
+@@ -5682,7 +5690,7 @@
+ 
+ /*
+  * Closes connection to gpm
+- * returns non-zero if connection succesfully closed
++ * returns non-zero if connection successfully closed
+  */
+     static void
+ gpm_close()
+diff -Naur vim71.orig/src/os_unix.h vim71/src/os_unix.h
+--- vim71.orig/src/os_unix.h	2007-05-07 19:35:05.000000000 +0000
++++ vim71/src/os_unix.h	2007-12-08 20:34:50.000000000 +0000
+@@ -508,6 +508,9 @@
+ #if !defined(S_ISFIFO) && defined(S_IFIFO)
+ # define	S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+ #endif
++#if !defined(S_ISCHR) && defined(S_IFCHR)
++# define	S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
++#endif
+ 
+ /* Note: Some systems need both string.h and strings.h (Savage).  However,
+  * some systems can't handle both, only use string.h in that case. */
+diff -Naur vim71.orig/src/popupmnu.c vim71/src/popupmnu.c
+--- vim71.orig/src/popupmnu.c	2007-03-24 20:07:39.000000000 +0000
++++ vim71/src/popupmnu.c	2007-12-08 20:34:51.000000000 +0000
+@@ -75,7 +75,6 @@
+ 
+     row = curwin->w_cline_row + W_WINROW(curwin);
+     height = curwin->w_cline_height;
+-    col = curwin->w_wcol + W_WINCOL(curwin) - curwin->w_leftcol;
+ 
+     if (firstwin->w_p_pvw)
+ 	top_clear = firstwin->w_height;
+@@ -167,6 +166,15 @@
+     pum_base_width = max_width;
+     pum_kind_width = kind_width;
+ 
++    /* Calculate column */
++#ifdef FEAT_RIGHTLEFT
++    if (curwin->w_p_rl)
++	col = W_WINCOL(curwin) + W_WIDTH(curwin) - curwin->w_wcol -
++							curwin->w_leftcol - 1;
++    else
++#endif
++	col = W_WINCOL(curwin) + curwin->w_wcol - curwin->w_leftcol;
++
+     /* if there are more items than room we need a scrollbar */
+     if (pum_height < size)
+     {
+@@ -179,11 +187,23 @@
+     if (def_width < max_width)
+ 	def_width = max_width;
+ 
+-    if (col < Columns - PUM_DEF_WIDTH || col < Columns - max_width)
++    if (((col < Columns - PUM_DEF_WIDTH || col < Columns - max_width)
++#ifdef FEAT_RIGHTLEFT
++		&& !curwin->w_p_rl)
++	    || (curwin->w_p_rl && (col > PUM_DEF_WIDTH || col > max_width)
++#endif
++       ))
+     {
+ 	/* align pum column with "col" */
+ 	pum_col = col;
+-	pum_width = Columns - pum_col - pum_scrollbar;
++
++#ifdef FEAT_RIGHTLEFT
++	if (curwin->w_p_rl)
++	    pum_width = pum_col - pum_scrollbar + 1;
++	else
++#endif
++	    pum_width = Columns - pum_col - pum_scrollbar;
++
+ 	if (pum_width > max_width + kind_width + extra_width + 1
+ 						 && pum_width > PUM_DEF_WIDTH)
+ 	{
+@@ -195,14 +215,24 @@
+     else if (Columns < def_width)
+     {
+ 	/* not enough room, will use what we have */
+-	pum_col = 0;
++#ifdef FEAT_RIGHTLEFT
++	if (curwin->w_p_rl)
++	    pum_col = Columns - 1;
++	else
++#endif
++	    pum_col = 0;
+ 	pum_width = Columns - 1;
+     }
+     else
+     {
+ 	if (max_width > PUM_DEF_WIDTH)
+ 	    max_width = PUM_DEF_WIDTH;	/* truncate */
+-	pum_col = Columns - max_width;
++#ifdef FEAT_RIGHTLEFT
++	if (curwin->w_p_rl)
++	    pum_col = max_width - 1;
++	else
++#endif
++	    pum_col = Columns - max_width;
+ 	pum_width = max_width - pum_scrollbar;
+     }
+ 
+@@ -255,8 +285,16 @@
+ 	attr = (idx == pum_selected) ? attr_select : attr_norm;
+ 
+ 	/* prepend a space if there is room */
+-	if (pum_col > 0)
+-	    screen_putchar(' ', row, pum_col - 1, attr);
++#ifdef FEAT_RIGHTLEFT
++	if (curwin->w_p_rl)
++	{
++	    if (pum_col < W_WINCOL(curwin) + W_WIDTH(curwin) - 1)
++		screen_putchar(' ', row, pum_col + 1, attr);
++	}
++	else
++#endif
++	    if (pum_col > 0)
++		screen_putchar(' ', row, pum_col - 1, attr);
+ 
+ 	/* Display each entry, use two spaces for a Tab.
+ 	 * Do this 3 times: For the main text, kind and extra info */
+@@ -282,26 +320,67 @@
+ 		    {
+ 			/* Display the text that fits or comes before a Tab.
+ 			 * First convert it to printable characters. */
+-			char_u *st;
+-			int  saved = *p;
++			char_u	*st;
++			int	saved = *p;
+ 
+ 			*p = NUL;
+ 			st = transstr(s);
+ 			*p = saved;
+-			if (st != NULL)
++#ifdef FEAT_RIGHTLEFT
++			if (curwin->w_p_rl)
+ 			{
+-			    screen_puts_len(st, (int)STRLEN(st), row, col,
++			    if (st != NULL)
++			    {
++				char_u	*rt = reverse_text(st);
++				char_u	*rt_saved = rt;
++				int	len, j;
++
++				if (rt != NULL)
++				{
++				    len = STRLEN(rt);
++				    if (len > pum_width)
++				    {
++					for (j = pum_width; j < len; ++j)
++					    mb_ptr_adv(rt);
++					len = pum_width;
++				    }
++				    screen_puts_len(rt, len, row,
++							col - len + 1, attr);
++				    vim_free(rt_saved);
++				}
++				vim_free(st);
++			    }
++			    col -= width;
++			}
++			else
++#endif
++			{
++			    if (st != NULL)
++			    {
++				screen_puts_len(st, (int)STRLEN(st), row, col,
+ 									attr);
+-			    vim_free(st);
++				vim_free(st);
++			    }
++			    col += width;
+ 			}
+-			col += width;
+ 
+ 			if (*p != TAB)
+ 			    break;
+ 
+ 			/* Display two spaces for a Tab. */
+-			screen_puts_len((char_u *)"  ", 2, row, col, attr);
+-			col += 2;
++#ifdef FEAT_RIGHTLEFT
++			if (curwin->w_p_rl)
++			{
++			    screen_puts_len((char_u *)"  ", 2, row, col - 1,
++									attr);
++			    col -= 2;
++			}
++			else
++#endif
++			{
++			    screen_puts_len((char_u *)"  ", 2, row, col, attr);
++			    col += 2;
++			}
+ 			totwidth += 2;
+ 			s = NULL;	    /* start text at next char */
+ 			width = 0;
+@@ -322,17 +401,44 @@
+ 					  && pum_array[idx].pum_extra == NULL)
+ 		    || pum_base_width + n >= pum_width)
+ 		break;
+-	    screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
++#ifdef FEAT_RIGHTLEFT
++	    if (curwin->w_p_rl)
++	    {
++		screen_fill(row, row + 1, pum_col - pum_base_width - n + 1,
++						    col + 1, ' ', ' ', attr);
++		col = pum_col - pum_base_width - n + 1;
++	    }
++	    else
++#endif
++	    {
++		screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
+ 							      ' ', ' ', attr);
+-	    col = pum_col + pum_base_width + n;
++		col = pum_col + pum_base_width + n;
++	    }
+ 	    totwidth = pum_base_width + n;
+ 	}
+ 
+-	screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', attr);
++#ifdef FEAT_RIGHTLEFT
++	if (curwin->w_p_rl)
++	    screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ',
++								    ' ', attr);
++	else
++#endif
++	    screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
++									attr);
+ 	if (pum_scrollbar > 0)
+-	    screen_putchar(' ', row, pum_col + pum_width,
+-		    i >= thumb_pos && i < thumb_pos + thumb_heigth
++	{
++#ifdef FEAT_RIGHTLEFT
++	    if (curwin->w_p_rl)
++		screen_putchar(' ', row, pum_col - pum_width,
++			i >= thumb_pos && i < thumb_pos + thumb_heigth
+ 						  ? attr_thumb : attr_scroll);
++	    else
++#endif
++		screen_putchar(' ', row, pum_col + pum_width,
++			i >= thumb_pos && i < thumb_pos + thumb_heigth
++						  ? attr_thumb : attr_scroll);
++	}
+ 
+ 	++row;
+     }
+@@ -466,7 +572,7 @@
+ 			set_option_value((char_u *)"bh", 0L,
+ 						 (char_u *)"wipe", OPT_LOCAL);
+ 			set_option_value((char_u *)"diff", 0L,
+-						     (char_u *)"", OPT_LOCAL);
++							     NULL, OPT_LOCAL);
+ 		    }
+ 		}
+ 		if (res == OK)
+diff -Naur vim71.orig/src/proto/charset.pro vim71/src/proto/charset.pro
+--- vim71.orig/src/proto/charset.pro	2007-05-12 10:39:01.000000000 +0000
++++ vim71/src/proto/charset.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -21,6 +21,7 @@
+ int vim_iswordp __ARGS((char_u *p));
+ int vim_iswordc_buf __ARGS((char_u *p, buf_T *buf));
+ int vim_isfilec __ARGS((int c));
++int vim_isfilec_or_wc __ARGS((int c));
+ int vim_isprintc __ARGS((int c));
+ int vim_isprintc_strict __ARGS((int c));
+ int lbr_chartabsize __ARGS((unsigned char *s, colnr_T col));
+diff -Naur vim71.orig/src/proto/ex_docmd.pro vim71/src/proto/ex_docmd.pro
+--- vim71.orig/src/proto/ex_docmd.pro	2007-05-12 10:39:10.000000000 +0000
++++ vim71/src/proto/ex_docmd.pro	2007-12-08 20:34:53.000000000 +0000
+@@ -5,6 +5,7 @@
+ int getline_equal __ARGS((char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int)));
+ void *getline_cookie __ARGS((char_u *(*fgetline)(int, void *, int), void *cookie));
+ int checkforcmd __ARGS((char_u **pp, char *cmd, int len));
++int modifier_len __ARGS((char_u *cmd));
+ int cmd_exists __ARGS((char_u *name));
+ char_u *set_one_cmd_context __ARGS((expand_T *xp, char_u *buff));
+ char_u *skip_range __ARGS((char_u *cmd, int *ctx));
+diff -Naur vim71.orig/src/proto/fileio.pro vim71/src/proto/fileio.pro
+--- vim71.orig/src/proto/fileio.pro	2007-05-12 10:39:14.000000000 +0000
++++ vim71/src/proto/fileio.pro	2007-12-08 20:34:52.000000000 +0000
+@@ -2,6 +2,7 @@
+ void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr));
+ int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags));
+ int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
++int check_file_readonly __ARGS((char_u *fname, int perm));
+ int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering));
+ void msg_add_fname __ARGS((buf_T *buf, char_u *fname));
+ void msg_add_lines __ARGS((int insert_space, long lnum, long nchars));
+@@ -39,6 +40,8 @@
+ int trigger_cursorhold __ARGS((void));
+ int has_cursormoved __ARGS((void));
+ int has_cursormovedI __ARGS((void));
++void block_autocmds __ARGS((void));
++void unblock_autocmds __ARGS((void));
+ int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf));
+ char_u *get_augroup_name __ARGS((expand_T *xp, int idx));
+ char_u *set_context_in_autocmd __ARGS((expand_T *xp, char_u *arg, int doautocmd));
+diff -Naur vim71.orig/src/proto/getchar.pro vim71/src/proto/getchar.pro
+--- vim71.orig/src/proto/getchar.pro	2007-05-12 10:39:16.000000000 +0000
++++ vim71/src/proto/getchar.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -38,6 +38,7 @@
+ void updatescript __ARGS((int c));
+ int vgetc __ARGS((void));
+ int safe_vgetc __ARGS((void));
++int plain_vgetc __ARGS((void));
+ int vpeekc __ARGS((void));
+ int vpeekc_nomap __ARGS((void));
+ int vpeekc_any __ARGS((void));
+diff -Naur vim71.orig/src/proto/if_cscope.pro vim71/src/proto/if_cscope.pro
+--- vim71.orig/src/proto/if_cscope.pro	2007-05-12 10:39:21.000000000 +0000
++++ vim71/src/proto/if_cscope.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -6,4 +6,5 @@
+ void cs_free_tags __ARGS((void));
+ void cs_print_tags __ARGS((void));
+ int cs_connection __ARGS((int num, char_u *dbpath, char_u *ppath));
++void cs_end __ARGS((void));
+ /* vim: set ft=c : */
+diff -Naur vim71.orig/src/proto/mbyte.pro vim71/src/proto/mbyte.pro
+--- vim71.orig/src/proto/mbyte.pro	2007-05-12 10:39:38.000000000 +0000
++++ vim71/src/proto/mbyte.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -12,9 +12,9 @@
+ int utf_ptr2cells __ARGS((char_u *p));
+ int dbcs_ptr2cells __ARGS((char_u *p));
+ int latin_char2cells __ARGS((int c));
+-int latin_off2cells __ARGS((unsigned off));
+-int dbcs_off2cells __ARGS((unsigned off));
+-int utf_off2cells __ARGS((unsigned off));
++int latin_off2cells __ARGS((unsigned off, unsigned max_off));
++int dbcs_off2cells __ARGS((unsigned off, unsigned max_off));
++int utf_off2cells __ARGS((unsigned off, unsigned max_off));
+ int latin_ptr2char __ARGS((char_u *p));
+ int utf_ptr2char __ARGS((char_u *p));
+ int mb_ptr2char_adv __ARGS((char_u **pp));
+diff -Naur vim71.orig/src/proto/misc1.pro vim71/src/proto/misc1.pro
+--- vim71.orig/src/proto/misc1.pro	2007-05-12 10:39:34.000000000 +0000
++++ vim71/src/proto/misc1.pro	2007-12-08 20:34:52.000000000 +0000
+@@ -48,10 +48,11 @@
+ void vim_beep __ARGS((void));
+ void init_homedir __ARGS((void));
+ void free_homedir __ARGS((void));
++char_u *expand_env_save __ARGS((char_u *src));
++char_u *expand_env_save_opt __ARGS((char_u *src, int one));
+ void expand_env __ARGS((char_u *src, char_u *dst, int dstlen));
+-void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, char_u *startstr));
++void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, int one, char_u *startstr));
+ char_u *vim_getenv __ARGS((char_u *name, int *mustfree));
+-char_u *expand_env_save __ARGS((char_u *src));
+ void vim_setenv __ARGS((char_u *name, char_u *val));
+ char_u *get_env_name __ARGS((expand_T *xp, int idx));
+ void home_replace __ARGS((buf_T *buf, char_u *src, char_u *dst, int dstlen, int one));
+diff -Naur vim71.orig/src/proto/search.pro vim71/src/proto/search.pro
+--- vim71.orig/src/proto/search.pro	2007-05-12 10:39:50.000000000 +0000
++++ vim71/src/proto/search.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -1,6 +1,7 @@
+ /* search.c */
+ int search_regcomp __ARGS((char_u *pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch));
+ char_u *get_search_pat __ARGS((void));
++char_u *reverse_text __ARGS((char_u *s));
+ void save_search_patterns __ARGS((void));
+ void restore_search_patterns __ARGS((void));
+ void free_search_patterns __ARGS((void));
+diff -Naur vim71.orig/src/proto/syntax.pro vim71/src/proto/syntax.pro
+--- vim71.orig/src/proto/syntax.pro	2007-05-12 10:39:52.000000000 +0000
++++ vim71/src/proto/syntax.pro	2007-12-08 20:34:50.000000000 +0000
+@@ -8,6 +8,8 @@
+ void syntax_clear __ARGS((buf_T *buf));
+ void ex_syntax __ARGS((exarg_T *eap));
+ int syntax_present __ARGS((buf_T *buf));
++void reset_expand_highlight __ARGS((void));
++void set_context_in_echohl_cmd __ARGS((expand_T *xp, char_u *arg));
+ void set_context_in_syntax_cmd __ARGS((expand_T *xp, char_u *arg));
+ char_u *get_syntax_name __ARGS((expand_T *xp, int idx));
+ int syn_get_id __ARGS((win_T *wp, long lnum, colnr_T col, int trans, int *spellp));
+diff -Naur vim71.orig/src/proto/window.pro vim71/src/proto/window.pro
+--- vim71.orig/src/proto/window.pro	2007-05-12 10:40:00.000000000 +0000
++++ vim71/src/proto/window.pro	2007-12-08 20:34:51.000000000 +0000
+@@ -59,4 +59,8 @@
+ int only_one_window __ARGS((void));
+ void check_lnums __ARGS((int do_curwin));
+ int win_hasvertsplit __ARGS((void));
++int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id));
++int match_delete __ARGS((win_T *wp, int id, int perr));
++void clear_matches __ARGS((win_T *wp));
++matchitem_T *get_match __ARGS((win_T *wp, int id));
+ /* vim: set ft=c : */
+diff -Naur vim71.orig/src/quickfix.c vim71/src/quickfix.c
+--- vim71.orig/src/quickfix.c	2007-02-04 00:50:17.000000000 +0000
++++ vim71/src/quickfix.c	2007-12-08 20:34:51.000000000 +0000
+@@ -1612,8 +1612,8 @@
+ 	}
+ 
+ 	/*
+-	 * If there is only one window and is the quickfix window, create a new
+-	 * one above the quickfix window.
++	 * If there is only one window and it is the quickfix window, create a
++	 * new one above the quickfix window.
+ 	 */
+ 	if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win)
+ 	{
+@@ -2331,7 +2331,7 @@
+ 	    set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
+ 								   OPT_LOCAL);
+ 	    set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
+-	    set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL);
++	    set_option_value((char_u *)"diff", 0L, NULL, OPT_LOCAL);
+ 	}
+ 
+ 	/* Only set the height when still in the same tab page and there is no
+@@ -2981,6 +2981,7 @@
+     buf_T	*buf;
+     int		duplicate_name = FALSE;
+     int		using_dummy;
++    int		redraw_for_dummy = FALSE;
+     int		found_match;
+     buf_T	*first_match_buf = NULL;
+     time_t	seconds = 0;
+@@ -3097,6 +3098,7 @@
+ 	    /* Remember that a buffer with this name already exists. */
+ 	    duplicate_name = (buf != NULL);
+ 	    using_dummy = TRUE;
++	    redraw_for_dummy = TRUE;
+ 
+ #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
+ 	    /* Don't do Filetype autocommands to avoid loading syntax and
+@@ -3243,11 +3245,29 @@
+     if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
+     {
+ 	if ((flags & VGR_NOJUMP) == 0)
++	{
++	    buf = curbuf;
+ 	    qf_jump(qi, 0, 0, eap->forceit);
++	    if (buf != curbuf)
++		/* If we jumped to another buffer redrawing will already be
++		 * taken care of. */
++		redraw_for_dummy = FALSE;
++	}
+     }
+     else
+ 	EMSG2(_(e_nomatch2), s);
+ 
++    /* If we loaded a dummy buffer into the current window, the autocommands
++     * may have messed up things, need to redraw and recompute folds. */
++    if (redraw_for_dummy)
++    {
++#ifdef FEAT_FOLDING
++	foldUpdateAll(curwin);
++#else
++	redraw_later(NOT_VALID);
++#endif
++    }
++
+ theend:
+     vim_free(regmatch.regprog);
+ }
+diff -Naur vim71.orig/src/regexp.c vim71/src/regexp.c
+--- vim71.orig/src/regexp.c	2007-05-07 19:50:03.000000000 +0000
++++ vim71/src/regexp.c	2007-12-08 20:34:53.000000000 +0000
+@@ -2220,7 +2220,7 @@
+ 				break;
+ 			    case CLASS_LOWER:
+ 				for (cu = 1; cu <= 255; cu++)
+-				    if (islower(cu))
++				    if (MB_ISLOWER(cu))
+ 					regc(cu);
+ 				break;
+ 			    case CLASS_PRINT:
+@@ -2240,7 +2240,7 @@
+ 				break;
+ 			    case CLASS_UPPER:
+ 				for (cu = 1; cu <= 255; cu++)
+-				    if (isupper(cu))
++				    if (MB_ISUPPER(cu))
+ 					regc(cu);
+ 				break;
+ 			    case CLASS_XDIGIT:
+@@ -2770,7 +2770,8 @@
+     {
+ #ifdef FEAT_MBYTE
+ 	if (enc_utf8)
+-	    prevchr_len += utf_char2len(mb_ptr2char(regparse + prevchr_len));
++	    /* exclude composing chars that mb_ptr2len does include */
++	    prevchr_len += utf_ptr2len(regparse + prevchr_len);
+ 	else if (has_mbyte)
+ 	    prevchr_len += (*mb_ptr2len)(regparse + prevchr_len);
+ 	else
+@@ -3465,7 +3466,7 @@
+ 			(enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
+ 			|| (c < 255 && prog->regstart < 255 &&
+ #endif
+-			    TOLOWER_LOC(prog->regstart) == TOLOWER_LOC(c)))))
++			    MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
+ 	    retval = regtry(prog, col);
+ 	else
+ 	    retval = 0;
+@@ -4200,7 +4201,7 @@
+ #ifdef FEAT_MBYTE
+ 			    !enc_utf8 &&
+ #endif
+-			    TOLOWER_LOC(*opnd) != TOLOWER_LOC(*reginput))))
++			    MB_TOLOWER(*opnd) != MB_TOLOWER(*reginput))))
+ 		    status = RA_NOMATCH;
+ 		else if (*opnd == NUL)
+ 		{
+@@ -4733,10 +4734,10 @@
+ 		    rst.nextb = *OPERAND(next);
+ 		    if (ireg_ic)
+ 		    {
+-			if (isupper(rst.nextb))
+-			    rst.nextb_ic = TOLOWER_LOC(rst.nextb);
++			if (MB_ISUPPER(rst.nextb))
++			    rst.nextb_ic = MB_TOLOWER(rst.nextb);
+ 			else
+-			    rst.nextb_ic = TOUPPER_LOC(rst.nextb);
++			    rst.nextb_ic = MB_TOUPPER(rst.nextb);
+ 		    }
+ 		    else
+ 			rst.nextb_ic = rst.nextb;
+@@ -5558,11 +5559,12 @@
+ 	    int	    cu, cl;
+ 
+ 	    /* This doesn't do a multi-byte character, because a MULTIBYTECODE
+-	     * would have been used for it. */
++	     * would have been used for it.  It does handle single-byte
++	     * characters, such as latin1. */
+ 	    if (ireg_ic)
+ 	    {
+-		cu = TOUPPER_LOC(*opnd);
+-		cl = TOLOWER_LOC(*opnd);
++		cu = MB_TOUPPER(*opnd);
++		cl = MB_TOLOWER(*opnd);
+ 		while (count < maxcount && (*scan == cu || *scan == cl))
+ 		{
+ 		    count++;
+@@ -6490,10 +6492,10 @@
+ 	cc = utf_fold(c);
+     else
+ #endif
+-	 if (isupper(c))
+-	cc = TOLOWER_LOC(c);
+-    else if (islower(c))
+-	cc = TOUPPER_LOC(c);
++	 if (MB_ISUPPER(c))
++	cc = MB_TOLOWER(c);
++    else if (MB_ISLOWER(c))
++	cc = MB_TOUPPER(c);
+     else
+ 	return vim_strchr(s, c);
+ 
+@@ -6637,9 +6639,9 @@
+ 		}
+ 	    }
+ 	    else if (magic)
+-		STRCPY(p, p + 1);		/* remove '~' */
++		mch_memmove(p, p + 1, STRLEN(p));	/* remove '~' */
+ 	    else
+-		STRCPY(p, p + 2);		/* remove '\~' */
++		mch_memmove(p, p + 2, STRLEN(p) - 1);	/* remove '\~' */
+ 	    --p;
+ 	}
+ 	else
+@@ -7014,7 +7016,14 @@
+ #ifdef FEAT_MBYTE
+ 			    if (has_mbyte)
+ 			    {
+-				int l = mb_ptr2len(s) - 1;
++				int l;
++
++				/* Copy composing characters separately, one
++				 * at a time. */
++				if (enc_utf8)
++				    l = utf_ptr2len(s) - 1;
++				else
++				    l = mb_ptr2len(s) - 1;
+ 
+ 				s += l;
+ 				len -= l;
+diff -Naur vim71.orig/src/screen.c vim71/src/screen.c
+--- vim71.orig/src/screen.c	2007-05-07 19:27:53.000000000 +0000
++++ vim71/src/screen.c	2007-12-08 20:34:53.000000000 +0000
+@@ -100,27 +100,7 @@
+ static int	screen_cur_row, screen_cur_col;	/* last known cursor position */
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+-/*
+- * Struct used for highlighting 'hlsearch' matches for the last use search
+- * pattern or a ":match" item.
+- * For 'hlsearch' there is one pattern for all windows.  For ":match" there is
+- * a different pattern for each window.
+- */
+-typedef struct
+-{
+-    regmmatch_T	rm;	/* points to the regexp program; contains last found
+-			   match (may continue in next line) */
+-    buf_T	*buf;	/* the buffer to search for a match */
+-    linenr_T	lnum;	/* the line to search for a match */
+-    int		attr;	/* attributes to be used for a match */
+-    int		attr_cur; /* attributes currently active in win_line() */
+-    linenr_T	first_lnum;	/* first lnum to search for multi-line pat */
+-    colnr_T	startcol; /* in win_line() points to char where HL starts */
+-    colnr_T	endcol;	 /* in win_line() points to char where HL ends */
+-} match_T;
+-
+ static match_T search_hl;	/* used for 'hlsearch' highlight matching */
+-static match_T match_hl[3];	/* used for ":match" highlight matching */
+ #endif
+ 
+ #ifdef FEAT_FOLDING
+@@ -155,6 +135,7 @@
+ static void redraw_custum_statusline __ARGS((win_T *wp));
+ #endif
+ #ifdef FEAT_SEARCH_EXTRA
++#define SEARCH_HL_PRIORITY 0
+ static void start_search_hl __ARGS((void));
+ static void end_search_hl __ARGS((void));
+ static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
+@@ -350,6 +331,11 @@
+     {
+ 	if (type < must_redraw)	    /* use maximal type */
+ 	    type = must_redraw;
++
++	/* must_redraw is reset here, so that when we run into some weird
++	 * reason to redraw while busy redrawing (e.g., asynchronous
++	 * scrolling), or update_topline() in win_update() will cause a
++	 * scroll, the screen will be redrawn later or in win_update(). */
+ 	must_redraw = 0;
+     }
+ 
+@@ -787,6 +773,7 @@
+ 					   w_topline got smaller a bit */
+ #endif
+ #ifdef FEAT_SEARCH_EXTRA
++    matchitem_T *cur;		/* points to the match list */
+     int		top_to_mod = FALSE;    /* redraw above mod_top */
+ #endif
+ 
+@@ -848,18 +835,20 @@
+ #endif
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+-    /* Setup for ":match" and 'hlsearch' highlighting.  Disable any previous
++    /* Setup for match and 'hlsearch' highlighting.  Disable any previous
+      * match */
+-    for (i = 0; i < 3; ++i)
++    cur = wp->w_match_head;
++    while (cur != NULL)
+     {
+-	match_hl[i].rm = wp->w_match[i];
+-	if (wp->w_match_id[i] == 0)
+-	    match_hl[i].attr = 0;
+-	else
+-	    match_hl[i].attr = syn_id2attr(wp->w_match_id[i]);
+-	match_hl[i].buf = buf;
+-	match_hl[i].lnum = 0;
+-	match_hl[i].first_lnum = 0;
++	cur->hl.rm = cur->match;
++	if (cur->hlg_id == 0)
++	    cur->hl.attr = 0;
++	else
++	    cur->hl.attr = syn_id2attr(cur->hlg_id);
++	cur->hl.buf = buf;
++	cur->hl.lnum = 0;
++	cur->hl.first_lnum = 0;
++	cur = cur->next;
+     }
+     search_hl.buf = buf;
+     search_hl.lnum = 0;
+@@ -923,19 +912,25 @@
+ 	     * change in one line may make the Search highlighting in a
+ 	     * previous line invalid.  Simple solution: redraw all visible
+ 	     * lines above the change.
+-	     * Same for a ":match" pattern.
++	     * Same for a match pattern.
+ 	     */
+ 	    if (search_hl.rm.regprog != NULL
+ 					&& re_multiline(search_hl.rm.regprog))
+ 		top_to_mod = TRUE;
+ 	    else
+-		for (i = 0; i < 3; ++i)
+-		    if (match_hl[i].rm.regprog != NULL
+-				      && re_multiline(match_hl[i].rm.regprog))
++	    {
++		cur = wp->w_match_head;
++		while (cur != NULL)
++		{
++		    if (cur->match.regprog != NULL
++					   && re_multiline(cur->match.regprog))
+ 		    {
+ 			top_to_mod = TRUE;
+ 			break;
+ 		    }
++		    cur = cur->next;
++		}
++	    }
+ #endif
+ 	}
+ #ifdef FEAT_FOLDING
+@@ -1029,6 +1024,13 @@
+ 	    type = VALID;
+     }
+ 
++    /* Trick: we want to avoid clearing the screen twice.  screenclear() will
++     * set "screen_cleared" to TRUE.  The special value MAYBE (which is still
++     * non-zero and thus not FALSE) will indicate that screenclear() was not
++     * called. */
++    if (screen_cleared)
++	screen_cleared = MAYBE;
++
+     /*
+      * If there are no changes on the screen that require a complete redraw,
+      * handle three cases:
+@@ -1230,7 +1232,11 @@
+ 	    mid_end = wp->w_height;
+ 	    if (lastwin == firstwin)
+ 	    {
+-		screenclear();
++		/* Clear the screen when it was not done by win_del_lines() or
++		 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
++		 * then. */
++		if (screen_cleared != TRUE)
++		    screenclear();
+ #ifdef FEAT_WINDOWS
+ 		/* The screen was cleared, redraw the tab pages line. */
+ 		if (redraw_tabline)
+@@ -1238,6 +1244,13 @@
+ #endif
+ 	    }
+ 	}
++
++	/* When win_del_lines() or win_ins_lines() caused the screen to be
++	 * cleared (only happens for the first window) or when screenclear()
++	 * was called directly above, "must_redraw" will have been set to
++	 * NOT_VALID, need to reset it here to avoid redrawing twice. */
++	if (screen_cleared == TRUE)
++	    must_redraw = 0;
+     }
+     else
+     {
+@@ -2292,9 +2305,11 @@
+ 			prev_c = u8c;
+ #endif
+ 		    /* Non-BMP character: display as ? or fullwidth ?. */
++#ifdef UNICODE16
+ 		    if (u8c >= 0x10000)
+ 			ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
+ 		    else
++#endif
+ 			ScreenLinesUC[idx] = u8c;
+ 		    for (i = 0; i < Screen_mco; ++i)
+ 		    {
+@@ -2542,7 +2557,7 @@
+ 
+     char_u	extra[18];		/* "%ld" and 'fdc' must fit in here */
+     int		n_extra = 0;		/* number of extra chars */
+-    char_u	*p_extra = NULL;	/* string of extra chars */
++    char_u	*p_extra = NULL;	/* string of extra chars, plus NUL */
+     int		c_extra = NUL;		/* extra chars, all the same */
+     int		extra_attr = 0;		/* attributes when n_extra != 0 */
+     static char_u *at_end_str = (char_u *)""; /* used for p_extra when
+@@ -2584,6 +2599,7 @@
+     int		syntax_attr = 0;	/* attributes desired by syntax */
+     int		has_syntax = FALSE;	/* this buffer has syntax highl. */
+     int		save_did_emsg;
++    int		eol_hl_off = 0;		/* 1 if highlighted char after EOL */
+ #endif
+ #ifdef FEAT_SPELL
+     int		has_spell = FALSE;	/* this buffer has spell checking */
+@@ -2626,10 +2642,13 @@
+     int		line_attr = 0;		/* atrribute for the whole line */
+ #endif
+ #ifdef FEAT_SEARCH_EXTRA
+-    match_T	*shl;			/* points to search_hl or match_hl */
+-#endif
+-#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_MBYTE)
+-    int		i;
++    matchitem_T *cur;			/* points to the match list */
++    match_T	*shl;			/* points to search_hl or a match */
++    int		shl_flag;		/* flag to indicate whether search_hl
++					   has been processed or not */
++    int		prevcol_hl_flag;	/* flag to indicate whether prevcol
++					   equals startcol of search_hl or one
++					   of the matches */
+ #endif
+ #ifdef FEAT_ARABIC
+     int		prev_c = 0;		/* previous Arabic character */
+@@ -3074,12 +3093,20 @@
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+     /*
+-     * Handle highlighting the last used search pattern and ":match".
+-     * Do this for both search_hl and match_hl[3].
++     * Handle highlighting the last used search pattern and matches.
++     * Do this for both search_hl and the match list.
+      */
+-    for (i = 3; i >= 0; --i)
++    cur = wp->w_match_head;
++    shl_flag = FALSE;
++    while (cur != NULL || shl_flag == FALSE)
+     {
+-	shl = (i == 3) ? &search_hl : &match_hl[i];
++	if (shl_flag == FALSE)
++	{
++	    shl = &search_hl;
++	    shl_flag = TRUE;
++	}
++	else
++	    shl = &cur->hl;
+ 	shl->startcol = MAXCOL;
+ 	shl->endcol = MAXCOL;
+ 	shl->attr_cur = 0;
+@@ -3122,6 +3149,8 @@
+ 		area_highlighting = TRUE;
+ 	    }
+ 	}
++	if (shl != &search_hl && cur != NULL)
++	    cur = cur->next;
+     }
+ #endif
+ 
+@@ -3163,10 +3192,8 @@
+ 		if (cmdwin_type != 0 && wp == curwin)
+ 		{
+ 		    /* Draw the cmdline character. */
+-		    *extra = cmdwin_type;
+ 		    n_extra = 1;
+-		    p_extra = extra;
+-		    c_extra = NUL;
++		    c_extra = cmdwin_type;
+ 		    char_attr = hl_attr(HLF_AT);
+ 		}
+ 	    }
+@@ -3182,6 +3209,7 @@
+ 		    fill_foldcolumn(extra, wp, FALSE, lnum);
+ 		    n_extra = wp->w_p_fdc;
+ 		    p_extra = extra;
++		    p_extra[n_extra] = NUL;
+ 		    c_extra = NUL;
+ 		    char_attr = hl_attr(HLF_FC);
+ 		}
+@@ -3388,13 +3416,24 @@
+ 		 * After end, check for start/end of next match.
+ 		 * When another match, have to check for start again.
+ 		 * Watch out for matching an empty string!
+-		 * Do this first for search_hl, then for match_hl, so that
+-		 * ":match" overrules 'hlsearch'.
++		 * Do this for 'search_hl' and the match list (ordered by
++		 * priority).
+ 		 */
+ 		v = (long)(ptr - line);
+-		for (i = 3; i >= 0; --i)
+-		{
+-		    shl = (i == 3) ? &search_hl : &match_hl[i];
++		cur = wp->w_match_head;
++		shl_flag = FALSE;
++		while (cur != NULL || shl_flag == FALSE)
++		{
++		    if (shl_flag == FALSE
++			    && ((cur != NULL
++				    && cur->priority > SEARCH_HL_PRIORITY)
++				|| cur == NULL))
++		    {
++			shl = &search_hl;
++			shl_flag = TRUE;
++		    }
++		    else
++			shl = &cur->hl;
+ 		    while (shl->rm.regprog != NULL)
+ 		    {
+ 			if (shl->startcol != MAXCOL
+@@ -3442,26 +3481,43 @@
+ 			}
+ 			break;
+ 		    }
++		    if (shl != &search_hl && cur != NULL)
++			cur = cur->next;
+ 		}
+ 
+-		/* ":match" highlighting overrules 'hlsearch' */
+-		for (i = 0; i <= 3; ++i)
+-		    if (i == 3)
+-			search_attr = search_hl.attr_cur;
+-		    else if (match_hl[i].attr_cur != 0)
++		/* Use attributes from match with highest priority among
++		 * 'search_hl' and the match list. */
++		search_attr = search_hl.attr_cur;
++		cur = wp->w_match_head;
++		shl_flag = FALSE;
++		while (cur != NULL || shl_flag == FALSE)
++		{
++		    if (shl_flag == FALSE
++			    && ((cur != NULL
++				    && cur->priority > SEARCH_HL_PRIORITY)
++				|| cur == NULL))
+ 		    {
+-			search_attr = match_hl[i].attr_cur;
+-			break;
++			shl = &search_hl;
++			shl_flag = TRUE;
+ 		    }
++		    else
++			shl = &cur->hl;
++		    if (shl->attr_cur != 0)
++			search_attr = shl->attr_cur;
++		    if (shl != &search_hl && cur != NULL)
++			cur = cur->next;
++		}
+ 	    }
+ #endif
+ 
+ #ifdef FEAT_DIFF
+ 	    if (diff_hlf != (hlf_T)0)
+ 	    {
+-		if (diff_hlf == HLF_CHD && ptr - line >= change_start)
++		if (diff_hlf == HLF_CHD && ptr - line >= change_start
++							      && n_extra == 0)
+ 		    diff_hlf = HLF_TXD;		/* changed text */
+-		if (diff_hlf == HLF_TXD && ptr - line > change_end)
++		if (diff_hlf == HLF_TXD && ptr - line > change_end
++							      && n_extra == 0)
+ 		    diff_hlf = HLF_CHD;		/* changed line */
+ 		line_attr = hl_attr(diff_hlf);
+ 	    }
+@@ -3496,9 +3552,11 @@
+ 	 * Get the next character to put on the screen.
+ 	 */
+ 	/*
+-	 * The 'extra' array contains the extra stuff that is inserted to
+-	 * represent special characters (non-printable stuff).  When all
+-	 * characters are the same, c_extra is used.
++	 * The "p_extra" points to the extra stuff that is inserted to
++	 * represent special characters (non-printable stuff) and other
++	 * things.  When all characters are the same, c_extra is used.
++	 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
++	 * "p_extra[n_extra]".
+ 	 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
+ 	 */
+ 	if (n_extra > 0)
+@@ -3611,6 +3669,8 @@
+ 			 * Draw it as a space with a composing char. */
+ 			if (utf_iscomposing(mb_c))
+ 			{
++			    int i;
++
+ 			    for (i = Screen_mco - 1; i > 0; --i)
+ 				u8cc[i] = u8cc[i - 1];
+ 			    u8cc[0] = mb_c;
+@@ -3621,13 +3681,18 @@
+ 		    if ((mb_l == 1 && c >= 0x80)
+ 			    || (mb_l >= 1 && mb_c == 0)
+ 			    || (mb_l > 1 && (!vim_isprintc(mb_c)
+-							 || mb_c >= 0x10000)))
++# ifdef UNICODE16
++							 || mb_c >= 0x10000
++# endif
++							 )))
+ 		    {
+ 			/*
+ 			 * Illegal UTF-8 byte: display as <xx>.
+ 			 * Non-BMP character : display as ? or fullwidth ?.
+ 			 */
++# ifdef UNICODE16
+ 			if (mb_c < 0x10000)
++# endif
+ 			{
+ 			    transchar_hex(extra, mb_c);
+ # ifdef FEAT_RIGHTLEFT
+@@ -3635,11 +3700,13 @@
+ 				rl_mirror(extra);
+ # endif
+ 			}
++# ifdef UNICODE16
+ 			else if (utf_char2cells(mb_c) != 2)
+ 			    STRCPY(extra, "?");
+ 			else
+ 			    /* 0xff1f in UTF-8: full-width '?' */
+ 			    STRCPY(extra, "\357\274\237");
++# endif
+ 
+ 			p_extra = extra;
+ 			c = *p_extra;
+@@ -3752,10 +3819,8 @@
+ 		 * a '<' in the first column. */
+ 		if (n_skip > 0 && mb_l > 1)
+ 		{
+-		    extra[0] = '<';
+-		    p_extra = extra;
+ 		    n_extra = 1;
+-		    c_extra = NUL;
++		    c_extra = '<';
+ 		    c = ' ';
+ 		    if (area_attr == 0 && search_attr == 0)
+ 		    {
+@@ -4248,20 +4313,39 @@
+ 	{
+ #ifdef FEAT_SEARCH_EXTRA
+ 	    long prevcol = (long)(ptr - line) - (c == NUL);
++
++	    /* we're not really at that column when skipping some text */
++	    if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
++		++prevcol;
+ #endif
+ 
+ 	    /* invert at least one char, used for Visual and empty line or
+ 	     * highlight match at end of line. If it's beyond the last
+ 	     * char on the screen, just overwrite that one (tricky!)  Not
+ 	     * needed when a '$' was displayed for 'list'. */
++#ifdef FEAT_SEARCH_EXTRA
++	    prevcol_hl_flag = FALSE;
++	    if (prevcol == (long)search_hl.startcol)
++		prevcol_hl_flag = TRUE;
++	    else
++	    {
++		cur = wp->w_match_head;
++		while (cur != NULL)
++		{
++		    if (prevcol == (long)cur->hl.startcol)
++		    {
++			prevcol_hl_flag = TRUE;
++			break;
++		    }
++		    cur = cur->next;
++		}
++	    }
++#endif
+ 	    if (lcs_eol == lcs_eol_one
+ 		    && ((area_attr != 0 && vcol == fromcol && c == NUL)
+ #ifdef FEAT_SEARCH_EXTRA
+ 			/* highlight 'hlsearch' match at end of line */
+-			|| ((prevcol == (long)search_hl.startcol
+-				|| prevcol == (long)match_hl[0].startcol
+-				|| prevcol == (long)match_hl[1].startcol
+-				|| prevcol == (long)match_hl[2].startcol)
++			|| (prevcol_hl_flag == TRUE
+ # if defined(LINE_ATTR)
+ 			    && did_line_attr <= 1
+ # endif
+@@ -4302,26 +4386,47 @@
+ #ifdef FEAT_SEARCH_EXTRA
+ 		if (area_attr == 0)
+ 		{
+-		    for (i = 0; i <= 3; ++i)
+-		    {
+-			if (i == 3)
+-			    char_attr = search_hl.attr;
+-			else if ((ptr - line) - 1 == (long)match_hl[i].startcol)
++		    /* Use attributes from match with highest priority among
++		     * 'search_hl' and the match list. */
++		    char_attr = search_hl.attr;
++		    cur = wp->w_match_head;
++		    shl_flag = FALSE;
++		    while (cur != NULL || shl_flag == FALSE)
++		    {
++			if (shl_flag == FALSE
++				&& ((cur != NULL
++					&& cur->priority > SEARCH_HL_PRIORITY)
++				    || cur == NULL))
+ 			{
+-			    char_attr = match_hl[i].attr;
+-			    break;
++			    shl = &search_hl;
++			    shl_flag = TRUE;
+ 			}
++			else
++			    shl = &cur->hl;
++			if ((ptr - line) - 1 == (long)shl->startcol)
++			    char_attr = shl->attr;
++			if (shl != &search_hl && cur != NULL)
++			    cur = cur->next;
+ 		    }
+ 		}
+ #endif
+ 		ScreenAttrs[off] = char_attr;
+ #ifdef FEAT_RIGHTLEFT
+ 		if (wp->w_p_rl)
++		{
+ 		    --col;
++		    --off;
++		}
+ 		else
+ #endif
++		{
+ 		    ++col;
++		    ++off;
++		}
+ 		++vcol;
++#ifdef FEAT_SYN_HL
++		eol_hl_off = 1;
++#endif
+ 	    }
+ 	}
+ 
+@@ -4331,6 +4436,14 @@
+ 	if (c == NUL)
+ 	{
+ #ifdef FEAT_SYN_HL
++	    if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol)
++	    {
++		/* highlight last char after line */
++		--col;
++		--off;
++		--vcol;
++	    }
++
+ 	    /* Highlight 'cursorcolumn' past end of the line. */
+ 	    if (wp->w_p_wrap)
+ 		v = wp->w_skipcol;
+@@ -4341,7 +4454,7 @@
+ 
+ 		vcol = v + col - win_col_off(wp);
+ 	    if (wp->w_p_cuc
+-		    && (int)wp->w_virtcol >= vcol
++		    && (int)wp->w_virtcol >= vcol - eol_hl_off
+ 		    && (int)wp->w_virtcol < W_WIDTH(wp) * (row - startrow + 1)
+ 									   + v
+ 		    && lnum != wp->w_cursor.lnum
+@@ -4460,6 +4573,8 @@
+ 	    {
+ 		if (mb_utf8)
+ 		{
++		    int i;
++
+ 		    ScreenLinesUC[off] = mb_c;
+ 		    if ((c & 0xff) == 0)
+ 			ScreenLines[off] = 0x80;   /* avoid storing zero */
+@@ -4548,7 +4663,7 @@
+ 
+ 	/*
+ 	 * At end of screen line and there is more to come: Display the line
+-	 * so far.  If there is no more to display it is catched above.
++	 * so far.  If there is no more to display it is caught above.
+ 	 */
+ 	if ((
+ #ifdef FEAT_RIGHTLEFT
+@@ -4625,9 +4740,13 @@
+ #endif
+ #ifdef FEAT_MBYTE
+ 			 && !(has_mbyte
+-			     && ((*mb_off2cells)(LineOffset[screen_row]) == 2
++			     && ((*mb_off2cells)(LineOffset[screen_row],
++				     LineOffset[screen_row] + screen_Columns)
++									  == 2
+ 				 || (*mb_off2cells)(LineOffset[screen_row - 1]
+-							+ (int)Columns - 2) == 2))
++							+ (int)Columns - 2,
++				     LineOffset[screen_row] + screen_Columns)
++									== 2))
+ #endif
+ 		   )
+ 		{
+@@ -4787,6 +4906,10 @@
+ {
+     unsigned	    off_from;
+     unsigned	    off_to;
++#ifdef FEAT_MBYTE
++    unsigned	    max_off_from;
++    unsigned	    max_off_to;
++#endif
+     int		    col = 0;
+ #if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_VERTSPLIT)
+     int		    hl;
+@@ -4813,6 +4936,10 @@
+ 
+     off_from = (unsigned)(current_ScreenLine - ScreenLines);
+     off_to = LineOffset[row] + coloff;
++#ifdef FEAT_MBYTE
++    max_off_from = off_from + screen_Columns;
++    max_off_to = LineOffset[row] + screen_Columns;
++#endif
+ 
+ #ifdef FEAT_RIGHTLEFT
+     if (rlflag)
+@@ -4847,7 +4974,7 @@
+     {
+ #ifdef FEAT_MBYTE
+ 	if (has_mbyte && (col + 1 < endcol))
+-	    char_cells = (*mb_off2cells)(off_from);
++	    char_cells = (*mb_off2cells)(off_from, max_off_from);
+ 	else
+ 	    char_cells = 1;
+ #endif
+@@ -4924,7 +5051,7 @@
+ 		 * ScreenLinesUC[] is sufficient. */
+ 		if (char_cells == 1
+ 			&& col + 1 < endcol
+-			&& (*mb_off2cells)(off_to) > 1)
++			&& (*mb_off2cells)(off_to, max_off_to) > 1)
+ 		{
+ 		    /* Writing a single-cell character over a double-cell
+ 		     * character: need to redraw the next cell. */
+@@ -4933,8 +5060,8 @@
+ 		}
+ 		else if (char_cells == 2
+ 			&& col + 2 < endcol
+-			&& (*mb_off2cells)(off_to) == 1
+-			&& (*mb_off2cells)(off_to + 1) > 1)
++			&& (*mb_off2cells)(off_to, max_off_to) == 1
++			&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)
+ 		{
+ 		    /* Writing the second half of a double-cell character over
+ 		     * a double-cell character: need to redraw the second
+@@ -4953,10 +5080,10 @@
+ 	     * char over the left halve of an existing one. */
+ 	    if (has_mbyte && col + char_cells == endcol
+ 		    && ((char_cells == 1
+-			    && (*mb_off2cells)(off_to) > 1)
++			    && (*mb_off2cells)(off_to, max_off_to) > 1)
+ 			|| (char_cells == 2
+-			    && (*mb_off2cells)(off_to) == 1
+-			    && (*mb_off2cells)(off_to + 1) > 1)))
++			    && (*mb_off2cells)(off_to, max_off_to) == 1
++			    && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
+ 		clear_next = TRUE;
+ #endif
+ 
+@@ -5096,10 +5223,11 @@
+ 			/* find previous character by counting from first
+ 			 * column and get its width. */
+ 			unsigned off = LineOffset[row];
++			unsigned max_off = LineOffset[row] + screen_Columns;
+ 
+ 			while (off < off_to)
+ 			{
+-			    prev_cells = (*mb_off2cells)(off);
++			    prev_cells = (*mb_off2cells)(off, max_off);
+ 			    off += prev_cells;
+ 			}
+ 		    }
+@@ -5285,7 +5413,7 @@
+ static int skip_status_match_char __ARGS((expand_T *xp, char_u *s));
+ 
+ /*
+- * Get the lenght of an item as it will be shown in the status line.
++ * Get the length of an item as it will be shown in the status line.
+  */
+     static int
+ status_match_len(xp, s)
+@@ -5351,7 +5479,7 @@
+     int		row;
+     char_u	*buf;
+     int		len;
+-    int		clen;		/* lenght in screen cells */
++    int		clen;		/* length in screen cells */
+     int		fillchar;
+     int		attr;
+     int		i;
+@@ -6103,6 +6231,7 @@
+     char_u	*ptr = text;
+     int		c;
+ #ifdef FEAT_MBYTE
++    unsigned	max_off;
+     int		mbyte_blen = 1;
+     int		mbyte_cells = 1;
+     int		u8c = 0;
+@@ -6119,8 +6248,12 @@
+ 	return;
+ 
+     off = LineOffset[row] + col;
+-    while (*ptr != NUL && col < screen_Columns
+-				      && (len < 0 || (int)(ptr - text) < len))
++#ifdef FEAT_MBYTE
++    max_off = LineOffset[row] + screen_Columns;
++#endif
++    while (col < screen_Columns
++	    && (len < 0 || (int)(ptr - text) < len)
++	    && *ptr != NUL)
+     {
+ 	c = *ptr;
+ #ifdef FEAT_MBYTE
+@@ -6143,6 +6276,7 @@
+ 		else
+ 		    u8c = utfc_ptr2char(ptr, u8cc);
+ 		mbyte_cells = utf_char2cells(u8c);
++# ifdef UNICODE16
+ 		/* Non-BMP character: display as ? or fullwidth ?. */
+ 		if (u8c >= 0x10000)
+ 		{
+@@ -6150,6 +6284,7 @@
+ 		    if (attr == 0)
+ 			attr = hl_attr(HLF_8);
+ 		}
++# endif
+ # ifdef FEAT_ARABIC
+ 		if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
+ 		{
+@@ -6241,19 +6376,19 @@
+ 	    else if (has_mbyte
+ 		    && (len < 0 ? ptr[mbyte_blen] == NUL
+ 					     : ptr + mbyte_blen >= text + len)
+-		    && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1)
++		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
+ 			|| (mbyte_cells == 2
+-			    && (*mb_off2cells)(off) == 1
+-			    && (*mb_off2cells)(off + 1) > 1)))
++			    && (*mb_off2cells)(off, max_off) == 1
++			    && (*mb_off2cells)(off + 1, max_off) > 1)))
+ 		clear_next_cell = TRUE;
+ 
+ 	    /* Make sure we never leave a second byte of a double-byte behind,
+ 	     * it confuses mb_off2cells(). */
+ 	    if (enc_dbcs
+-		    && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1)
++		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
+ 			|| (mbyte_cells == 2
+-			    && (*mb_off2cells)(off) == 1
+-			    && (*mb_off2cells)(off + 1) > 1)))
++			    && (*mb_off2cells)(off, max_off) == 1
++			    && (*mb_off2cells)(off + 1, max_off) > 1)))
+ 		ScreenLines[off + mbyte_blen] = 0;
+ #endif
+ 	    ScreenLines[off] = c;
+@@ -6318,7 +6453,7 @@
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+ /*
+- * Prepare for 'searchhl' highlighting.
++ * Prepare for 'hlsearch' highlighting.
+  */
+     static void
+ start_search_hl()
+@@ -6331,7 +6466,7 @@
+ }
+ 
+ /*
+- * Clean up for 'searchhl' highlighting.
++ * Clean up for 'hlsearch' highlighting.
+  */
+     static void
+ end_search_hl()
+@@ -6351,18 +6486,28 @@
+     win_T	*wp;
+     linenr_T	lnum;
+ {
+-    match_T	*shl;		/* points to search_hl or match_hl */
++    matchitem_T *cur;		/* points to the match list */
++    match_T	*shl;		/* points to search_hl or a match */
++    int		shl_flag;	/* flag to indicate whether search_hl
++				   has been processed or not */
+     int		n;
+-    int		i;
+ 
+     /*
+      * When using a multi-line pattern, start searching at the top
+      * of the window or just after a closed fold.
+-     * Do this both for search_hl and match_hl[3].
++     * Do this both for search_hl and the match list.
+      */
+-    for (i = 3; i >= 0; --i)
++    cur = wp->w_match_head;
++    shl_flag = FALSE;
++    while (cur != NULL || shl_flag == FALSE)
+     {
+-	shl = (i == 3) ? &search_hl : &match_hl[i];
++	if (shl_flag == FALSE)
++	{
++	    shl = &search_hl;
++	    shl_flag = TRUE;
++	}
++	else
++	    shl = &cur->hl;
+ 	if (shl->rm.regprog != NULL
+ 		&& shl->lnum == 0
+ 		&& re_multiline(shl->rm.regprog))
+@@ -6397,11 +6542,13 @@
+ 		}
+ 	    }
+ 	}
++	if (shl != &search_hl && cur != NULL)
++	    cur = cur->next;
+     }
+ }
+ 
+ /*
+- * Search for a next 'searchl' or ":match" match.
++ * Search for a next 'hlsearch' or match.
+  * Uses shl->buf.
+  * Sets shl->lnum and shl->rm contents.
+  * Note: Assumes a previous match is always before "lnum", unless
+@@ -6411,7 +6558,7 @@
+     static void
+ next_search_hl(win, shl, lnum, mincol)
+     win_T	*win;
+-    match_T	*shl;		/* points to search_hl or match_hl */
++    match_T	*shl;		/* points to search_hl or a match */
+     linenr_T	lnum;
+     colnr_T	mincol;		/* minimal column for a match */
+ {
+@@ -6479,7 +6626,7 @@
+ 	    /* Error while handling regexp: stop using this regexp. */
+ 	    if (shl == &search_hl)
+ 	    {
+-		/* don't free the regprog in match_hl[], it's a copy */
++		/* don't free regprog in the match list, it's a copy */
+ 		vim_free(shl->rm.regprog);
+ 		no_hlsearch = TRUE;
+ 	    }
+@@ -6827,6 +6974,9 @@
+ {
+     int		r, c;
+     int		off;
++#ifdef FEAT_MBYTE
++    int		max_off;
++#endif
+ 
+     /* Can't use ScreenLines unless initialized */
+     if (ScreenLines == NULL)
+@@ -6837,10 +6987,13 @@
+     for (r = row; r < row + height; ++r)
+     {
+ 	off = LineOffset[r];
++#ifdef FEAT_MBYTE
++	max_off = off + screen_Columns;
++#endif
+ 	for (c = col; c < col + width; ++c)
+ 	{
+ #ifdef FEAT_MBYTE
+-	    if (enc_dbcs != 0 && dbcs_off2cells(off + c) > 1)
++	    if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
+ 	    {
+ 		screen_char_2(off + c, r, c);
+ 		++c;
+@@ -6850,7 +7003,7 @@
+ 	    {
+ 		screen_char(off + c, r, c);
+ #ifdef FEAT_MBYTE
+-		if (utf_off2cells(off + c) > 1)
++		if (utf_off2cells(off + c, max_off) > 1)
+ 		    ++c;
+ #endif
+ 	    }
+diff -Naur vim71.orig/src/search.c vim71/src/search.c
+--- vim71.orig/src/search.c	2007-05-07 19:42:02.000000000 +0000
++++ vim71/src/search.c	2007-12-08 20:34:51.000000000 +0000
+@@ -101,7 +101,6 @@
+ static char_u	    *mr_pattern = NULL;	/* pattern used by search_regcomp() */
+ #ifdef FEAT_RIGHTLEFT
+ static int	    mr_pattern_alloced = FALSE; /* mr_pattern was allocated */
+-static char_u	    *reverse_text __ARGS((char_u *s));
+ #endif
+ 
+ #ifdef FEAT_FIND_ID
+@@ -228,12 +227,12 @@
+     return mr_pattern;
+ }
+ 
+-#ifdef FEAT_RIGHTLEFT
++#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
+ /*
+  * Reverse text into allocated memory.
+  * Returns the allocated string, NULL when out of memory.
+  */
+-    static char_u *
++    char_u *
+ reverse_text(s)
+     char_u *s;
+ {
+@@ -573,8 +572,12 @@
+ 	/*
+ 	 * Start searching in current line, unless searching backwards and
+ 	 * we're in column 0.
++	 * If we are searching backwards, in column 0, and not including the
++	 * current position, gain some efficiency by skipping back a line.
++	 * Otherwise begin the search in the current line.
+ 	 */
+-	if (dir == BACKWARD && start_pos.col == 0)
++	if (dir == BACKWARD && start_pos.col == 0
++					     && (options & SEARCH_START) == 0)
+ 	{
+ 	    lnum = pos->lnum - 1;
+ 	    at_first_line = FALSE;
+@@ -1894,7 +1897,7 @@
+     }
+ 
+ #ifdef FEAT_RIGHTLEFT
+-    /* This is just guessing: when 'rightleft' is set, search for a maching
++    /* This is just guessing: when 'rightleft' is set, search for a matching
+      * paren/brace in the other direction. */
+     if (curwin->w_p_rl && vim_strchr((char_u *)"()[]{}<>", initc) != NULL)
+ 	backwards = !backwards;
+@@ -2124,6 +2127,9 @@
+ 			else if (!backwards)
+ 			    inquote = TRUE;
+ 		    }
++
++		    /* ml_get() only keeps one line, need to get linep again */
++		    linep = ml_get(pos.lnum);
+ 		}
+ 	    }
+ 	}
+@@ -2795,7 +2801,7 @@
+ 	i = inc_cursor();
+ 	if (i == -1 || (i >= 1 && last_line)) /* started at last char in file */
+ 	    return FAIL;
+-	if (i == 1 && eol && count == 0)      /* started at last char in line */
++	if (i >= 1 && eol && count == 0)      /* started at last char in line */
+ 	    return OK;
+ 
+ 	/*
+@@ -3600,13 +3606,16 @@
+     {
+ 	oap->start = start_pos;
+ 	oap->motion_type = MCHAR;
++	oap->inclusive = FALSE;
+ 	if (sol)
+-	{
+ 	    incl(&curwin->w_cursor);
+-	    oap->inclusive = FALSE;
+-	}
+-	else
++	else if (lt(start_pos, curwin->w_cursor))
++	    /* Include the character under the cursor. */
+ 	    oap->inclusive = TRUE;
++	else
++	    /* End is before the start (no text in between <>, [], etc.): don't
++	     * operate on any text. */
++	    curwin->w_cursor = start_pos;
+     }
+ 
+     return OK;
+@@ -3734,7 +3743,7 @@
+ 
+ 	if (in_html_tag(FALSE))
+ 	{
+-	    /* cursor on start tag, move to just after it */
++	    /* cursor on start tag, move to its '>' */
+ 	    while (*ml_get_cursor() != '>')
+ 		if (inc_cursor() < 0)
+ 		    break;
+@@ -3838,7 +3847,7 @@
+ 	/* Exclude the start tag. */
+ 	curwin->w_cursor = start_pos;
+ 	while (inc_cursor() >= 0)
+-	    if (*ml_get_cursor() == '>' && lt(curwin->w_cursor, end_pos))
++	    if (*ml_get_cursor() == '>')
+ 	    {
+ 		inc_cursor();
+ 		start_pos = curwin->w_cursor;
+@@ -3860,7 +3869,11 @@
+ #ifdef FEAT_VISUAL
+     if (VIsual_active)
+     {
+-	if (*p_sel == 'e')
++	/* If the end is before the start there is no text between tags, select
++	 * the char under the cursor. */
++	if (lt(end_pos, start_pos))
++	    curwin->w_cursor = start_pos;
++	else if (*p_sel == 'e')
+ 	    ++curwin->w_cursor.col;
+ 	VIsual = start_pos;
+ 	VIsual_mode = 'v';
+@@ -3872,7 +3885,15 @@
+     {
+ 	oap->start = start_pos;
+ 	oap->motion_type = MCHAR;
+-	oap->inclusive = TRUE;
++	if (lt(end_pos, start_pos))
++	{
++	    /* End is before the start: there is no text between tags; operate
++	     * on an empty area. */
++	    curwin->w_cursor = start_pos;
++	    oap->inclusive = FALSE;
++	}
++	else
++	    oap->inclusive = TRUE;
+     }
+     retval = OK;
+ 
+diff -Naur vim71.orig/src/spell.c vim71/src/spell.c
+--- vim71.orig/src/spell.c	2007-05-07 19:48:38.000000000 +0000
++++ vim71/src/spell.c	2007-12-08 20:34:51.000000000 +0000
+@@ -7829,7 +7829,7 @@
+ # if (_MSC_VER <= 1200)
+ /* This line is required for VC6 without the service pack.  Also see the
+  * matching #pragma below. */
+-/* # pragma optimize("", off) */
++ #  pragma optimize("", off)
+ # endif
+ #endif
+ 
+@@ -7859,7 +7859,7 @@
+ 
+ #ifdef _MSC_VER
+ # if (_MSC_VER <= 1200)
+-/* # pragma optimize("", on) */
++ #  pragma optimize("", on)
+ # endif
+ #endif
+ 
+@@ -12182,7 +12182,9 @@
+ 	    {
+ 		n = mb_cptr2len(p);
+ 		c = mb_ptr2char(p);
+-		if (!soundfold && !spell_iswordp(p + n, curbuf))
++		if (p[n] == NUL)
++		    c2 = NUL;
++		else if (!soundfold && !spell_iswordp(p + n, curbuf))
+ 		    c2 = c; /* don't swap non-word char */
+ 		else
+ 		    c2 = mb_ptr2char(p + n);
+@@ -12190,12 +12192,21 @@
+ 	    else
+ #endif
+ 	    {
+-		if (!soundfold && !spell_iswordp(p + 1, curbuf))
++		if (p[1] == NUL)
++		    c2 = NUL;
++		else if (!soundfold && !spell_iswordp(p + 1, curbuf))
+ 		    c2 = c; /* don't swap non-word char */
+ 		else
+ 		    c2 = p[1];
+ 	    }
+ 
++	    /* When the second character is NUL we can't swap. */
++	    if (c2 == NUL)
++	    {
++		sp->ts_state = STATE_REP_INI;
++		break;
++	    }
++
+ 	    /* When characters are identical, swap won't do anything.
+ 	     * Also get here if the second char is not a word character. */
+ 	    if (c == c2)
+diff -Naur vim71.orig/src/structs.h vim71/src/structs.h
+--- vim71.orig/src/structs.h	2007-05-07 19:50:49.000000000 +0000
++++ vim71/src/structs.h	2007-12-08 20:34:53.000000000 +0000
+@@ -278,6 +278,9 @@
+     linenr_T	ue_lcount;	/* linecount when u_save called */
+     char_u	**ue_array;	/* array of lines in undo block */
+     long	ue_size;	/* number of lines in ue_array */
++#ifdef U_DEBUG
++    int		ue_magic;	/* magic number to check allocation */
++#endif
+ };
+ 
+ struct u_header
+@@ -300,6 +303,9 @@
+     visualinfo_T uh_visual;	/* Visual areas before undo/after redo */
+ #endif
+     time_t	uh_time;	/* timestamp when the change was made */
++#ifdef U_DEBUG
++    int		uh_magic;	/* magic number to check allocation */
++#endif
+ };
+ 
+ /* values for uh_flags */
+@@ -1453,6 +1459,7 @@
+ #ifdef FEAT_MBYTE
+     char_u	*b_start_fenc;	/* 'fileencoding' when edit started or NULL */
+     int		b_bad_char;	/* "++bad=" argument when edit started or 0 */
++    int		b_start_bomb;	/* 'bomb' when it was read */
+ #endif
+ 
+ #ifdef FEAT_EVAL
+@@ -1694,6 +1701,41 @@
+ #define FR_COL	2	/* frame with a column of windows */
+ 
+ /*
++ * Struct used for highlighting 'hlsearch' matches, matches defined by
++ * ":match" and matches defined by match functions.
++ * For 'hlsearch' there is one pattern for all windows.  For ":match" and the
++ * match functions there is a different pattern for each window.
++ */
++typedef struct
++{
++    regmmatch_T	rm;	/* points to the regexp program; contains last found
++			   match (may continue in next line) */
++    buf_T	*buf;	/* the buffer to search for a match */
++    linenr_T	lnum;	/* the line to search for a match */
++    int		attr;	/* attributes to be used for a match */
++    int		attr_cur; /* attributes currently active in win_line() */
++    linenr_T	first_lnum;	/* first lnum to search for multi-line pat */
++    colnr_T	startcol; /* in win_line() points to char where HL starts */
++    colnr_T	endcol;	 /* in win_line() points to char where HL ends */
++} match_T;
++
++/*
++ * matchitem_T provides a linked list for storing match items for ":match" and
++ * the match functions.
++ */
++typedef struct matchitem matchitem_T;
++struct matchitem
++{
++    matchitem_T	*next;
++    int		id;	    /* match ID */
++    int		priority;   /* match priority */
++    char_u	*pattern;   /* pattern to highlight */
++    int		hlg_id;	    /* highlight group ID */
++    regmmatch_T	match;	    /* regexp program for pattern */
++    match_T	hl;	    /* struct for doing the actual highlighting */
++};
++
++/*
+  * Structure which contains all information that belongs to a window
+  *
+  * All row numbers are relative to the start of the window, except w_winrow.
+@@ -1934,9 +1976,8 @@
+ #endif
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+-    regmmatch_T	w_match[3];	    /* regexp programs for ":match" */
+-    char_u	*(w_match_pat[3]);  /* patterns for ":match" */
+-    int		w_match_id[3];	    /* highlight IDs for ":match" */
++    matchitem_T	*w_match_head;		/* head of match list */
++    int		w_next_match_id;	/* next match ID */
+ #endif
+ 
+     /*
+diff -Naur vim71.orig/src/syntax.c vim71/src/syntax.c
+--- vim71.orig/src/syntax.c	2007-05-07 19:42:55.000000000 +0000
++++ vim71/src/syntax.c	2007-12-08 20:34:53.000000000 +0000
+@@ -66,8 +66,10 @@
+ #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data)))
+ 
+ #ifdef FEAT_CMDL_COMPL
+-static int include_default = FALSE;	/* include "default" for expansion */
+-static int include_link = FALSE;	/* include "link" for expansion */
++/* Flags to indicate an additional string for highlight name completion. */
++static int include_none = 0;	/* when 1 include "None" */
++static int include_default = 0;	/* when 1 include "default" */
++static int include_link = 0;	/* when 2 include "link" and "clear" */
+ #endif
+ 
+ /*
+@@ -277,7 +279,8 @@
+  */
+ typedef struct state_item
+ {
+-    int		si_idx;			/* index of syntax pattern */
++    int		si_idx;			/* index of syntax pattern or
++					   KEYWORD_IDX */
+     int		si_id;			/* highlight group ID for keywords */
+     int		si_trans_id;		/* idem, transparancy removed */
+     int		si_m_lnum;		/* lnum of the match */
+@@ -835,9 +838,18 @@
+ 			    current_lnum = end_lnum;
+ 			    break;
+ 			}
+-			spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]);
+-			found_flags = spp->sp_flags;
+-			found_match_idx = spp->sp_sync_idx;
++			if (cur_si->si_idx < 0)
++			{
++			    /* Cannot happen? */
++			    found_flags = 0;
++			    found_match_idx = KEYWORD_IDX;
++			}
++			else
++			{
++			    spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]);
++			    found_flags = spp->sp_flags;
++			    found_match_idx = spp->sp_sync_idx;
++			}
+ 			found_current_lnum = current_lnum;
+ 			found_current_col = current_col;
+ 			found_m_endpos = cur_si->si_m_endpos;
+@@ -1725,6 +1737,13 @@
+ {
+     int	    attr = 0;
+ 
++    if (can_spell != NULL)
++	/* Default: Only do spelling when there is no @Spell cluster or when
++	 * ":syn spell toplevel" was used. */
++	*can_spell = syn_buf->b_syn_spell == SYNSPL_DEFAULT
++		    ? (syn_buf->b_spell_cluster_id == 0)
++		    : (syn_buf->b_syn_spell == SYNSPL_TOP);
++
+     /* check for out of memory situation */
+     if (syn_buf->b_sst_array == NULL)
+ 	return 0;
+@@ -2524,6 +2543,10 @@
+     stateitem_T	*sip = &CUR_STATE(idx);
+     synpat_T	*spp;
+ 
++    /* This should not happen... */
++    if (sip->si_idx < 0)
++	return;
++
+     spp = &(SYN_ITEMS(syn_buf)[sip->si_idx]);
+     if (sip->si_flags & HL_MATCH)
+ 	sip->si_id = spp->sp_syn_match_id;
+@@ -2639,6 +2662,10 @@
+     lpos_T	end_endpos;
+     int		end_idx;
+ 
++    /* return quickly for a keyword */
++    if (sip->si_idx < 0)
++	return;
++
+     /* Don't update when it's already done.  Can be a match of an end pattern
+      * that started in a previous line.  Watch out: can also be a "keepend"
+      * from a containing item. */
+@@ -2751,6 +2778,10 @@
+     char_u	*line;
+     int		had_match = FALSE;
+ 
++    /* just in case we are invoked for a keyword */
++    if (idx < 0)
++	return;
++
+     /*
+      * Check for being called with a START pattern.
+      * Can happen with a match that continues to the next line, because it
+@@ -3323,6 +3354,7 @@
+     {
+ 	vim_free(SYN_ITEMS(buf)[i].sp_cont_list);
+ 	vim_free(SYN_ITEMS(buf)[i].sp_next_list);
++	vim_free(SYN_ITEMS(buf)[i].sp_syn.cont_in_list);
+     }
+ }
+ 
+@@ -4460,8 +4492,8 @@
+     current_syn_inc_tag = ++running_syn_inc_tag;
+     prev_toplvl_grp = curbuf->b_syn_topgrp;
+     curbuf->b_syn_topgrp = sgl_id;
+-    if (source ? do_source(eap->arg, FALSE, FALSE) == FAIL
+-				: source_runtime(eap->arg, DOSO_NONE) == FAIL)
++    if (source ? do_source(eap->arg, FALSE, DOSO_NONE) == FAIL
++				: source_runtime(eap->arg, TRUE) == FAIL)
+ 	EMSG2(_(e_notopen), eap->arg);
+     curbuf->b_syn_topgrp = prev_toplvl_grp;
+     current_syn_inc_tag = prev_syn_inc_tag;
+@@ -5956,8 +5988,8 @@
+ {
+     return (buf->b_syn_patterns.ga_len != 0
+ 	    || buf->b_syn_clusters.ga_len != 0
+-	    || curbuf->b_keywtab.ht_used > 0
+-	    || curbuf->b_keywtab_ic.ht_used > 0);
++	    || buf->b_keywtab.ht_used > 0
++	    || buf->b_keywtab_ic.ht_used > 0);
+ }
+ 
+ #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+@@ -5968,6 +6000,29 @@
+     EXP_CASE	    /* expand ":syn case" arguments */
+ } expand_what;
+ 
++/*
++ * Reset include_link, include_default, include_none to 0.
++ * Called when we are done expanding.
++ */
++    void
++reset_expand_highlight()
++{
++    include_link = include_default = include_none = 0;
++}
++
++/*
++ * Handle command line completion for :match and :echohl command: Add "None"
++ * as highlight group.
++ */
++    void
++set_context_in_echohl_cmd(xp, arg)
++    expand_T	*xp;
++    char_u	*arg;
++{
++    xp->xp_context = EXPAND_HIGHLIGHT;
++    xp->xp_pattern = arg;
++    include_none = 1;
++}
+ 
+ /*
+  * Handle command line completion for :syntax command.
+@@ -5983,8 +6038,8 @@
+     xp->xp_context = EXPAND_SYNTAX;
+     expand_what = EXP_SUBCMD;
+     xp->xp_pattern = arg;
+-    include_link = FALSE;
+-    include_default = FALSE;
++    include_link = 0;
++    include_default = 0;
+ 
+     /* (part of) subcommand already typed */
+     if (*arg != NUL)
+@@ -8479,7 +8534,7 @@
+ syn_id2name(id)
+     int		id;
+ {
+-    if (id <= 0 || id >= highlight_ga.ga_len)
++    if (id <= 0 || id > highlight_ga.ga_len)
+ 	return (char_u *)"";
+     return HL_TABLE()[id - 1].sg_name;
+ }
+@@ -8949,7 +9004,7 @@
+     return OK;
+ }
+ 
+-#ifdef FEAT_CMDL_COMPL
++#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ 
+ static void highlight_list __ARGS((void));
+ static void highlight_list_two __ARGS((int cnt, int attr));
+@@ -8967,8 +9022,8 @@
+     /* Default: expand group names */
+     xp->xp_context = EXPAND_HIGHLIGHT;
+     xp->xp_pattern = arg;
+-    include_link = TRUE;
+-    include_default = TRUE;
++    include_link = 2;
++    include_default = 1;
+ 
+     /* (part of) subcommand already typed */
+     if (*arg != NUL)
+@@ -8976,7 +9031,7 @@
+ 	p = skiptowhite(arg);
+ 	if (*p != NUL)			/* past "default" or group name */
+ 	{
+-	    include_default = FALSE;
++	    include_default = 0;
+ 	    if (STRNCMP("default", arg, p - arg) == 0)
+ 	    {
+ 		arg = skipwhite(p);
+@@ -8985,7 +9040,7 @@
+ 	    }
+ 	    if (*p != NUL)			/* past group name */
+ 	    {
+-		include_link = FALSE;
++		include_link = 0;
+ 		if (arg[1] == 'i' && arg[0] == 'N')
+ 		    highlight_list();
+ 		if (STRNCMP("link", arg, p - arg) == 0
+@@ -9045,31 +9100,25 @@
+     expand_T	*xp;
+     int		idx;
+ {
+-    if (idx == highlight_ga.ga_len
+ #ifdef FEAT_CMDL_COMPL
+-	    && include_link
+-#endif
+-	    )
++    if (idx == highlight_ga.ga_len && include_none != 0)
++	return (char_u *)"none";
++    if (idx == highlight_ga.ga_len + include_none && include_default != 0)
++	return (char_u *)"default";
++    if (idx == highlight_ga.ga_len + include_none + include_default
++							 && include_link != 0)
+ 	return (char_u *)"link";
+-    if (idx == highlight_ga.ga_len + 1
+-#ifdef FEAT_CMDL_COMPL
+-	    && include_link
+-#endif
+-	    )
++    if (idx == highlight_ga.ga_len + include_none + include_default + 1
++							 && include_link != 0)
+ 	return (char_u *)"clear";
+-    if (idx == highlight_ga.ga_len + 2
+-#ifdef FEAT_CMDL_COMPL
+-	    && include_default
+ #endif
+-	    )
+-	return (char_u *)"default";
+     if (idx < 0 || idx >= highlight_ga.ga_len)
+ 	return NULL;
+     return HL_TABLE()[idx].sg_name;
+ }
+ #endif
+ 
+-#ifdef FEAT_GUI
++#if defined(FEAT_GUI) || defined(PROTO)
+ /*
+  * Free all the highlight group fonts.
+  * Used when quitting for systems which need it.
+diff -Naur vim71.orig/src/term.c vim71/src/term.c
+--- vim71.orig/src/term.c	2007-05-07 19:39:11.000000000 +0000
++++ vim71/src/term.c	2007-12-08 20:34:51.000000000 +0000
+@@ -4809,6 +4809,8 @@
+ 	    if (num_bytes == -1)
+ 		return -1;
+ 	    current_tab = (int)bytes[0];
++	    if (current_tab == 255)	/* -1 in a byte gives 255 */
++		current_tab = -1;
+ 	    slen += num_bytes;
+ 	}
+ 	else if (key_name[0] == (int)KS_TABMENU)
+diff -Naur vim71.orig/src/termlib.c vim71/src/termlib.c
+--- vim71.orig/src/termlib.c	2007-05-07 19:39:49.000000000 +0000
++++ vim71/src/termlib.c	2007-12-08 20:34:51.000000000 +0000
+@@ -191,7 +191,7 @@
+ 	    lbuf[0] == '\t' &&
+ 	    lbuf[1] == ':')
+ 	{
+-	    strcpy(lbuf, lbuf+2);
++	    mch_memmove(lbuf, lbuf + 2, strlen(lbuf + 2) + 1);
+ 	    llen -= 2;
+ 	}
+ 	if (lbuf[llen-2] == '\\')		/* and continuations */
+diff -Naur vim71.orig/src/testdir/Makefile vim71/src/testdir/Makefile
+--- vim71.orig/src/testdir/Makefile	2006-04-30 11:08:01.000000000 +0000
++++ vim71/src/testdir/Makefile	2007-12-08 20:34:52.000000000 +0000
+@@ -1,9 +1,13 @@
+ #
+-# Makefile to run al tests for Vim
++# Makefile to run all tests for Vim
+ #
+ 
+ VIMPROG = ../vim
+ 
++# Uncomment this line for using valgrind.
++# The output goes into a file "valgrind.$PID" (sorry, no test number).
++# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=15 --logfile=valgrind
++
+ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
+ 		test7.out test8.out test9.out test10.out test11.out \
+ 		test12.out  test13.out test14.out test15.out test17.out \
+@@ -15,7 +19,8 @@
+ 		test43.out test44.out test45.out test46.out test47.out \
+ 		test48.out test49.out test51.out test52.out test53.out \
+ 		test54.out test55.out test56.out test57.out test58.out \
+-		test59.out test60.out test61.out test62.out
++		test59.out test60.out test61.out test62.out test63.out \
++		test64.out
+ 
+ SCRIPTS_GUI = test16.out
+ 
+@@ -34,11 +39,11 @@
+ $(SCRIPTS) $(SCRIPTS_GUI): $(VIMPROG)
+ 
+ clean:
+-	-rm -rf *.out *.failed *.rej *.orig test.log tiny.vim small.vim mbyte.vim test.ok X* viminfo
++	-rm -rf *.out *.failed *.rej *.orig test.log tiny.vim small.vim mbyte.vim test.ok X* valgrind.pid* viminfo
+ 
+ test1.out: test1.in
+ 	-rm -f $*.failed tiny.vim small.vim mbyte.vim test.ok X* viminfo
+-	$(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in
++	$(VALGRIND) $(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in
+ 	@/bin/sh -c "if diff test.out $*.ok; \
+ 		then mv -f test.out $*.out; \
+ 		else echo; \
+@@ -51,7 +56,7 @@
+ 	cp $*.ok test.ok
+ 	# Sleep a moment to avoid that the xterm title is messed up
+ 	@-sleep .2
+-	-$(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in
++	-$(VALGRIND) $(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in
+ 	@/bin/sh -c "if test -f test.out; then\
+ 		  if diff test.out $*.ok; \
+ 		  then mv -f test.out $*.out; \
+@@ -61,5 +66,9 @@
+ 		fi"
+ 	-rm -rf X* test.ok viminfo
+ 
++test49.out: test49.vim
++
++test60.out: test60.vim
++
+ nolog:
+ 	-echo Test results: >test.log
+diff -Naur vim71.orig/src/testdir/test14.in vim71/src/testdir/test14.in
+--- vim71.orig/src/testdir/test14.in	2004-06-07 14:32:05.000000000 +0000
++++ vim71/src/testdir/test14.in	2007-12-08 20:34:52.000000000 +0000
+@@ -18,6 +18,7 @@
+ : let tt = "o\<C-V>65\<C-V>x42\<C-V>o103 \<C-V>33a\<C-V>xfg\<C-V>o78\<Esc>"
+ :endif
+ :exe "normal " . tt
++:unlet tt
+ :.w >>test.out
+ :set vb
+ /^Piece
+diff -Naur vim71.orig/src/testdir/test26.in vim71/src/testdir/test26.in
+--- vim71.orig/src/testdir/test26.in	2004-06-07 14:32:05.000000000 +0000
++++ vim71/src/testdir/test26.in	2007-12-08 20:34:52.000000000 +0000
+@@ -37,6 +37,7 @@
+ :    endif
+ :  endif
+ :endwhile
++:unlet i j
+ :'t,$w! test.out
+ :qa!
+ ENDTEST
+diff -Naur vim71.orig/src/testdir/test34.in vim71/src/testdir/test34.in
+--- vim71.orig/src/testdir/test34.in	2006-04-30 13:33:24.000000000 +0000
++++ vim71/src/testdir/test34.in	2007-12-08 20:34:52.000000000 +0000
+@@ -52,7 +52,15 @@
+ ---*---
+ (one
+ (two
+-[(one again:$-5,$wq! test.out
++[(one again:$-5,$w! test.out
++:delfunc Table
++:delfunc Compute
++:delfunc Expr1
++:delfunc Expr2
++:delfunc ListItem
++:delfunc ListReset
++:unlet retval counter
++:q!
+ ENDTEST
+ 
+ here
+diff -Naur vim71.orig/src/testdir/test45.in vim71/src/testdir/test45.in
+--- vim71.orig/src/testdir/test45.in	2004-06-07 14:32:05.000000000 +0000
++++ vim71/src/testdir/test45.in	2007-12-08 20:34:52.000000000 +0000
+@@ -55,6 +55,7 @@
+ /kk$
+ :call append("$", foldlevel("."))
+ :/^last/+1,$w! test.out
++:delfun Flvl
+ :qa!
+ ENDTEST
+ 
+diff -Naur vim71.orig/src/testdir/test47.in vim71/src/testdir/test47.in
+--- vim71.orig/src/testdir/test47.in	2004-06-07 14:32:05.000000000 +0000
++++ vim71/src/testdir/test47.in	2007-12-08 20:34:52.000000000 +0000
+@@ -34,6 +34,7 @@
+ :call append("$", two)
+ :call append("$", three)
+ :$-2,$w! test.out
++:unlet one two three
+ :qa!
+ ENDTEST
+ 
+diff -Naur vim71.orig/src/testdir/test49.in vim71/src/testdir/test49.in
+--- vim71.orig/src/testdir/test49.in	2006-04-28 09:29:54.000000000 +0000
++++ vim71/src/testdir/test49.in	2007-12-08 20:34:52.000000000 +0000
+@@ -1,13 +1,29 @@
+ This is a test of the script language.
+ 
+ If after adding a new test, the test output doesn't appear properly in
+-test49.failed, try to add one ore more "G"s at the line before ENDTEST.
++test49.failed, try to add one ore more "G"s at the line ending in "test.out"
+ 
+ STARTTEST
+ :so small.vim
+ :se nocp nomore viminfo+=nviminfo
+ :so test49.vim
+-GGGGGGGGGG"rp:.-,$wq! test.out
++GGGGGGGGGGGGGG"rp:.-,$w! test.out
++:"
++:" make valgrind happy
++:redir => funclist
++:silent func
++:redir END
++:for line in split(funclist, "\n")
++:  let name = matchstr(line, 'function \zs[A-Z]\w*\ze(')
++:  if name != ''
++:    exe "delfunc " . name
++:  endif
++:endfor
++:for v in keys(g:)
++:  silent! exe "unlet " . v
++:endfor
++:unlet v
++:qa!
+ ENDTEST
+ 
+ Results of test49.vim:
+diff -Naur vim71.orig/src/testdir/test55.in vim71/src/testdir/test55.in
+--- vim71.orig/src/testdir/test55.in	2006-10-15 14:07:05.000000000 +0000
++++ vim71/src/testdir/test55.in	2007-12-08 20:34:52.000000000 +0000
+@@ -345,6 +345,10 @@
+ :endfun
+ :call Test(1, 2, [3, 4], {5: 6})  " This may take a while
+ :"
++:delfunc Test
++:unlet dict
++:call garbagecollect(1)
++:"
+ :/^start:/,$wq! test.out
+ ENDTEST
+ 
+diff -Naur vim71.orig/src/testdir/test56.in vim71/src/testdir/test56.in
+--- vim71.orig/src/testdir/test56.in	2006-09-03 14:28:41.000000000 +0000
++++ vim71/src/testdir/test56.in	2007-12-08 20:34:52.000000000 +0000
+@@ -17,5 +17,5 @@
+ fun s:DoNothing()
+   call append(line('$'), "nothing line")
+ endfun
+-nnoremap <buffer> _x	:call <SID>DoNothing()<bar>call <SID>DoLast()<cr>
++nnoremap <buffer> _x	:call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr>
+ end:
+diff -Naur vim71.orig/src/testdir/test58.in vim71/src/testdir/test58.in
+--- vim71.orig/src/testdir/test58.in	2006-04-03 18:24:04.000000000 +0000
++++ vim71/src/testdir/test58.in	2007-12-08 20:34:52.000000000 +0000
+@@ -86,6 +86,7 @@
+ :$put =str
+ `m]s:let [str, a] = spellbadword()
+ :$put =str
++:unlet str a
+ :"
+ :" Postponed prefixes
+ :call TestOne('2', '1')
+@@ -100,6 +101,10 @@
+ :" NOSLITSUGS
+ :call TestOne('8', '8')
+ :"
++:" clean up for valgrind
++:delfunc TestOne
++:set spl= enc=latin1
++:"
+ gg:/^test output:/,$wq! test.out
+ ENDTEST
+ 
+diff -Naur vim71.orig/src/testdir/test59.in vim71/src/testdir/test59.in
+--- vim71.orig/src/testdir/test59.in	2006-04-03 18:29:24.000000000 +0000
++++ vim71/src/testdir/test59.in	2007-12-08 20:34:52.000000000 +0000
+@@ -90,6 +90,7 @@
+ :$put =str
+ `m]s:let [str, a] = spellbadword()
+ :$put =str
++:unlet str a
+ :"
+ :" Postponed prefixes
+ :call TestOne('2', '1')
+@@ -101,6 +102,10 @@
+ :call TestOne('6', '6')
+ :call TestOne('7', '7')
+ :"
++:" clean up for valgrind
++:delfunc TestOne
++:set spl= enc=latin1
++:"
+ gg:/^test output:/,$wq! test.out
+ ENDTEST
+ 
+diff -Naur vim71.orig/src/testdir/test60.in vim71/src/testdir/test60.in
+--- vim71.orig/src/testdir/test60.in	2006-05-05 18:41:18.000000000 +0000
++++ vim71/src/testdir/test60.in	2007-12-08 20:34:52.000000000 +0000
+@@ -569,6 +569,9 @@
+     redir END
+ endfunction
+ :call TestExists()
++:delfunc TestExists
++:delfunc RunTest
++:delfunc TestFuncArg
+ :edit! test.out
+ :set ff=unix
+ :w
+diff -Naur vim71.orig/src/testdir/test60.vim vim71/src/testdir/test60.vim
+--- vim71.orig/src/testdir/test60.vim	2006-01-12 19:45:59.000000000 +0000
++++ vim71/src/testdir/test60.vim	2007-12-08 20:34:52.000000000 +0000
+@@ -94,4 +94,5 @@
+ else
+     echo "FAILED"
+ endif
++unlet str
+ 
+diff -Naur vim71.orig/src/testdir/test62.in vim71/src/testdir/test62.in
+--- vim71.orig/src/testdir/test62.in	2006-04-30 11:29:15.000000000 +0000
++++ vim71/src/testdir/test62.in	2007-12-08 20:34:52.000000000 +0000
+@@ -7,6 +7,7 @@
+ :let nr = tabpagenr()
+ :q
+ :call append(line('$'), 'tab page ' . nr)
++:unlet nr
+ :"
+ :" Open three tab pages and use ":tabdo"
+ :0tabnew
+@@ -23,6 +24,7 @@
+ :q!
+ :call append(line('$'), line1)
+ :call append(line('$'), line2)
++:unlet line1 line2
+ :"
+ :"
+ :/^Results/,$w! test.out
+diff -Naur vim71.orig/src/testdir/test63.in vim71/src/testdir/test63.in
+--- vim71.orig/src/testdir/test63.in	1970-01-01 00:00:00.000000000 +0000
++++ vim71/src/testdir/test63.in	2007-12-08 20:34:52.000000000 +0000
+@@ -0,0 +1,157 @@
++Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
++"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
++
++STARTTEST
++:so small.vim
++:" --- Check that "matcharg()" returns the correct group and pattern if a match
++:" --- is defined.
++:let @r = "*** Test 1: "
++:highlight MyGroup1 ctermbg=red
++:highlight MyGroup2 ctermbg=green
++:highlight MyGroup3 ctermbg=blue
++:match MyGroup1 /TODO/
++:2match MyGroup2 /FIXME/
++:3match MyGroup3 /XXX/
++:if matcharg(1) == ['MyGroup1', 'TODO'] && matcharg(2) == ['MyGroup2', 'FIXME'] && matcharg(3) == ['MyGroup3', 'XXX']
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:" --- Check that "matcharg()" returns an empty list if the argument is not 1,
++:" --- 2 or 3 (only 0 and 4 are tested).
++:let @r .= "*** Test 2: "
++:if matcharg(0) == [] && matcharg(4) == []
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:" --- Check that "matcharg()" returns ['', ''] if a match is not defined.
++:let @r .= "*** Test 3: "
++:match
++:2match
++:3match
++:if matcharg(1) == ['', ''] && matcharg(2) == ['', ''] && matcharg(3) == ['', '']
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:" --- Check that "matchadd()" and "getmatches()" agree on added matches and
++:" --- that default values apply.
++:let @r .= "*** Test 4: "
++:let m1 = matchadd("MyGroup1", "TODO")
++:let m2 = matchadd("MyGroup2", "FIXME", 42)
++:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
++:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:" --- Check that "matchdelete()" deletes the matches defined in the previous
++:" --- test correctly.
++:let @r .= "*** Test 5: "
++:call matchdelete(m1)
++:call matchdelete(m2)
++:call matchdelete(m3)
++:unlet m1
++:unlet m2
++:unlet m3
++:if getmatches() == []
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:" --- Check that "matchdelete()" returns 0 if successful and otherwise -1.
++:let @r .= "*** Test 6: "
++:let m = matchadd("MyGroup1", "TODO")
++:let r1 = matchdelete(m)
++:let r2 = matchdelete(42)
++:if r1 == 0 && r2 == -1
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:unlet m
++:unlet r1
++:unlet r2
++:" --- Check that "clearmatches()" clears all matches defined by ":match" and
++:" --- "matchadd()".
++:let @r .= "*** Test 7: "
++:let m1 = matchadd("MyGroup1", "TODO")
++:let m2 = matchadd("MyGroup2", "FIXME", 42)
++:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
++:match MyGroup1 /COFFEE/
++:2match MyGroup2 /HUMPPA/
++:3match MyGroup3 /VIM/
++:call clearmatches()
++:if getmatches() == []
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:unlet m1
++:unlet m2
++:unlet m3
++:" --- Check that "setmatches()" restores a list of matches saved by
++:" --- "getmatches()" without changes. (Matches with equal priority must also
++:" --- remain in the same order.)
++:let @r .= "*** Test 8: "
++:let m1 = matchadd("MyGroup1", "TODO")
++:let m2 = matchadd("MyGroup2", "FIXME", 42)
++:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
++:match MyGroup1 /COFFEE/
++:2match MyGroup2 /HUMPPA/
++:3match MyGroup3 /VIM/
++:let ml = getmatches()
++:call clearmatches()
++:call setmatches(ml)
++:if getmatches() == ml
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:call clearmatches()
++:unlet m1
++:unlet m2
++:unlet m3
++:unlet ml
++:" --- Check that "setmatches()" will not add two matches with the same ID. The
++:" --- expected behaviour (for now) is to add the first match but not the
++:" --- second and to return 0 (even though it is a matter of debate whether
++:" --- this can be considered successful behaviour).
++:let @r .= "*** Test 9: "
++:let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])
++:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}] && r1 == 0
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:call clearmatches()
++:unlet r1
++:" --- Check that "setmatches()" returns 0 if successful and otherwise -1.
++:" --- (A range of valid and invalid input values are tried out to generate the
++:" --- return values.)
++:let @r .= "*** Test 10: "
++:let rs1 = setmatches([])
++:let rs2 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])
++:call clearmatches()
++:let rf1 = setmatches(0)
++:let rf2 = setmatches([0])
++:let rf3 = setmatches([{'wrong key': 'wrong value'}])
++:if rs1 == 0 && rs2 == 0 && rf1 == -1 && rf2 == -1 && rf3 == -1
++:  let @r .= "OK\n"
++:else
++:  let @r .= "FAILED\n"
++:endif
++:unlet rs1
++:unlet rs2
++:unlet rf1
++:unlet rf2
++:unlet rf3
++:highlight clear MyGroup1
++:highlight clear MyGroup2
++:highlight clear MyGroup3
++G"rp
++:/^Results/,$wq! test.out
++ENDTEST
++
++Results of test63:
+diff -Naur vim71.orig/src/testdir/test63.ok vim71/src/testdir/test63.ok
+--- vim71.orig/src/testdir/test63.ok	1970-01-01 00:00:00.000000000 +0000
++++ vim71/src/testdir/test63.ok	2007-12-08 20:34:51.000000000 +0000
+@@ -0,0 +1,11 @@
++Results of test63:
++*** Test 1: OK
++*** Test 2: OK
++*** Test 3: OK
++*** Test 4: OK
++*** Test 5: OK
++*** Test 6: OK
++*** Test 7: OK
++*** Test 8: OK
++*** Test 9: OK
++*** Test 10: OK
+diff -Naur vim71.orig/src/testdir/test64.in vim71/src/testdir/test64.in
+--- vim71.orig/src/testdir/test64.in	1970-01-01 00:00:00.000000000 +0000
++++ vim71/src/testdir/test64.in	2007-12-08 20:34:52.000000000 +0000
+@@ -0,0 +1,54 @@
++Test for regexp patterns.
++
++A pattern that gives the expected result produces OK, so that we know it was
++actually tried.
++
++STARTTEST
++:so small.vim
++:" tl is a List of Lists with:
++:"    regexp pattern
++:"    text to test the pattern on
++:"    expected match (optional)
++:"    expected submatch 1 (optional)
++:"    expected submatch 2 (optional)
++:"    etc.
++:"  When there is no match use only the first two items.
++:let tl = []
++:call add(tl, ['b', 'abcdef', 'b'])
++:call add(tl, ['bc*', 'abccccdef', 'bcccc'])
++:call add(tl, ['bc\{-}', 'abccccdef', 'b'])
++:call add(tl, ['bc\{-}\(d\)', 'abccccdef', 'bccccd', 'd'])
++:call add(tl, ['x', 'abcdef'])
++:"
++:for t in tl
++:  let l = matchlist(t[1], t[0])
++:" check the match itself
++:  if len(l) == 0 && len(t) > 2
++:    $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", did not match, expected: \"' . t[2] . '\"'
++:  elseif len(l) > 0 && len(t) == 2
++:    $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", match: \"' . l[0] . '\", expected no match'
++:  elseif len(t) > 2 && l[0] != t[2]
++:    $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", match: \"' . l[0] . '\", expected: \"' . t[2] . '\"'
++:  else
++:    $put ='OK'
++:  endif
++:  if len(l) > 0
++:"   check all the nine submatches
++:    for i in range(1, 9)
++:      if len(t) <= i + 2
++:        let e = ''
++:      else
++:        let e = t[i + 2]
++:      endif
++:      if l[i] != e
++:        $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", submatch ' . i . ': \"' . l[i] . '\", expected: \"' . e . '\"'
++:      endif
++:    endfor
++:    unlet i
++:  endif
++:endfor
++:unlet t tl e l
++:/^Results/,$wq! test.out
++ENDTEST
++
++Results of test64:
+diff -Naur vim71.orig/src/testdir/test64.ok vim71/src/testdir/test64.ok
+--- vim71.orig/src/testdir/test64.ok	1970-01-01 00:00:00.000000000 +0000
++++ vim71/src/testdir/test64.ok	2007-12-08 20:34:51.000000000 +0000
+@@ -0,0 +1,6 @@
++Results of test64:
++OK
++OK
++OK
++OK
++OK
+diff -Naur vim71.orig/src/ui.c vim71/src/ui.c
+--- vim71.orig/src/ui.c	2007-05-07 19:49:09.000000000 +0000
++++ vim71/src/ui.c	2007-12-08 20:34:51.000000000 +0000
+@@ -1603,8 +1603,6 @@
+ #if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM) \
+ 	|| defined(FEAT_XCLIPBOARD) || defined(VMS) \
+ 	|| defined(FEAT_SNIFF) || defined(FEAT_CLIENTSERVER) \
+-	|| (defined(FEAT_GUI) && (!defined(USE_ON_FLY_SCROLL) \
+-		|| defined(FEAT_MENU))) \
+ 	|| defined(PROTO)
+ /*
+  * Add the given bytes to the input buffer
+@@ -1630,7 +1628,9 @@
+ }
+ #endif
+ 
+-#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) \
++#if ((defined(FEAT_XIM) || defined(FEAT_DND)) && defined(FEAT_GUI_GTK)) \
++	|| defined(FEAT_GUI_MSWIN) \
++	|| defined(FEAT_GUI_MAC) \
+ 	|| (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) \
+ 	|| (defined(FEAT_GUI) && (!defined(USE_ON_FLY_SCROLL) \
+ 		|| defined(FEAT_MENU))) \
+diff -Naur vim71.orig/src/undo.c vim71/src/undo.c
+--- vim71.orig/src/undo.c	2007-05-07 19:21:14.000000000 +0000
++++ vim71/src/undo.c	2007-12-08 20:34:53.000000000 +0000
+@@ -76,6 +76,12 @@
+  * buffer is unloaded.
+  */
+ 
++/* Uncomment the next line for including the u_check() function.  This warns
++ * for errors in the debug information. */
++/* #define U_DEBUG 1 */
++#define UH_MAGIC 0x18dade	/* value for uh_magic when in use */
++#define UE_MAGIC 0xabc123	/* value for ue_magic when in use */
++
+ #include "vim.h"
+ 
+ /* See below: use malloc()/free() for memory management. */
+@@ -113,6 +119,95 @@
+  */
+ static int	undo_undoes = FALSE;
+ 
++#ifdef U_DEBUG
++/*
++ * Check the undo structures for being valid.  Print a warning when something
++ * looks wrong.
++ */
++static int seen_b_u_curhead;
++static int seen_b_u_newhead;
++static int header_count;
++
++    static void
++u_check_tree(u_header_T *uhp,
++	u_header_T *exp_uh_next,
++	u_header_T *exp_uh_alt_prev)
++{
++    u_entry_T *uep;
++
++    if (uhp == NULL)
++	return;
++    ++header_count;
++    if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1)
++    {
++	EMSG("b_u_curhead found twice (looping?)");
++	return;
++    }
++    if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1)
++    {
++	EMSG("b_u_newhead found twice (looping?)");
++	return;
++    }
++
++    if (uhp->uh_magic != UH_MAGIC)
++	EMSG("uh_magic wrong (may be using freed memory)");
++    else
++    {
++	/* Check pointers back are correct. */
++	if (uhp->uh_next != exp_uh_next)
++	{
++	    EMSG("uh_next wrong");
++	    smsg((char_u *)"expected: 0x%x, actual: 0x%x",
++						   exp_uh_next, uhp->uh_next);
++	}
++	if (uhp->uh_alt_prev != exp_uh_alt_prev)
++	{
++	    EMSG("uh_alt_prev wrong");
++	    smsg((char_u *)"expected: 0x%x, actual: 0x%x",
++					   exp_uh_alt_prev, uhp->uh_alt_prev);
++	}
++
++	/* Check the undo tree at this header. */
++	for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
++	{
++	    if (uep->ue_magic != UE_MAGIC)
++	    {
++		EMSG("ue_magic wrong (may be using freed memory)");
++		break;
++	    }
++	}
++
++	/* Check the next alt tree. */
++	u_check_tree(uhp->uh_alt_next, uhp->uh_next, uhp);
++
++	/* Check the next header in this branch. */
++	u_check_tree(uhp->uh_prev, uhp, NULL);
++    }
++}
++
++    void
++u_check(int newhead_may_be_NULL)
++{
++    seen_b_u_newhead = 0;
++    seen_b_u_curhead = 0;
++    header_count = 0;
++
++    u_check_tree(curbuf->b_u_oldhead, NULL, NULL);
++
++    if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL
++	    && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL))
++	EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead);
++    if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0)
++	EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead);
++    if (header_count != curbuf->b_u_numhead)
++    {
++	EMSG("b_u_numhead invalid");
++	smsg((char_u *)"expected: %ld, actual: %ld",
++			       (long)header_count, (long)curbuf->b_u_numhead);
++    }
++}
++#endif
++
+ /*
+  * Save the current line for both the "u" and "U" command.
+  * Returns OK or FAIL.
+@@ -243,6 +338,9 @@
+     if (!undo_allowed())
+ 	return FAIL;
+ 
++#ifdef U_DEBUG
++    u_check(FALSE);
++#endif
+ #ifdef FEAT_NETBEANS_INTG
+     /*
+      * Netbeans defines areas that cannot be modified.  Bail out here when
+@@ -294,6 +392,9 @@
+ 	    uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T));
+ 	    if (uhp == NULL)
+ 		goto nomem;
++#ifdef U_DEBUG
++	    uhp->uh_magic = UH_MAGIC;
++#endif
+ 	}
+ 	else
+ 	    uhp = NULL;
+@@ -316,8 +417,11 @@
+ 	{
+ 	    u_header_T	    *uhfree = curbuf->b_u_oldhead;
+ 
+-	    /* If there is no branch only free one header. */
+-	    if (uhfree->uh_alt_next == NULL)
++	    if (uhfree == old_curhead)
++		/* Can't reconnect the branch, delete all of it. */
++		u_freebranch(curbuf, uhfree, &old_curhead);
++	    else if (uhfree->uh_alt_next == NULL)
++		/* There is no branch, only free one header. */
+ 		u_freeheader(curbuf, uhfree, &old_curhead);
+ 	    else
+ 	    {
+@@ -326,6 +430,9 @@
+ 		    uhfree = uhfree->uh_alt_next;
+ 		u_freebranch(curbuf, uhfree, &old_curhead);
+ 	    }
++#ifdef U_DEBUG
++	    u_check(TRUE);
++#endif
+ 	}
+ 
+ 	if (uhp == NULL)		/* no undo at all */
+@@ -478,6 +585,9 @@
+     uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T));
+     if (uep == NULL)
+ 	goto nomem;
++#ifdef U_DEBUG
++    uep->ue_magic = UE_MAGIC;
++#endif
+ 
+     uep->ue_size = size;
+     uep->ue_top = top;
+@@ -525,6 +635,9 @@
+     curbuf->b_u_synced = FALSE;
+     undo_undoes = FALSE;
+ 
++#ifdef U_DEBUG
++    u_check(FALSE);
++#endif
+     return OK;
+ 
+ nomem:
+@@ -955,6 +1068,9 @@
+     int		empty_buffer;		    /* buffer became empty */
+     u_header_T	*curhead = curbuf->b_u_curhead;
+ 
++#ifdef U_DEBUG
++    u_check(FALSE);
++#endif
+     old_flags = curhead->uh_flags;
+     new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
+ 	       ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
+@@ -1186,6 +1302,9 @@
+     /* The timestamp can be the same for multiple changes, just use the one of
+      * the undone/redone change. */
+     curbuf->b_u_seq_time = curhead->uh_time;
++#ifdef U_DEBUG
++    u_check(FALSE);
++#endif
+ }
+ 
+ /*
+@@ -1515,7 +1634,7 @@
+ }
+ 
+ /*
+- * Free one header and its entry list and adjust the pointers.
++ * Free one header "uhp" and its entry list and adjust the pointers.
+  */
+     static void
+ u_freeheader(buf, uhp, uhpp)
+@@ -1523,6 +1642,8 @@
+     u_header_T	    *uhp;
+     u_header_T	    **uhpp;	/* if not NULL reset when freeing this header */
+ {
++    u_header_T	    *uhap;
++
+     /* When there is an alternate redo list free that branch completely,
+      * because we can never go there. */
+     if (uhp->uh_alt_next != NULL)
+@@ -1540,7 +1661,8 @@
+     if (uhp->uh_prev == NULL)
+ 	buf->b_u_newhead = uhp->uh_next;
+     else
+-	uhp->uh_prev->uh_next = uhp->uh_next;
++	for (uhap = uhp->uh_prev; uhap != NULL; uhap = uhap->uh_alt_next)
++	    uhap->uh_next = uhp->uh_next;
+ 
+     u_freeentries(buf, uhp, uhpp);
+ }
+@@ -1556,6 +1678,14 @@
+ {
+     u_header_T	    *tofree, *next;
+ 
++    /* If this is the top branch we may need to use u_freeheader() to update
++     * all the pointers. */
++    if (uhp == buf->b_u_oldhead)
++    {
++	u_freeheader(buf, uhp, uhpp);
++	return;
++    }
++
+     if (uhp->uh_alt_prev != NULL)
+ 	uhp->uh_alt_prev->uh_alt_next = NULL;
+ 
+@@ -1585,6 +1715,8 @@
+     /* Check for pointers to the header that become invalid now. */
+     if (buf->b_u_curhead == uhp)
+ 	buf->b_u_curhead = NULL;
++    if (buf->b_u_newhead == uhp)
++	buf->b_u_newhead = NULL;  /* freeing the newest entry */
+     if (uhpp != NULL && uhp == *uhpp)
+ 	*uhpp = NULL;
+ 
+@@ -1594,6 +1726,9 @@
+ 	u_freeentry(uep, uep->ue_size);
+     }
+ 
++#ifdef U_DEBUG
++    uhp->uh_magic = 0;
++#endif
+     U_FREE_LINE((char_u *)uhp);
+     --buf->b_u_numhead;
+ }
+@@ -1609,6 +1744,9 @@
+     while (n > 0)
+ 	U_FREE_LINE(uep->ue_array[--n]);
+     U_FREE_LINE((char_u *)uep->ue_array);
++#ifdef U_DEBUG
++    uep->ue_magic = 0;
++#endif
+     U_FREE_LINE((char_u *)uep);
+ }
+ 
+diff -Naur vim71.orig/src/version.c vim71/src/version.c
+--- vim71.orig/src/version.c	2007-05-12 10:23:44.000000000 +0000
++++ vim71/src/version.c	2007-12-08 20:34:53.000000000 +0000
+@@ -667,6 +667,312 @@
+ static int included_patches[] =
+ {   /* Add new patch number below this line */
+ /**/
++    171,
++/**/
++    170,
++/**/
++    169,
++/**/
++    167,
++/**/
++    166,
++/**/
++    165,
++/**/
++    164,
++/**/
++    163,
++/**/
++    162,
++/**/
++    161,
++/**/
++    160,
++/**/
++    159,
++/**/
++    157,
++/**/
++    156,
++/**/
++    155,
++/**/
++    154,
++/**/
++    153,
++/**/
++    152,
++/**/
++    151,
++/**/
++    150,
++/**/
++    149,
++/**/
++    148,
++/**/
++    147,
++/**/
++    145,
++/**/
++    144,
++/**/
++    143,
++/**/
++    142,
++/**/
++    141,
++/**/
++    140,
++/**/
++    139,
++/**/
++    138,
++/**/
++    137,
++/**/
++    136,
++/**/
++    135,
++/**/
++    133,
++/**/
++    132,
++/**/
++    131,
++/**/
++    130,
++/**/
++    127,
++/**/
++    125,
++/**/
++    123,
++/**/
++    122,
++/**/
++    121,
++/**/
++    120,
++/**/
++    119,
++/**/
++    118,
++/**/
++    117,
++/**/
++    116,
++/**/
++    115,
++/**/
++    114,
++/**/
++    113,
++/**/
++    112,
++/**/
++    111,
++/**/
++    110,
++/**/
++    109,
++/**/
++    108,
++/**/
++    107,
++/**/
++    106,
++/**/
++    105,
++/**/
++    104,
++/**/
++    103,
++/**/
++    102,
++/**/
++    101,
++/**/
++    100,
++/**/
++    99,
++/**/
++    98,
++/**/
++    97,
++/**/
++    96,
++/**/
++    95,
++/**/
++    94,
++/**/
++    93,
++/**/
++    90,
++/**/
++    89,
++/**/
++    87,
++/**/
++    86,
++/**/
++    85,
++/**/
++    84,
++/**/
++    83,
++/**/
++    82,
++/**/
++    81,
++/**/
++    79,
++/**/
++    78,
++/**/
++    77,
++/**/
++    76,
++/**/
++    75,
++/**/
++    74,
++/**/
++    73,
++/**/
++    71,
++/**/
++    69,
++/**/
++    68,
++/**/
++    67,
++/**/
++    66,
++/**/
++    64,
++/**/
++    63,
++/**/
++    62,
++/**/
++    61,
++/**/
++    60,
++/**/
++    59,
++/**/
++    58,
++/**/
++    57,
++/**/
++    56,
++/**/
++    55,
++/**/
++    54,
++/**/
++    53,
++/**/
++    52,
++/**/
++    51,
++/**/
++    50,
++/**/
++    49,
++/**/
++    48,
++/**/
++    47,
++/**/
++    46,
++/**/
++    45,
++/**/
++    44,
++/**/
++    43,
++/**/
++    42,
++/**/
++    40,
++/**/
++    39,
++/**/
++    38,
++/**/
++    37,
++/**/
++    36,
++/**/
++    35,
++/**/
++    34,
++/**/
++    33,
++/**/
++    32,
++/**/
++    31,
++/**/
++    30,
++/**/
++    29,
++/**/
++    28,
++/**/
++    27,
++/**/
++    26,
++/**/
++    25,
++/**/
++    24,
++/**/
++    23,
++/**/
++    22,
++/**/
++    21,
++/**/
++    20,
++/**/
++    19,
++/**/
++    18,
++/**/
++    17,
++/**/
++    16,
++/**/
++    15,
++/**/
++    14,
++/**/
++    13,
++/**/
++    12,
++/**/
++    11,
++/**/
++    10,
++/**/
++    9,
++/**/
++    8,
++/**/
++    6,
++/**/
++    5,
++/**/
++    4,
++/**/
++    2,
++/**/
++    1,
++/**/
+     0
+ };
+ 
+diff -Naur vim71.orig/src/vim.h vim71/src/vim.h
+--- vim71.orig/src/vim.h	2007-05-12 09:53:29.000000000 +0000
++++ vim71/src/vim.h	2007-12-08 20:34:51.000000000 +0000
+@@ -1380,8 +1380,14 @@
+ #endif
+ 
+ #ifdef FEAT_MBYTE
+-# define MB_STRICMP(d, s)	(has_mbyte ? mb_strnicmp((char_u *)(d), (char_u *)(s), (int)MAXCOL) : STRICMP((d), (s)))
+-# define MB_STRNICMP(d, s, n)	(has_mbyte ? mb_strnicmp((char_u *)(d), (char_u *)(s), (int)(n)) : STRNICMP((d), (s), (n)))
++/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte
++ * encoding because mb_stricmp() takes care of all ascii and non-ascii
++ * encodings, including characters with umluats in latin1, etc., while
++ * STRICMP() only handles the system locale version, which often does not
++ * handle non-ascii properly. */
++
++# define MB_STRICMP(d, s)	mb_strnicmp((char_u *)(d), (char_u *)(s), (int)MAXCOL)
++# define MB_STRNICMP(d, s, n)	mb_strnicmp((char_u *)(d), (char_u *)(s), (int)(n))
+ #else
+ # define MB_STRICMP(d, s)	STRICMP((d), (s))
+ # define MB_STRNICMP(d, s, n)	STRNICMP((d), (s), (n))
+diff -Naur vim71.orig/src/vimtutor vim71/src/vimtutor
+--- vim71.orig/src/vimtutor	2004-06-07 14:32:27.000000000 +0000
++++ vim71/src/vimtutor	2007-12-08 20:34:50.000000000 +0000
+@@ -39,18 +39,22 @@
+ # remove the copy of the tutor on exit
+ trap "rm -rf $TODELETE" 0 1 2 3 9 11 13 15
+ 
+-# Vim could be called "vim" or "vi".  Also check for "vim6", for people who
+-# have Vim 5.x installed as "vim" and Vim 6.0 as "vim6".
+-testvim=`which vim6 2>/dev/null`
+-if test -f "$testvim"; then
+-	VIM=vim6
+-else
+-	testvim=`which vim`
++# Vim could be called "vim" or "vi".  Also check for "vimN", for people who
++# have Vim installed with its version number.
++# We anticipate up to a future Vim 8 version :-).
++seq="vim vim8 vim75 vim74 vim73 vim72 vim71 vim70 vim7 vim6 vi"
++for i in $seq; do
++	testvim=`which $i 2>/dev/null`
+ 	if test -f "$testvim"; then
+-		VIM=vim
+-	else
+-		VIM=vi
++		VIM=$i
++		break
+ 	fi
++done
++
++# When no Vim version was found fall back to "vim", you'll get an error message
++# below.
++if test -z "$VIM"; then
++	VIM=vim
+ fi
+ 
+ # Use Vim to copy the tutor, it knows the value of $VIMRUNTIME
+diff -Naur vim71.orig/src/window.c vim71/src/window.c
+--- vim71.orig/src/window.c	2007-05-07 19:25:30.000000000 +0000
++++ vim71/src/window.c	2007-12-08 20:34:52.000000000 +0000
+@@ -75,6 +75,7 @@
+ static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
+ 
+ #endif /* FEAT_WINDOWS */
++
+ static win_T *win_alloc __ARGS((win_T *after));
+ static void win_new_height __ARGS((win_T *, int));
+ 
+@@ -583,7 +584,7 @@
+ 		++no_mapping;
+ 		++allow_keys;   /* no mapping for xchar, but allow key codes */
+ 		if (xchar == NUL)
+-		    xchar = safe_vgetc();
++		    xchar = plain_vgetc();
+ #ifdef FEAT_LANGMAP
+ 		LANGMAP_ADJUST(xchar, TRUE);
+ #endif
+@@ -732,7 +733,6 @@
+     if (flags & WSP_VERT)
+     {
+ 	layout = FR_ROW;
+-	do_equal = (p_ea && new_size == 0 && *p_ead != 'v');
+ 
+ 	/*
+ 	 * Check if we are able to split the current window and compute its
+@@ -769,16 +769,31 @@
+ 	 * instead, if possible. */
+ 	if (oldwin->w_p_wfw)
+ 	    win_setwidth_win(oldwin->w_width + new_size, oldwin);
++
++	/* Only make all windows the same width if one of them (except oldwin)
++	 * is wider than one of the split windows. */
++	if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
++	   && oldwin->w_frame->fr_parent != NULL)
++	{
++	    frp = oldwin->w_frame->fr_parent->fr_child;
++	    while (frp != NULL)
++	    {
++		if (frp->fr_win != oldwin && frp->fr_win != NULL
++			&& (frp->fr_win->w_width > new_size
++			    || frp->fr_win->w_width > oldwin->w_width
++						   - new_size - STATUS_HEIGHT))
++		{
++		    do_equal = TRUE;
++		    break;
++		}
++		frp = frp->fr_next;
++	    }
++	}
+     }
+     else
+ #endif
+     {
+ 	layout = FR_COL;
+-	do_equal = (p_ea && new_size == 0
+-#ifdef FEAT_VERTSPLIT
+-		&& *p_ead != 'h'
+-#endif
+-		);
+ 
+ 	/*
+ 	 * Check if we are able to split the current window and compute its
+@@ -831,6 +846,29 @@
+ 	    if (need_status)
+ 		oldwin_height -= STATUS_HEIGHT;
+ 	}
++
++	/* Only make all windows the same height if one of them (except oldwin)
++	 * is higher than one of the split windows. */
++	if (!do_equal && p_ea && size == 0
++#ifdef FEAT_VERTSPLIT
++		&& *p_ead != 'h'
++#endif
++	   && oldwin->w_frame->fr_parent != NULL)
++	{
++	    frp = oldwin->w_frame->fr_parent->fr_child;
++	    while (frp != NULL)
++	    {
++		if (frp->fr_win != oldwin && frp->fr_win != NULL
++			&& (frp->fr_win->w_height > new_size
++			    || frp->fr_win->w_height > oldwin_height - new_size
++							      - STATUS_HEIGHT))
++		{
++		    do_equal = TRUE;
++		    break;
++		}
++		frp = frp->fr_next;
++	    }
++	}
+     }
+ 
+     /*
+@@ -1253,7 +1291,7 @@
+      * Don't execute autocommands while creating the windows.  Must do that
+      * when putting the buffers in the windows.
+      */
+-    ++autocmd_block;
++    block_autocmds();
+ #endif
+ 
+     /* todo is number of windows left to create */
+@@ -1275,7 +1313,7 @@
+ 	}
+ 
+ #ifdef FEAT_AUTOCMD
+-    --autocmd_block;
++    unblock_autocmds();
+ #endif
+ 
+     /* return actual number of windows */
+@@ -2120,7 +2158,7 @@
+ 	if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
+ 	{
+ 	    /*
+-	     * The cursor goes to the preview or the quickfix window, try
++	     * If the cursor goes to the preview or the quickfix window, try
+ 	     * finding another window to go to.
+ 	     */
+ 	    for (;;)
+@@ -2307,7 +2345,6 @@
+     frame_T	*frp, *frp2, *frp3;
+     frame_T	*frp_close = win->w_frame;
+     win_T	*wp;
+-    int		old_size = 0;
+ 
+     /*
+      * If there is only one window there is nothing to remove.
+@@ -2328,33 +2365,77 @@
+     if (frp_close->fr_parent->fr_layout == FR_COL)
+     {
+ #endif
+-	/* When 'winfixheight' is set, remember its old size and restore
+-	 * it later (it's a simplistic solution...).  Don't do this if the
+-	 * window will occupy the full height of the screen. */
+-	if (frp2->fr_win != NULL
+-		&& (frp2->fr_next != NULL || frp2->fr_prev != NULL)
+-		&& frp2->fr_win->w_p_wfh)
+-	    old_size = frp2->fr_win->w_height;
++	/* When 'winfixheight' is set, try to find another frame in the column
++	 * (as close to the closed frame as possible) to distribute the height
++	 * to. */
++	if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
++	{
++	    frp = frp_close->fr_prev;
++	    frp3 = frp_close->fr_next;
++	    while (frp != NULL || frp3 != NULL)
++	    {
++		if (frp != NULL)
++		{
++		    if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh)
++		    {
++			frp2 = frp;
++			wp = frp->fr_win;
++			break;
++		    }
++		    frp = frp->fr_prev;
++		}
++		if (frp3 != NULL)
++		{
++		    if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
++		    {
++			frp2 = frp3;
++			wp = frp3->fr_win;
++			break;
++		    }
++		    frp3 = frp3->fr_next;
++		}
++	    }
++	}
+ 	frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
+ 			    frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+-	if (old_size != 0)
+-	    win_setheight_win(old_size, frp2->fr_win);
+ #ifdef FEAT_VERTSPLIT
+ 	*dirp = 'v';
+     }
+     else
+     {
+-	/* When 'winfixwidth' is set, remember its old size and restore
+-	 * it later (it's a simplistic solution...).  Don't do this if the
+-	 * window will occupy the full width of the screen. */
+-	if (frp2->fr_win != NULL
+-		&& (frp2->fr_next != NULL || frp2->fr_prev != NULL)
+-		&& frp2->fr_win->w_p_wfw)
+-	    old_size = frp2->fr_win->w_width;
++	/* When 'winfixwidth' is set, try to find another frame in the column
++	 * (as close to the closed frame as possible) to distribute the width
++	 * to. */
++	if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
++	{
++	    frp = frp_close->fr_prev;
++	    frp3 = frp_close->fr_next;
++	    while (frp != NULL || frp3 != NULL)
++	    {
++		if (frp != NULL)
++		{
++		    if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw)
++		    {
++			frp2 = frp;
++			wp = frp->fr_win;
++			break;
++		    }
++		    frp = frp->fr_prev;
++		}
++		if (frp3 != NULL)
++		{
++		    if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
++		    {
++			frp2 = frp3;
++			wp = frp3->fr_win;
++			break;
++		    }
++		    frp3 = frp3->fr_next;
++		}
++	    }
++	}
+ 	frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
+ 			    frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+-	if (old_size != 0)
+-	    win_setwidth_win(old_size, frp2->fr_win);
+ 	*dirp = 'h';
+     }
+ #endif
+@@ -3334,7 +3415,7 @@
+      * Don't execute autocommands while creating the tab pages.  Must do that
+      * when putting the buffers in the windows.
+      */
+-    ++autocmd_block;
++    block_autocmds();
+ #endif
+ 
+     for (todo = count - 1; todo > 0; --todo)
+@@ -3342,7 +3423,7 @@
+ 	    break;
+ 
+ #ifdef FEAT_AUTOCMD
+-    --autocmd_block;
++    unblock_autocmds();
+ #endif
+ 
+     /* return actual number of tab pages */
+@@ -4081,7 +4162,7 @@
+ 	/* Don't execute autocommands while the window is not properly
+ 	 * initialized yet.  gui_create_scrollbar() may trigger a FocusGained
+ 	 * event. */
+-	++autocmd_block;
++	block_autocmds();
+ #endif
+ 	/*
+ 	 * link the window in the window list
+@@ -4126,7 +4207,11 @@
+ 	foldInitWin(newwin);
+ #endif
+ #ifdef FEAT_AUTOCMD
+-	--autocmd_block;
++	unblock_autocmds();
++#endif
++#ifdef FEAT_SEARCH_EXTRA
++	newwin->w_match_head = NULL;
++	newwin->w_next_match_id = 4;
+ #endif
+     }
+     return newwin;
+@@ -4147,7 +4232,7 @@
+ #ifdef FEAT_AUTOCMD
+     /* Don't execute autocommands while the window is halfway being deleted.
+      * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */
+-    ++autocmd_block;
++    block_autocmds();
+ #endif
+ 
+ #ifdef FEAT_MZSCHEME
+@@ -4185,11 +4270,11 @@
+ 	vim_free(wp->w_tagstack[i].tagname);
+ 
+     vim_free(wp->w_localdir);
++
+ #ifdef FEAT_SEARCH_EXTRA
+-    vim_free(wp->w_match[0].regprog);
+-    vim_free(wp->w_match[1].regprog);
+-    vim_free(wp->w_match[2].regprog);
++    clear_matches(wp);
+ #endif
++
+ #ifdef FEAT_JUMPLIST
+     free_jumplist(wp);
+ #endif
+@@ -4210,7 +4295,7 @@
+     vim_free(wp);
+ 
+ #ifdef FEAT_AUTOCMD
+-    --autocmd_block;
++    unblock_autocmds();
+ #endif
+ }
+ 
+@@ -5438,6 +5523,7 @@
+ 		{
+ 		    EMSG(_(e_noroom));
+ 		    p_ch = old_p_ch;
++		    curtab->tp_ch_used = p_ch;
+ 		    cmdline_row = Rows - p_ch;
+ 		    break;
+ 		}
+@@ -6174,3 +6260,175 @@
+     return FALSE;
+ }
+ #endif
++
++#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
++/*
++ * Add match to the match list of window 'wp'.  The pattern 'pat' will be
++ * highligted with the group 'grp' with priority 'prio'.
++ * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
++ * If no particular ID is desired, -1 must be specified for 'id'.
++ * Return ID of added match, -1 on failure.
++ */
++    int
++match_add(wp, grp, pat, prio, id)
++    win_T	*wp;
++    char_u	*grp;
++    char_u	*pat;
++    int		prio;
++    int		id;
++{
++    matchitem_T *cur;
++    matchitem_T *prev;
++    matchitem_T *m;
++    int		hlg_id;
++    regprog_T	*regprog;
++
++    if (*grp == NUL || *pat == NUL)
++	return -1;
++    if (id < -1 || id == 0)
++    {
++	EMSGN("E799: Invalid ID: %ld (must be greater than or equal to 1)", id);
++	return -1;
++    }
++    if (id != -1)
++    {
++	cur = wp->w_match_head;
++	while (cur != NULL)
++	{
++	    if (cur->id == id)
++	    {
++		EMSGN("E801: ID already taken: %ld", id);
++		return -1;
++	    }
++	    cur = cur->next;
++	}
++    }
++    if ((hlg_id = syn_namen2id(grp, STRLEN(grp))) == 0)
++    {
++	EMSG2(_(e_nogroup), grp);
++	return -1;
++    }
++    if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
++    {
++	EMSG2(_(e_invarg2), pat);
++	return -1;
++    }
++
++    /* Find available match ID. */
++    while (id == -1)
++    {
++	cur = wp->w_match_head;
++	while (cur != NULL && cur->id != wp->w_next_match_id)
++	    cur = cur->next;
++	if (cur == NULL)
++	    id = wp->w_next_match_id;
++	wp->w_next_match_id++;
++    }
++
++    /* Build new match. */
++    m = (matchitem_T *)alloc(sizeof(matchitem_T));
++    m->id = id;
++    m->priority = prio;
++    m->pattern = vim_strsave(pat);
++    m->hlg_id = hlg_id;
++    m->match.regprog = regprog;
++    m->match.rmm_ic = FALSE;
++    m->match.rmm_maxcol = 0;
++
++    /* Insert new match.  The match list is in ascending order with regard to
++     * the match priorities. */
++    cur = wp->w_match_head;
++    prev = cur;
++    while (cur != NULL && prio >= cur->priority)
++    {
++	prev = cur;
++	cur = cur->next;
++    }
++    if (cur == prev)
++	wp->w_match_head = m;
++    else
++	prev->next = m;
++    m->next = cur;
++
++    redraw_later(SOME_VALID);
++    return id;
++}
++
++/*
++ * Delete match with ID 'id' in the match list of window 'wp'.
++ * Print error messages if 'perr' is TRUE.
++ */
++    int
++match_delete(wp, id, perr)
++    win_T	*wp;
++    int		id;
++    int		perr;
++{
++    matchitem_T *cur = wp->w_match_head;
++    matchitem_T *prev = cur;
++
++    if (id < 1)
++    {
++	if (perr == TRUE)
++	    EMSGN("E802: Invalid ID: %ld (must be greater than or equal to 1)",
++									  id);
++	return -1;
++    }
++    while (cur != NULL && cur->id != id)
++    {
++	prev = cur;
++	cur = cur->next;
++    }
++    if (cur == NULL)
++    {
++	if (perr == TRUE)
++	    EMSGN("E803: ID not found: %ld", id);
++	return -1;
++    }
++    if (cur == prev)
++	wp->w_match_head = cur->next;
++    else
++	prev->next = cur->next;
++    vim_free(cur->match.regprog);
++    vim_free(cur->pattern);
++    vim_free(cur);
++    redraw_later(SOME_VALID);
++    return 0;
++}
++
++/*
++ * Delete all matches in the match list of window 'wp'.
++ */
++    void
++clear_matches(wp)
++    win_T	*wp;
++{
++    matchitem_T *m;
++
++    while (wp->w_match_head != NULL)
++    {
++	m = wp->w_match_head->next;
++	vim_free(wp->w_match_head->match.regprog);
++	vim_free(wp->w_match_head->pattern);
++	vim_free(wp->w_match_head);
++	wp->w_match_head = m;
++    }
++    redraw_later(SOME_VALID);
++}
++
++/*
++ * Get match from ID 'id' in window 'wp'.
++ * Return NULL if match not found.
++ */
++    matchitem_T *
++get_match(wp, id)
++    win_T	*wp;
++    int		id;
++{
++    matchitem_T *cur = wp->w_match_head;
++
++    while (cur != NULL && cur->id != id)
++	cur = cur->next;
++    return cur;
++}
++#endif
+diff -Naur vim71.orig/src/xxd/xxd.c vim71/src/xxd/xxd.c
+--- vim71.orig/src/xxd/xxd.c	2007-05-07 19:41:57.000000000 +0000
++++ vim71/src/xxd/xxd.c	2007-12-08 20:34:53.000000000 +0000
+@@ -212,7 +212,7 @@
+ 
+ #define TRY_SEEK	/* attempt to use lseek, or skip forward by reading */
+ #define COLS 256	/* change here, if you ever need more columns */
+-#define LLEN (9 + (5*COLS-1)/2 + 2 + COLS)
++#define LLEN (11 + (9*COLS-1)/1 + COLS + 2)
+ 
+ char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
+ 
+@@ -590,7 +590,8 @@
+       default:			octspergrp = 0; break;
+       }
+ 
+-  if (cols < 1 || (!hextype && (cols > COLS)))
++  if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS)
++							    && (cols > COLS)))
+     {
+       fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
+       exit(1);
+@@ -750,6 +751,7 @@
+ 	}
+       if (ebcdic)
+ 	e = (e < 64) ? '.' : etoa64[e-64];
++      /* When changing this update definition of LLEN above. */
+       l[11 + (grplen * cols - 1)/octspergrp + p] =
+ #ifdef __MVS__
+ 	  (e >= 64)




More information about the patches mailing list