updated for version 7.0227
diff --git a/src/globals.h b/src/globals.h
index 86d8ad9..b0523fc 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1504,6 +1504,9 @@
 EXTERN int xsmp_icefd INIT(= -1);   /* The actual connection */
 #endif
 
+/* For undo we need to know the lowest time possible. */
+EXTERN time_t starttime;
+
 /*
  * Optional Farsi support.  Include it here, so EXTERN and INIT are defined.
  */
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 46ca546..6e36080 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -323,6 +323,7 @@
 static BOOL (WINAPI *pImmSetCompositionFont)(HIMC, LPLOGFONTA);
 static BOOL (WINAPI *pImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
 static BOOL (WINAPI *pImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
+static BOOL (WINAPI *pImmSetConversionStatus)(HIMC, DWORD, DWORD);
 static void dyn_imm_load(void);
 #else
 # define pImmGetCompositionStringA ImmGetCompositionStringA
@@ -336,6 +337,7 @@
 # define pImmSetCompositionFont   ImmSetCompositionFontA
 # define pImmSetCompositionWindow ImmSetCompositionWindow
 # define pImmGetConversionStatus  ImmGetConversionStatus
+# define pImmSetConversionStatus  ImmSetConversionStatus
 #endif
 
 #ifndef ETO_IGNORELANGUAGE
@@ -1714,6 +1716,39 @@
 	hImc = pImmGetContext(s_hwnd);
 	if (hImc)
 	{
+	    /*
+	     * for Korean ime
+	     */
+	    HKL hKL = GetKeyboardLayout(0);
+
+	    if (LOWORD(hKL) == MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN))
+	    {
+		static DWORD dwConversionSaved = 0, dwSentenceSaved = 0;
+		static BOOL bSaved = FALSE;
+
+		if (active)
+		{
+		    /* if we have a saved conversion status, restore it */
+		    if (bSaved)
+			pImmSetConversionStatus(hImc, dwConversionSaved,
+							     dwSentenceSaved);
+		    bSaved = FALSE;
+		}
+		else
+		{
+		    /* save conversion status and disable korean */
+		    if (pImmGetConversionStatus(hImc, &dwConversionSaved,
+							    &dwSentenceSaved))
+		    {
+			bSaved = TRUE;
+			pImmSetConversionStatus(hImc,
+				dwConversionSaved & ~(IME_CMODE_NATIVE
+						       | IME_CMODE_FULLSHAPE),
+				dwSentenceSaved);
+		    }
+		}
+	    }
+
 	    pImmSetOpenStatus(hImc, active);
 	    pImmReleaseContext(s_hwnd, hImc);
 	}
@@ -1785,7 +1820,7 @@
 {
     int		c;
 
-    while (len-- >= 0)
+    while (--len >= 0)
     {
 	c = *text++;
 	switch (c)
@@ -2021,28 +2056,28 @@
     {
 	/* Output UTF-8 characters.  Caller has already separated
 	 * composing characters. */
-	int		i = 0;
-	int		clen;	/* string length up to composing char */
+	int		i;
+	int		wlen;	/* string length in words */
+	int		clen;	/* string length in characters */
 	int		cells;	/* cell width of string up to composing char */
 	int		cw;	/* width of current cell */
 	int		c;
-	int		xtra;
 
+	wlen = 0
+	clen = 0;
 	cells = 0;
-	for (clen = 0; i < len; )
+	for (i = 0; i < len; )
 	{
 	    c = utf_ptr2char(text + i);
 	    if (c >= 0x10000)
 	    {
 		/* Turn into UTF-16 encoding. */
-		unicodebuf[clen] = ((c - 0x10000) >> 10) + 0xD800;
-		unicodebuf[clen + 1] = ((c - 0x10000) & 0x3ff) + 0xDC00;
-		xtra = 1;
+		unicodebuf[wlen++] = ((c - 0x10000) >> 10) + 0xD800;
+		unicodebuf[wlen++] = ((c - 0x10000) & 0x3ff) + 0xDC00;
 	    }
 	    else
 	    {
-		unicodebuf[clen] = c;
-		xtra = 0;
+		unicodebuf[wlen++] = c;
 	    }
 	    cw = utf_char2cells(c);
 	    if (cw > 2)		/* don't use 4 for unprintable char */
@@ -2053,15 +2088,13 @@
 		 * when the font uses different widths (e.g., bold character
 		 * is wider).  */
 		unicodepdy[clen] = cw * gui.char_width;
-		if (xtra == 1)
-		    unicodepdy[clen + 1] = cw * gui.char_width;
 	    }
 	    cells += cw;
 	    i += utfc_ptr2len_len(text + i, len - i);
-	    clen += xtra + 1;
+	    ++clen;
 	}
 	ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
-			   foptions, pcliprect, unicodebuf, clen, unicodepdy);
+			   foptions, pcliprect, unicodebuf, wlen, unicodepdy);
 	len = cells;	/* used for underlining */
     }
     else if ((enc_codepage > 0 && (int)GetACP() != enc_codepage) || enc_latin9)
@@ -3894,6 +3927,8 @@
 	    = (void *)GetProcAddress(hLibImm, "ImmSetCompositionWindow");
     pImmGetConversionStatus
 	    = (void *)GetProcAddress(hLibImm, "ImmGetConversionStatus");
+    pImmSetConversionStatus
+	    = (void *)GetProcAddress(hLibImm, "ImmSetConversionStatus");
 
     if (       pImmGetCompositionStringA == NULL
 	    || pImmGetCompositionStringW == NULL
@@ -3905,7 +3940,8 @@
 	    || pImmGetCompositionFont == NULL
 	    || pImmSetCompositionFont == NULL
 	    || pImmSetCompositionWindow == NULL
-	    || pImmGetConversionStatus == NULL)
+	    || pImmGetConversionStatus == NULL
+	    || pImmSetConversionStatus == NULL)
     {
 	FreeLibrary(hLibImm);
 	hLibImm = NULL;
diff --git a/src/main.c b/src/main.c
index 3209183..aff8b3f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -208,6 +208,7 @@
     time_fd = mch_fopen(STARTUPTIME, "a");
     TIME_MSG("--- VIM STARTING ---");
 #endif
+    starttime = time(NULL);
 
 #ifdef __EMX__
     _wildcard(&params.argc, &params.argv);
diff --git a/src/misc1.c b/src/misc1.c
index 873159c..00921dc 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -2147,9 +2147,9 @@
  */
 /*ARGSUSED*/
     int
-del_bytes(count, fixpos, use_delcombine)
+del_bytes(count, fixpos_arg, use_delcombine)
     long	count;
-    int		fixpos;
+    int		fixpos_arg;
     int		use_delcombine;	    /* 'delcombine' option applies */
 {
     char_u	*oldp, *newp;
@@ -2158,6 +2158,7 @@
     colnr_T	col = curwin->w_cursor.col;
     int		was_alloced;
     long	movelen;
+    int		fixpos = fixpos_arg;
 
     oldp = ml_get(lnum);
     oldlen = (int)STRLEN(oldp);
@@ -2201,9 +2202,14 @@
     {
 	/*
 	 * If we just took off the last character of a non-blank line, and
-	 * fixpos is TRUE, we don't want to end up positioned at the NUL.
+	 * fixpos is TRUE, we don't want to end up positioned at the NUL,
+	 * unless "restart_edit" is set or 'virtualedit' contains "onemore".
 	 */
-	if (col > 0 && fixpos)
+	if (col > 0 && fixpos && restart_edit == 0
+#ifdef FEAT_VIRTUALEDIT
+					      && (ve_flags & VE_ONEMORE) == 0
+#endif
+					      )
 	{
 	    --curwin->w_cursor.col;
 #ifdef FEAT_VIRTUALEDIT
diff --git a/src/ops.c b/src/ops.c
index fce995f..a13cee7 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -1843,8 +1843,7 @@
 		    curwin->w_cursor.coladd = 0;
 	    }
 #endif
-	    (void)del_bytes((long)n, restart_edit == NUL && !virtual_op,
-				oap->op_type == OP_DELETE
+	    (void)del_bytes((long)n, !virtual_op, oap->op_type == OP_DELETE
 #ifdef FEAT_VISUAL
 				    && !oap->is_VIsual
 #endif
@@ -1868,8 +1867,7 @@
 	    /* delete from start of line until op_end */
 	    curwin->w_cursor.col = 0;
 	    (void)del_bytes((long)(oap->end.col + 1 - !oap->inclusive),
-					   restart_edit == NUL && !virtual_op,
-				oap->op_type == OP_DELETE
+					!virtual_op, oap->op_type == OP_DELETE
 #ifdef FEAT_VISUAL
 					&& !oap->is_VIsual
 #endif
diff --git a/src/proto/mbyte.pro b/src/proto/mbyte.pro
index e5c9295..16a36c8 100644
--- a/src/proto/mbyte.pro
+++ b/src/proto/mbyte.pro
@@ -49,6 +49,7 @@
 void mb_copy_char __ARGS((char_u **fp, char_u **tp));
 int mb_off_next __ARGS((char_u *base, char_u *p));
 int mb_tail_off __ARGS((char_u *base, char_u *p));
+void utf_find_illegal __ARGS((void));
 int utf_valid_string __ARGS((char_u *s, char_u *end));
 int dbcs_screen_tail_off __ARGS((char_u *base, char_u *p));
 void mb_adjust_cursor __ARGS((void));
diff --git a/src/screen.c b/src/screen.c
index 6de791d..fbc3fee 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -4296,7 +4296,7 @@
 			ScreenLinesUC[off] = 0;
 #endif
 		    ++col;
-		    if (vcol == wp->w_virtcol)
+		    if (vcol == (long)wp->w_virtcol)
 		    {
 			ScreenAttrs[off] = hl_attr(HLF_CUC);
 			break;
@@ -4360,7 +4360,7 @@
 #ifdef FEAT_SYN_HL
 	/* Highlight the cursor column if 'cursorcolumn' is set.  But don't
 	 * highlight the cursor position itself. */
-	if (wp->w_p_cuc && vcol == wp->w_virtcol
+	if (wp->w_p_cuc && vcol == (long)wp->w_virtcol
 		&& lnum != wp->w_cursor.lnum
 		&& draw_state == WL_LINE)
 	{
diff --git a/src/structs.h b/src/structs.h
index 26fee9a..1e66e6f 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1254,11 +1254,9 @@
     u_header_T	*b_u_curhead;	/* pointer to current header */
     int		b_u_numhead;	/* current number of headers */
     int		b_u_synced;	/* entry lists are synced */
-    long	b_u_seq_last;	/* last used undo sequence number plus 1 */
-    long	b_u_seq_cur;	/* undo sequence number of last header used
-				   plus 1 */
-    time_t	b_u_seq_time;	/* uh_time of the last header used plus 1 or
-				   uh_time of current header */
+    long	b_u_seq_last;	/* last used undo sequence number */
+    long	b_u_seq_cur;	/* hu_seq of header below which we are now */
+    time_t	b_u_seq_time;	/* uh_time of header below which we are now */
 
     /*
      * variables for "U" command in undo.c
diff --git a/src/undo.c b/src/undo.c
index 330915d..555d9e5 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -87,7 +87,7 @@
 static int undo_allowed __ARGS((void));
 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
 static void u_doit __ARGS((int count));
-static void u_undoredo __ARGS((void));
+static void u_undoredo __ARGS((int undo));
 static void u_undo_end __ARGS((void));
 static void u_add_time __ARGS((char_u *buf, size_t buflen, time_t tt));
 static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
@@ -350,8 +350,8 @@
 	if (curbuf->b_u_newhead != NULL)
 	    curbuf->b_u_newhead->uh_prev = uhp;
 
-	uhp->uh_seq = curbuf->b_u_seq_last++;
-	curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
+	uhp->uh_seq = ++curbuf->b_u_seq_last;
+	curbuf->b_u_seq_cur = uhp->uh_seq;
 	uhp->uh_time = time(NULL);
 	curbuf->b_u_seq_time = uhp->uh_time + 1;
 
@@ -579,9 +579,11 @@
  * Undo or redo, depending on 'undo_undoes', 'count' times.
  */
     static void
-u_doit(count)
-    int count;
+u_doit(startcount)
+    int startcount;
 {
+    int count = startcount;
+
     if (!undo_allowed())
 	return;
 
@@ -604,22 +606,30 @@
 		/* stick curbuf->b_u_curhead at end */
 		curbuf->b_u_curhead = curbuf->b_u_oldhead;
 		beep_flush();
+		if (count == startcount - 1)
+		{
+		    MSG(_("Already at oldest change"));
+		    return;
+		}
 		break;
 	    }
 
-	    u_undoredo();
+	    u_undoredo(TRUE);
 	}
 	else
 	{
 	    if (curbuf->b_u_curhead == NULL || p_ul <= 0)
 	    {
 		beep_flush();	/* nothing to redo */
+		if (count == startcount - 1)
+		{
+		    MSG(_("Already at newest change"));
+		    return;
+		}
 		break;
 	    }
 
-	    u_undoredo();
-	    ++curbuf->b_u_seq_cur;
-	    ++curbuf->b_u_seq_time;
+	    u_undoredo(FALSE);
 
 	    /* Advance for next redo.  Set "newhead" when at the end of the
 	     * redoable changes. */
@@ -652,7 +662,6 @@
     long	    closest_start;
     long	    closest_seq = 0;
     long	    val;
-    long	    limit;
     u_header_T	    *uhp;
     u_header_T	    *last;
     int		    mark;
@@ -670,43 +679,39 @@
     if (curbuf->b_ml.ml_flags & ML_EMPTY)
 	u_oldcount = -1;
 
-    /* "target" is the node below which we want to be.  When going forward
-     * the current one also counts, thus do one less. */
+    /* "target" is the node below which we want to be.
+     * Init "closest" to a value we can't reach. */
     if (absolute)
     {
 	target = step;
-	closest = -2;
+	closest = -1;
     }
-    else if (step < 0)
+    else
     {
+	/* When doing computations with time_t subtract starttime, because
+	 * time_t converted to a long may result in a wrong number. */
 	if (sec)
-	    target = (long)curbuf->b_u_seq_time + step;
+	    target = (long)(curbuf->b_u_seq_time - starttime) + step;
 	else
 	    target = curbuf->b_u_seq_cur + step;
-	if (target < 0)
-	    target = -1;
-	closest = -2;
-    }
-    else
-    {
-	if (sec)
+	if (step < 0)
 	{
-	    target = curbuf->b_u_seq_time + step - 1;
-	    closest = time(NULL) + 1;
+	    if (target < 0)
+		target = 0;
+	    closest = -1;
 	}
 	else
 	{
-	    target = curbuf->b_u_seq_cur + step - 1;
-	    closest = curbuf->b_u_seq_last + 1;
+	    if (sec)
+		closest = time(NULL) - starttime + 1;
+	    else
+		closest = curbuf->b_u_seq_last + 2;
+	    if (target >= closest)
+		target = closest - 1;
 	}
-	if (target >= closest)
-	    target = closest - 1;
     }
     closest_start = closest;
-    if (sec)
-	limit = curbuf->b_u_seq_time + (step > 0 ? -1 : 1);
-    else
-	limit = curbuf->b_u_seq_cur;
+    closest_seq = curbuf->b_u_seq_cur;
 
     /*
      * May do this twice:
@@ -733,27 +738,28 @@
 	while (uhp != NULL)
 	{
 	    uhp->uh_walk = mark;
-	    val = (dosec ? uhp->uh_time : uhp->uh_seq);
+	    val = (dosec ? (uhp->uh_time - starttime) : uhp->uh_seq);
 
 	    if (round == 1)
 	    {
 		/* Remember the header that is closest to the target.
 		 * It must be at least in the right direction (checked with
-		 * "limit").  When the timestamp is equal find the
+		 * "b_u_seq_cur").  When the timestamp is equal find the
 		 * highest/lowest sequence number. */
-		if ((dosec && val == closest)
-			? (step < 0
-			    ? uhp->uh_seq < closest_seq
-			    : uhp->uh_seq > closest_seq)
-			: (step < 0
-			    ? (val < limit
-				&& (closest > target
-				    ? (val <= closest)
-				    : (val >= closest)))
-			    : (val > limit
-				&& (closest < target
-				    ? val >= closest
-				    : val <= closest))))
+		if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur
+			      : uhp->uh_seq > curbuf->b_u_seq_cur)
+			&& ((dosec && val == closest)
+			    ? (step < 0
+				? uhp->uh_seq < closest_seq
+				: uhp->uh_seq > closest_seq)
+			    : closest == closest_start
+				|| (val > target
+				    ? (closest > target
+					? val - target <= closest - target
+					: val - target <= target - closest)
+				    : (closest > target
+					? target - val <= closest - target
+					: target - val <= target - closest))))
 		{
 		    closest = val;
 		    closest_seq = uhp->uh_seq;
@@ -830,19 +836,12 @@
 	    if (uhp == NULL)
 		uhp = curbuf->b_u_newhead;
 	    else
-	    {
-		while (uhp->uh_alt_prev != NULL
-					 && uhp->uh_alt_prev->uh_walk == mark)
-		{
-		    uhp->uh_walk = nomark;
-		    uhp = uhp->uh_alt_prev;
-		}
 		uhp = uhp->uh_next;
-	    }
-	    if (uhp == NULL || uhp->uh_walk != mark)
+	    if (uhp == NULL || uhp->uh_walk != mark
+					 || (uhp->uh_seq == target && !above))
 		break;
 	    curbuf->b_u_curhead = uhp;
-	    u_undoredo();
+	    u_undoredo(TRUE);
 	    uhp->uh_walk = nomark;	/* don't go back down here */
 	}
 
@@ -850,7 +849,7 @@
 	 * And now go down the tree (redo), branching off where needed.
 	 */
 	uhp = curbuf->b_u_curhead;
-	for (;;)
+	while (uhp != NULL)
 	{
 	    /* Find the last branch with a mark, that's the one. */
 	    last = uhp;
@@ -869,10 +868,10 @@
 		uhp->uh_alt_prev = last;
 
 		uhp = last;
+		if (uhp->uh_next != NULL)
+		    uhp->uh_next->uh_prev = uhp;
 	    }
 	    curbuf->b_u_curhead = uhp;
-	    curbuf->b_u_seq_cur = uhp->uh_seq;
-	    curbuf->b_u_seq_time = uhp->uh_time;
 
 	    if (uhp->uh_walk != mark)
 		break;	    /* must have reached the target */
@@ -882,9 +881,7 @@
 	    if (uhp->uh_seq == target && above)
 		break;
 
-	    u_undoredo();
-	    ++curbuf->b_u_seq_cur;
-	    ++curbuf->b_u_seq_time;
+	    u_undoredo(FALSE);
 
 	    /* Advance "curhead" to below the header we last used.  If it
 	     * becomes NULL then we need to set "newhead" to this leaf. */
@@ -898,6 +895,7 @@
 	    uhp = uhp->uh_prev;
 	    if (uhp == NULL || uhp->uh_walk != mark)
 	    {
+		/* Need to redo more but can't find it... */
 		EMSG2(_(e_intern2), "undo_time()");
 		break;
 	    }
@@ -912,9 +910,12 @@
  * The lines in the file are replaced by the lines in the entry list at
  * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
  * list for the next undo/redo.
+ *
+ * When "undo" is TRUE we go up in the tree, when FALSE we go down.
  */
     static void
-u_undoredo()
+u_undoredo(undo)
+    int		undo;
 {
     char_u	**newarray = NULL;
     linenr_T	oldsize;
@@ -1157,6 +1158,13 @@
 
     /* Remember where we are for "g-" and ":earlier 10s". */
     curbuf->b_u_seq_cur = curhead->uh_seq;
+    if (undo)
+	/* We are below the previous undo.  However, to make ":earlier 1s"
+	 * work we compute this as being just above the just undone change. */
+	--curbuf->b_u_seq_cur;
+
+    /* 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;
 }
 
@@ -1212,8 +1220,9 @@
     else
 	u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
 
-    smsg((char_u *)_("%ld %s; #%ld  %s"), u_oldcount, _(msg),
-				      uhp == NULL ? 0L : uhp->uh_seq, msgbuf);
+    smsg((char_u *)_("%ld %s; #%ld  %s"),
+	    u_oldcount < 0 ? -u_oldcount : u_oldcount,
+	    _(msg), uhp == NULL ? 0L : uhp->uh_seq, msgbuf);
 }
 
 /*
@@ -1264,7 +1273,8 @@
     uhp = curbuf->b_u_oldhead;
     while (uhp != NULL)
     {
-	if (uhp->uh_prev == NULL)
+	if (uhp->uh_prev == NULL && uhp->uh_walk != nomark
+						      && uhp->uh_walk != mark)
 	{
 	    if (ga_grow(&ga, 1) == FAIL)
 		break;
diff --git a/src/version.h b/src/version.h
index 19333f2..92f7411 100644
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT	"vim70aa"
 #define VIM_VERSION_SHORT	"7.0aa"
 #define VIM_VERSION_MEDIUM	"7.0aa ALPHA"
-#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 16)"
-#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 16, compiled "
+#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 17)"
+#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 17, compiled "