updated for version 7.0151
diff --git a/src/eval.c b/src/eval.c
index 206bbfb..e521211 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5571,8 +5571,8 @@
     list_append(l, li);
     li->li_tv.v_type = VAR_STRING;
     li->li_tv.v_lock = 0;
-    if ((li->li_tv.vval.v_string = len >= 0 ? vim_strnsave(str, len)
-						  : vim_strsave(str)) == NULL)
+    if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len)
+						 : vim_strsave(str))) == NULL)
 	return FAIL;
     return OK;
 }
@@ -8271,7 +8271,7 @@
     static int		fnum = 0;
     static int		change_start = 0;
     static int		change_end = 0;
-    static enum hlf_value hlID = 0;
+    static hlf_T	hlID = 0;
     int			filler_lines;
     int			col;
 
@@ -8298,7 +8298,7 @@
 		hlID = HLF_ADD;	/* added line */
 	}
 	else
-	    hlID = (enum hlf_value)0;
+	    hlID = (hlf_T)0;
 	prev_lnum = lnum;
 	changedtick = curbuf->b_changedtick;
 	fnum = curbuf->b_fnum;
@@ -8312,7 +8312,7 @@
 	else
 	    hlID = HLF_CHD;			/* changed line */
     }
-    rettv->vval.v_number = hlID == (enum hlf_value)0 ? 0 : (int)hlID;
+    rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
 #endif
 }
 
@@ -13902,8 +13902,8 @@
 {
     char_u	*word = (char_u *)"";
 #ifdef FEAT_SYN_HL
-    int		len;
-    int		attr = 0;
+    int		len = 0;
+    hlf_T	attr = HLF_COUNT;
     list_T	*l;
 #endif
 
@@ -13933,7 +13933,7 @@
 	    while (*str != NUL)
 	    {
 		len = spell_check(curwin, str, &attr, &capcol);
-		if (attr != 0)
+		if (attr != HLF_COUNT)
 		{
 		    word = str;
 		    break;
@@ -13946,11 +13946,11 @@
 
     list_append_string(l, word, len);
     list_append_string(l, (char_u *)(
-		    attr == highlight_attr[HLF_SPB] ? "bad" :
-		    attr == highlight_attr[HLF_SPR] ? "rare" :
-		    attr == highlight_attr[HLF_SPL] ? "local" :
-		    attr == highlight_attr[HLF_SPC] ? "caps" :
-		    ""), -1);
+			attr == HLF_SPB ? "bad" :
+			attr == HLF_SPR ? "rare" :
+			attr == HLF_SPL ? "local" :
+			attr == HLF_SPC ? "caps" :
+			""), -1);
 }
 
 /*
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index c635bfc..449b66c 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -3901,7 +3901,15 @@
 		 * FEAT_GETTEXT isn't defined, so that shell commands use this
 		 * value. */
 		if (what == LC_ALL)
+		{
 		    vim_setenv((char_u *)"LANG", name);
+# ifdef WIN32
+		    /* Apparently MS-Windows printf() may cause a crash when
+		     * we give it 8-bit text while it's expecting text in the
+		     * current locale.  This call avoids that. */
+		    setlocale(LC_CTYPE, "C");
+# endif
+		}
 		if (what != LC_CTYPE)
 		{
 		    char_u	*mname;
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index f88fbf8..7242381 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -5900,7 +5900,7 @@
 
     for (i = 0; command_complete[i].expand != 0; ++i)
     {
-	if (STRLEN(command_complete[i].name) == valend
+	if ((int)STRLEN(command_complete[i].name) == valend
 		&& STRNCMP(value, command_complete[i].name, valend) == 0)
 	{
 	    *complp = command_complete[i].expand;
@@ -9179,15 +9179,21 @@
      */
     if (ssop_flags & SSOP_SESDIR)
     {
-	if (put_line(fd, "exe \"cd \" . expand(\"<sfile>:p:h\")") == FAIL)
+	if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')")
+								      == FAIL)
 	    return FAIL;
     }
     else if (ssop_flags & SSOP_CURDIR)
     {
 	sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow);
 	if (sname == NULL
-		|| fprintf(fd, "cd %s", sname) < 0 || put_eol(fd) == FAIL)
+		|| fputs("cd ", fd) < 0
+		|| ses_put_fname(fd, sname, &ssop_flags) == FAIL
+		|| put_eol(fd) == FAIL)
+	{
+	    vim_free(sname);
 	    return FAIL;
+	}
 	vim_free(sname);
     }
 
diff --git a/src/ex_getln.c b/src/ex_getln.c
index a3fac10..2748915 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -1700,7 +1700,7 @@
 #ifdef FEAT_RIGHTLEFT
 	if (cmdmsg_rl
 # ifdef FEAT_ARABIC
-		|| p_arshape
+		|| (p_arshape && !p_tbidi && enc_utf8)
 # endif
 		)
 	    /* Always redraw the whole command line to fix shaping and
@@ -1873,7 +1873,11 @@
 
     set_cmdspos();
     if (KeyTyped)
+    {
 	m = Columns * Rows;
+	if (m < 0)	/* overflow, Columns or Rows at weird value */
+	    m = MAXCOL;
+    }
     else
 	m = MAXCOL;
     for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i)
@@ -2641,7 +2645,11 @@
 #endif
 	{
 	    if (KeyTyped)
+	    {
 		m = Columns * Rows;
+		if (m < 0)	/* overflow, Columns or Rows at weird value */
+		    m = MAXCOL;
+	    }
 	    else
 		m = MAXCOL;
 	    for (i = 0; i < len; ++i)
diff --git a/src/globals.h b/src/globals.h
index 4b916ef..3731f06 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -35,6 +35,9 @@
  *
  * "LineOffset[n]" is the offset from ScreenLines[] for the start of line 'n'.
  * The same value is used for ScreenLinesUC[] and ScreenAttrs[].
+ *
+ * Note: before the screen is initialized and when out of memory these can be
+ * NULL.
  */
 EXTERN schar_T	*ScreenLines INIT(= NULL);
 EXTERN sattr_T	*ScreenAttrs INIT(= NULL);
@@ -818,7 +821,7 @@
 EXTERN char_u	*edit_submode INIT(= NULL); /* msg for CTRL-X submode */
 EXTERN char_u	*edit_submode_pre INIT(= NULL); /* prepended to edit_submode */
 EXTERN char_u	*edit_submode_extra INIT(= NULL);/* appended to edit_submode */
-EXTERN enum hlf_value	edit_submode_highl; /* highl. method for extra info */
+EXTERN hlf_T	edit_submode_highl;	/* highl. method for extra info */
 EXTERN int	ctrl_x_mode INIT(= 0);	/* Which Ctrl-X mode are we in? */
 #endif
 
diff --git a/src/main.c b/src/main.c
index 898205e..f7e2b1b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1236,6 +1236,12 @@
 init_locale()
 {
     setlocale(LC_ALL, "");
+# ifdef WIN32
+    /* Apparently MS-Windows printf() may cause a crash when we give it 8-bit
+     * text while it's expecting text in the current locale.  This call avoids
+     * that. */
+    setlocale(LC_CTYPE, "C");
+# endif
 
 # ifdef FEAT_GETTEXT
     {
diff --git a/src/normal.c b/src/normal.c
index 84de270..1e645e4 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -4750,10 +4750,9 @@
 		    if (ptr == NULL)
 		    {
 			pos_T	pos = curwin->w_cursor;
-			int	attr;
 
 			/* Find bad word under the cursor. */
-			len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
+			len = spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL);
 			if (len != 0 && curwin->w_cursor.col <= pos.col)
 			    ptr = ml_get_pos(&curwin->w_cursor);
 			curwin->w_cursor = pos;
diff --git a/src/option.c b/src/option.c
index d547edc..b3c80d6 100644
--- a/src/option.c
+++ b/src/option.c
@@ -3277,6 +3277,7 @@
 	 * "linux"	    Linux console
 	 * "screen.linux"   Linux console with screen
 	 * "cygwin"	    Cygwin shell
+	 * "putty"	    Putty program
 	 * We also check the COLORFGBG environment variable, which is set by
 	 * rxvt and derivatives. This variable contains either two or three
 	 * values separated by semicolons; we want the last value in either
@@ -3287,6 +3288,7 @@
 		&& (STRCMP(T_NAME, "linux") == 0
 		    || STRCMP(T_NAME, "screen.linux") == 0
 		    || STRCMP(T_NAME, "cygwin") == 0
+		    || STRCMP(T_NAME, "putty") == 0
 		    || ((p = mch_getenv((char_u *)"COLORFGBG")) != NULL
 			&& (p = vim_strrchr(p, ';')) != NULL
 			&& ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
@@ -7343,6 +7345,11 @@
 	}
 	Columns = MIN_COLUMNS;
     }
+    /* Limit the values to avoid an overflow in Rows * Columns. */
+    if (Columns > 10000)
+	Columns = 10000;
+    if (Rows > 1000)
+	Rows = 1000;
 
 #ifdef DJGPP
     /* avoid a crash by checking for a too large value of 'columns' */
diff --git a/src/proto/spell.pro b/src/proto/spell.pro
index 2adc137..facbfbc 100644
--- a/src/proto/spell.pro
+++ b/src/proto/spell.pro
@@ -1,6 +1,6 @@
 /* spell.c */
-int spell_check __ARGS((win_T *wp, char_u *ptr, int *attrp, int *capcol));
-int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, int *attrp));
+int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol));
+int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, hlf_T *attrp));
 void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen));
 char_u *did_set_spelllang __ARGS((buf_T *buf));
 void spell_free_all __ARGS((void));
diff --git a/src/screen.c b/src/screen.c
index f497f37..fa13904 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -128,7 +128,7 @@
 static schar_T	*current_ScreenLine;
 
 static void win_update __ARGS((win_T *wp));
-static void win_draw_end __ARGS((win_T *wp, int c1, int c2, int row, int endrow, enum hlf_value hl));
+static void win_draw_end __ARGS((win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl));
 #ifdef FEAT_FOLDING
 static void fold_line __ARGS((win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row));
 static void fill_foldcolumn __ARGS((char_u *p, win_T *wp, int closed, linenr_T lnum));
@@ -1904,7 +1904,7 @@
     int		c2;
     int		row;
     int		endrow;
-    enum hlf_value hl;
+    hlf_T	hl;
 {
 #if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
     int		n = 0;
@@ -2531,7 +2531,7 @@
 #ifdef FEAT_DIFF
     int		filler_lines;		/* nr of filler lines to be drawn */
     int		filler_todo;		/* nr of filler lines still to do + 1 */
-    enum hlf_value diff_hlf = (enum hlf_value)0; /* type of diff highlighting */
+    hlf_T	diff_hlf = (hlf_T)0;	/* type of diff highlighting */
     int		change_start = MAXCOL;	/* first col of changed area */
     int		change_end = -1;	/* last col of changed area */
 #endif
@@ -2926,22 +2926,28 @@
 	if (has_spell)
 	{
 	    int		len;
+	    hlf_T	spell_hlf = HLF_COUNT;
 
 	    pos = wp->w_cursor;
 	    wp->w_cursor.lnum = lnum;
 	    wp->w_cursor.col = ptr - line;
-	    len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_attr);
+	    len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
 	    if (len == 0 || (int)wp->w_cursor.col > ptr - line)
 	    {
 		/* no bad word found at line start, don't check until end of a
 		 * word */
-		spell_attr = 0;
+		spell_hlf = HLF_COUNT;
 		word_end = spell_to_word_end(ptr, wp->w_buffer) - line + 1;
 	    }
 	    else
+	    {
 		/* bad word found, use attributes until end of word */
 		word_end = wp->w_cursor.col + len + 1;
 
+		/* Turn index into actual attributes. */
+		if (spell_hlf != HLF_COUNT)
+		    spell_attr = highlight_attr[spell_hlf];
+	    }
 	    wp->w_cursor = pos;
 
 	    /* Need to restart syntax highlighting for this line. */
@@ -3353,7 +3359,7 @@
 		char_attr = search_attr;
 
 #ifdef FEAT_DIFF
-	    if (diff_hlf != (enum hlf_value)0 && n_extra == 0)
+	    if (diff_hlf != (hlf_T)0 && n_extra == 0)
 	    {
 		if (diff_hlf == HLF_CHD && ptr - line >= change_start)
 		    diff_hlf = HLF_TXD;		/* changed text */
@@ -3719,6 +3725,7 @@
 		    {
 			char_u	*prev_ptr, *p;
 			int	len;
+			hlf_T	spell_hlf = HLF_COUNT;
 # ifdef FEAT_MBYTE
 			if (has_mbyte)
 			{
@@ -3736,23 +3743,23 @@
 			else
 			    p = prev_ptr;
 			cap_col -= (prev_ptr - line);
-			len = spell_check(wp, p, &spell_attr, &cap_col);
+			len = spell_check(wp, p, &spell_hlf, &cap_col);
 			word_end = v + len;
 
 			/* In Insert mode only highlight a word that
 			 * doesn't touch the cursor. */
-			if (spell_attr != 0
+			if (spell_hlf != HLF_COUNT
 				&& (State & INSERT) != 0
 				&& wp->w_cursor.lnum == lnum
 				&& wp->w_cursor.col >=
 						    (colnr_T)(prev_ptr - line)
 				&& wp->w_cursor.col < (colnr_T)word_end)
 			{
-			    spell_attr = 0;
+			    spell_hlf = HLF_COUNT;
 			    spell_redraw_lnum = lnum;
 			}
 
-			if (spell_attr == 0 && p != prev_ptr
+			if (spell_hlf == HLF_COUNT && p != prev_ptr
 				       && (p - nextline) + len > nextline_idx)
 			{
 			    /* Remember that the good word continues at the
@@ -3761,6 +3768,10 @@
 			    checked_col = (p - nextline) + len - nextline_idx;
 			}
 
+			/* Turn index into actual attributes. */
+			if (spell_hlf != HLF_COUNT)
+			    spell_attr = highlight_attr[spell_hlf];
+
 			if (cap_col > 0)
 			{
 			    if (p != prev_ptr
@@ -3889,7 +3900,7 @@
 		     * "$". */
 		    if (
 # ifdef FEAT_DIFF
-			    diff_hlf == (enum hlf_value)0
+			    diff_hlf == (hlf_T)0
 #  ifdef LINE_ATTR
 			    &&
 #  endif
@@ -3976,7 +3987,7 @@
 #if defined(FEAT_DIFF) || defined(LINE_ATTR)
 		else if ((
 # ifdef FEAT_DIFF
-			    diff_hlf != (enum hlf_value)0
+			    diff_hlf != (hlf_T)0
 #  ifdef LINE_ATTR
 			    ||
 #  endif
@@ -6398,6 +6409,10 @@
     int		r, c;
     int		off;
 
+    /* Can't use ScreenLines unless initialized */
+    if (ScreenLines == NULL)
+	return;
+
     if (invert)
 	screen_char_attr = HL_INVERSE;
     for (r = row; r < row + height; ++r)
@@ -6696,6 +6711,7 @@
     unsigned	    *new_LineOffset;
     char_u	    *new_LineWraps;
     static int	    entered = FALSE;		/* avoid recursiveness */
+    static int	    did_outofmem_msg = FALSE;	/* did outofmem message */
 
     /*
      * Allocation of the screen buffers is done only when the size changes and
@@ -6790,7 +6806,15 @@
 	    || new_LineWraps == NULL
 	    || outofmem)
     {
-	do_outofmem_msg((long_u)((Rows + 1) * Columns));    /* guess the size */
+	if (ScreenLines != NULL || !did_outofmem_msg)
+	{
+	    /* guess the size */
+	    do_outofmem_msg((long_u)((Rows + 1) * Columns));
+
+	    /* Remember we did this to avoid getting outofmem messages over
+	     * and over again. */
+	    did_outofmem_msg = TRUE;
+	}
 	vim_free(new_ScreenLines);
 	new_ScreenLines = NULL;
 #ifdef FEAT_MBYTE
@@ -6812,6 +6836,8 @@
     }
     else
     {
+	did_outofmem_msg = FALSE;
+
 	for (new_row = 0; new_row < Rows; ++new_row)
 	{
 	    new_LineOffset[new_row] = new_row * Columns;
@@ -6844,7 +6870,7 @@
 		(void)vim_memset(new_ScreenAttrs + new_row * Columns,
 					0, (size_t)Columns * sizeof(sattr_T));
 		old_row = new_row + (screen_Rows - Rows);
-		if (old_row >= 0)
+		if (old_row >= 0 && ScreenLines != NULL)
 		{
 		    if (screen_Columns < Columns)
 			len = screen_Columns;
diff --git a/src/search.c b/src/search.c
index 2ed15df..f4e8f61 100644
--- a/src/search.c
+++ b/src/search.c
@@ -4410,6 +4410,7 @@
     int		i;
     char_u	*already = NULL;
     char_u	*startp = NULL;
+    char_u	*inc_opt = NULL;
 #ifdef RISCOS
     int		previous_munging = __riscosify_control;
 #endif
@@ -4449,10 +4450,10 @@
 	if (regmatch.regprog == NULL)
 	    goto fpip_end;
     }
-    if (*curbuf->b_p_inc != NUL || *p_inc != NUL)
+    inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc;
+    if (*inc_opt != NUL)
     {
-	incl_regmatch.regprog = vim_regcomp(*curbuf->b_p_inc == NUL
-			   ? p_inc : curbuf->b_p_inc, p_magic ? RE_MAGIC : 0);
+	incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0);
 	if (incl_regmatch.regprog == NULL)
 	    goto fpip_end;
 	incl_regmatch.rm_ic = FALSE;	/* don't ignore case in incl. pat. */
@@ -4484,10 +4485,18 @@
 	if (incl_regmatch.regprog != NULL
 		&& vim_regexec(&incl_regmatch, line, (colnr_T)0))
 	{
-	    new_fname = file_name_in_line(incl_regmatch.endp[0],
-		    0, FNAME_EXP|FNAME_INCL|FNAME_REL, 1L,
-		    curr_fname == curbuf->b_fname
-					     ? curbuf->b_ffname : curr_fname);
+	    char_u *p_fname = (curr_fname == curbuf->b_fname)
+					      ? curbuf->b_ffname : curr_fname;
+
+	    if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL)
+		/* Use text from '\zs' to '\ze' (or end) of 'include'. */
+		new_fname = find_file_name_in_path(incl_regmatch.startp[0],
+			      incl_regmatch.endp[0] - incl_regmatch.startp[0],
+				 FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname);
+	    else
+		/* Use text after match with 'include'. */
+		new_fname = file_name_in_line(incl_regmatch.endp[0], 0,
+				 FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname);
 	    already_searched = FALSE;
 	    if (new_fname != NULL)
 	    {
diff --git a/src/spell.c b/src/spell.c
index 53447af..6076dfc 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -477,6 +477,8 @@
     int		su_badflags;	    /* caps flags for bad word */
     char_u	su_badword[MAXWLEN]; /* bad word truncated at su_badlen */
     char_u	su_fbadword[MAXWLEN]; /* su_badword case-folded */
+    char_u	su_sal_badword[MAXWLEN]; /* su_badword soundfolded */
+    slang_T	*su_slang_first;    /* slang_T used for su_sal_badword */
     hashtab_T	su_banned;	    /* table with banned words */
     slang_T	*su_sallang;	    /* default language for sound folding */
 } suginfo_T;
@@ -749,6 +751,7 @@
 static int was_banned __ARGS((suginfo_T *su, char_u *word));
 static void free_banned __ARGS((suginfo_T *su));
 static void rescore_suggestions __ARGS((suginfo_T *su));
+static void rescore_one __ARGS((suginfo_T *su, suggest_T *stp));
 static int cleanup_suggestions __ARGS((garray_T *gap, int maxscore, int keep));
 static void spell_soundfold __ARGS((slang_T *slang, char_u *inword, int folded, char_u *res));
 static void spell_soundfold_sofo __ARGS((slang_T *slang, char_u *inword, char_u *res));
@@ -815,8 +818,8 @@
 /*
  * Main spell-checking function.
  * "ptr" points to a character that could be the start of a word.
- * "*attrp" is set to the attributes for a badly spelled word.  For a non-word
- * or when it's OK it remains unchanged.
+ * "*attrp" is set to the highlight index for a badly spelled word.  For a
+ * non-word or when it's OK it remains unchanged.
  * This must only be called when 'spelllang' is not empty.
  *
  * "capcol" is used to check for a Capitalised word after the end of a
@@ -831,7 +834,7 @@
 spell_check(wp, ptr, attrp, capcol)
     win_T	*wp;		/* current window */
     char_u	*ptr;
-    int		*attrp;
+    hlf_T	*attrp;
     int		*capcol;	/* column to check for Capital */
 {
     matchinf_T	mi;		/* Most things are put in "mi" so that it can
@@ -1008,17 +1011,17 @@
 	}
 
 	if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
-	    *attrp = highlight_attr[HLF_SPB];
+	    *attrp = HLF_SPB;
 	else if (mi.mi_result == SP_RARE)
-	    *attrp = highlight_attr[HLF_SPR];
+	    *attrp = HLF_SPR;
 	else
-	    *attrp = highlight_attr[HLF_SPL];
+	    *attrp = HLF_SPL;
     }
 
     if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE))
     {
 	/* Report SpellCap only when the word isn't badly spelled. */
-	*attrp = highlight_attr[HLF_SPC];
+	*attrp = HLF_SPC;
 	return wrongcaplen;
     }
 
@@ -1822,7 +1825,8 @@
     int		dir;		/* FORWARD or BACKWARD */
     int		allwords;	/* TRUE for "[s"/"]s", FALSE for "[S"/"]S" */
     int		curline;
-    int		*attrp;		/* return: attributes of bad word or NULL */
+    hlf_T	*attrp;		/* return: attributes of bad word or NULL
+				   (only when "dir" is FORWARD) */
 {
     linenr_T	lnum;
     pos_T	found_pos;
@@ -1830,7 +1834,7 @@
     char_u	*line;
     char_u	*p;
     char_u	*endp;
-    int		attr;
+    hlf_T	attr;
     int		len;
     int		has_syntax = syntax_present(wp->w_buffer);
     int		col;
@@ -1900,13 +1904,13 @@
 		break;
 
 	    /* start of word */
-	    attr = 0;
+	    attr = HLF_COUNT;
 	    len = spell_check(wp, p, &attr, &capcol);
 
-	    if (attr != 0)
+	    if (attr != HLF_COUNT)
 	    {
 		/* We found a bad word.  Check the attribute. */
-		if (allwords || attr == highlight_attr[HLF_SPB])
+		if (allwords || attr == HLF_SPB)
 		{
 		    found_one = TRUE;
 
@@ -2017,7 +2021,7 @@
 
 	    /* Skip the characters at the start of the next line that were
 	     * included in a match crossing line boundaries. */
-	    if (attr == 0)
+	    if (attr == HLF_COUNT)
 		skip = p - endp;
 	    else
 		skip = 0;
@@ -5098,7 +5102,9 @@
 		    ga_append(&spin->si_map, '/');
 		}
 	    }
-	    else if (STRCMP(items[0], "SAL") == 0 && itemcnt == 3)
+	    /* Accept "SAL from to" and "SAL from to # comment". */
+	    else if (STRCMP(items[0], "SAL") == 0
+		    && (itemcnt == 3 || (itemcnt > 3 && items[3][0] == '#')))
 	    {
 		if (do_sal)
 		{
@@ -8769,7 +8775,7 @@
     int		banbadword;	/* don't include badword in suggestions */
     int		need_cap;	/* word should start with capital */
 {
-    int		attr = 0;
+    hlf_T	attr = HLF_COUNT;
     char_u	buf[MAXPATHL];
     char_u	*p;
     int		do_combine = FALSE;
@@ -8821,11 +8827,17 @@
 	}
     }
 
+    /* Soundfold the bad word with the default sound folding, so that we don't
+     * have to do this many times. */
+    if (su->su_sallang != NULL)
+	spell_soundfold(su->su_sallang, su->su_fbadword, TRUE,
+							  su->su_sal_badword);
+
     /* If the word is not capitalised and spell_check() doesn't consider the
      * word to be bad then it might need to be capitalised.  Add a suggestion
      * for that. */
     c = PTR2CHAR(su->su_badptr);
-    if (!SPELL_ISUPPER(c) && attr == 0)
+    if (!SPELL_ISUPPER(c) && attr == HLF_COUNT)
     {
 	make_case_word(su->su_badword, buf, WF_ONECAP);
 	add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
@@ -9173,8 +9185,11 @@
 	su->su_fbadword[len] = NUL;
 	make_case_word(su->su_fbadword, word, su->su_badflags);
 	su->su_fbadword[len] = c;
-	add_suggestion(su, &su->su_ga, word, su->su_badlen, SCORE_DEL,
-						     0, TRUE, su->su_sallang);
+
+	/* Give a soundalike score of 0, compute the score as if deleting one
+	 * character. */
+	add_suggestion(su, &su->su_ga, word, su->su_badlen,
+			      RESCORE(SCORE_REP, 0), 0, TRUE, su->su_sallang);
     }
 }
 
@@ -9226,6 +9241,8 @@
     slang_T	*slang;
     int		fword_ends;
     int		lpi;
+    int		maysplit;
+    int		goodword_ends;
 
     /* We make a copy of the case-folded bad word, so that we can modify it
      * to find matches (esp. REP items).  Append some more text, changing
@@ -9401,10 +9418,13 @@
 		    }
 		}
 
-		/* Check NEEDCOMPOUND: can't use word without compounding. */
+		/* Check NEEDCOMPOUND: can't use word without compounding.  Do
+		 * try appending another compound word below. */
 		if (sp->ts_complen == sp->ts_compsplit && fword_ends
 						     && (flags & WF_NEEDCOMP))
-		    break;
+		    goodword_ends = FALSE;
+		else
+		    goodword_ends = TRUE;
 
 		if (sp->ts_complen > sp->ts_compsplit)
 		{
@@ -9508,9 +9528,15 @@
 		    add_banned(su, preword + sp->ts_prewordlen);
 		    break;
 		}
-		if (was_banned(su, preword + sp->ts_prewordlen)
+		if ((sp->ts_complen == sp->ts_compsplit
+			    && was_banned(su, preword + sp->ts_prewordlen))
 						   || was_banned(su, preword))
-		    break;
+		{
+		    if (slang->sl_compprog == NULL)
+			break;
+		    /* the word so far was banned but we may try compounding */
+		    goodword_ends = FALSE;
+		}
 
 		newscore = 0;
 		if ((flags & WF_REGION)
@@ -9523,7 +9549,9 @@
 				  captype(preword + sp->ts_prewordlen, NULL)))
 		    newscore += SCORE_ICASE;
 
-		if (fword_ends && sp->ts_fidx >= sp->ts_fidxtry)
+		maysplit = TRUE;
+		if (fword_ends && goodword_ends
+					     && sp->ts_fidx >= sp->ts_fidxtry)
 		{
 		    /* The badword also ends: add suggestions.  Give a penalty
 		     * when changing non-word char to word char, e.g., "thes,"
@@ -9549,11 +9577,20 @@
 		    }
 
 		    add_suggestion(su, &su->su_ga, preword,
-			    sp->ts_fidx - repextra,
-				     sp->ts_score + newscore, 0, FALSE,
-				     lp->lp_sallang);
+					sp->ts_fidx - repextra,
+					sp->ts_score + newscore, 0, FALSE,
+					lp->lp_sallang);
+
+		    /* When the bad word doesn't end yet, try changing the
+		     * next word.  E.g., find suggestions for "the the" where
+		     * the second "the" is different.  It's done like a split.
+		     */
+		    if (sp->ts_fidx - repextra >= su->su_badlen)
+			maysplit = FALSE;
 		}
-		else if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
+
+		if (maysplit
+			&& (sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
 #ifdef FEAT_MBYTE
 			/* Don't split halfway a character. */
 			&& (!has_mbyte || sp->ts_tcharlen == 0)
@@ -9574,7 +9611,7 @@
 		     *    the following word is valid.
 		     */
 		    try_compound = FALSE;
-		    if (!fword_ends
+		    if ((!fword_ends || !goodword_ends)
 			    && slang->sl_compprog != NULL
 			    && ((unsigned)flags >> 24) != 0
 			    && sp->ts_twordlen - sp->ts_splitoff
@@ -9618,7 +9655,7 @@
 		    else
 			sp->ts_flags &= ~TSF_DIDSPLIT;
 
-		    if (!try_compound && !fword_ends)
+		    if (!try_compound && (!fword_ends || !goodword_ends))
 		    {
 			/* If we're going to split need to check that the
 			 * words so far are valid for compounding.  If there
@@ -9656,10 +9693,12 @@
 			/* If the badword has a non-word character at this
 			 * position skip it.  That means replacing the
 			 * non-word character with a space.  Always skip a
-			 * character when the word ends. */
-			if ((!try_compound
-				   && !spell_iswordp_nmw(fword + sp->ts_fidx))
+			 * character when the word ends.  But only when the
+			 * good word can end. */
+			if (((!try_compound
+				    && !spell_iswordp_nmw(fword + sp->ts_fidx))
 				|| fword_ends)
+			    && goodword_ends)
 			{
 			    int	    l;
 
@@ -10726,12 +10765,17 @@
     char_u	*badsound;	/* sound-folded badword */
 {
     char_u	*p;
+    char_u	*pbad;
+    char_u	*pgood;
     char_u	badsound2[MAXWLEN];
     char_u	fword[MAXWLEN];
     char_u	goodsound[MAXWLEN];
+    char_u	goodword[MAXWLEN];
+    int		lendiff;
 
-    if (stp->st_orglen <= su->su_badlen)
-	p = badsound;
+    lendiff = (int)(su->su_badlen - stp->st_orglen);
+    if (lendiff >= 0)
+	pbad = badsound;
     else
     {
 	/* soundfold the bad word with more characters following */
@@ -10747,13 +10791,24 @@
 		mch_memmove(p, p + 1, STRLEN(p));
 
 	spell_soundfold(slang, fword, TRUE, badsound2);
-	p = badsound2;
+	pbad = badsound2;
     }
 
-    /* Sound-fold the word and compute the score for the difference. */
-    spell_soundfold(slang, stp->st_word, FALSE, goodsound);
+    if (lendiff > 0)
+    {
+	/* Add part of the bad word to the good word, so that we soundfold
+	 * what replaces the bad word. */
+	STRCPY(goodword, stp->st_word);
+	STRNCAT(goodword, su->su_badptr + su->su_badlen - lendiff, lendiff);
+	pgood = goodword;
+    }
+    else
+	pgood = stp->st_word;
 
-    return soundalike_score(goodsound, p);
+    /* Sound-fold the word and compute the score for the difference. */
+    spell_soundfold(slang, pgood, FALSE, goodsound);
+
+    return soundalike_score(goodsound, pbad);
 }
 
 /*
@@ -11081,23 +11136,24 @@
  * with spell_edit_score().
  */
     static void
-add_suggestion(su, gap, goodword, badlen, score, altscore, had_bonus, slang)
+add_suggestion(su, gap, goodword, badlenarg, score, altscore, had_bonus, slang)
     suginfo_T	*su;
     garray_T	*gap;
     char_u	*goodword;
-    int		badlen;		/* length of bad word used */
+    int		badlenarg;	/* len of bad word replaced with "goodword" */
     int		score;
     int		altscore;
     int		had_bonus;	/* value for st_had_bonus */
     slang_T	*slang;		/* language for sound folding */
 {
-    int		goodlen = STRLEN(goodword);
+    int		goodlen = STRLEN(goodword); /* len of goodword changed */
+    int		badlen = badlenarg;	    /* len of bad word changed */
     suggest_T   *stp;
+    suggest_T   new_sug;
     int		i;
-    char_u	*p = NULL;
-    int		c = 0;
-    int		attr = 0;
+    hlf_T	attr = HLF_COUNT;
     char_u	longword[MAXWLEN + 1];
+    char_u	*pgood, *pbad;
 
     /* Check that the word really is valid.  Esp. for banned words and for
      * split words, such as "the the".  Need to append what follows to check
@@ -11105,36 +11161,34 @@
     STRCPY(longword, goodword);
     vim_strncpy(longword + goodlen, su->su_badptr + badlen, MAXWLEN - goodlen);
     (void)spell_check(curwin, longword, &attr, NULL);
-    if (attr != 0)
+    if (attr != HLF_COUNT)
 	return;
 
-    /* If past "su_badlen" and the rest is identical stop at "su_badlen".
-     * Remove the common part from "goodword". */
-    i = badlen - su->su_badlen;
-    if (i > 0)
+    /* Minimize "badlen" for consistency.  Avoids that changing "the the" to
+     * "thee the" is added next to changing the first "the" the "thee".  */
+    pgood = goodword + STRLEN(goodword);
+    pbad = su->su_badptr + badlen;
+    while (pgood > goodword && pbad > su->su_badptr)
     {
-	/* This assumes there was no case folding or it didn't change the
-	 * length... */
-	p = goodword + goodlen - i;
-	if (p > goodword && STRNICMP(su->su_badptr + su->su_badlen, p, i) == 0)
+	mb_ptr_back(goodword, pgood);
+	mb_ptr_back(su->su_badptr, pbad);
+#ifdef FEAT_MBYTE
+	if (has_mbyte)
 	{
-	    badlen = su->su_badlen;
-	    c = *p;
-	    *p = NUL;
+	    if (mb_ptr2char(pgood) != mb_ptr2char(pbad))
+		break;
 	}
 	else
-	    p = NULL;
+#endif
+	    if (*pgood != *pbad)
+		break;
+	badlen = pbad - su->su_badptr;
+	goodlen = pgood - goodword;
     }
-    else if (i < 0)
-    {
-	/* When replacing part of the word check that we actually change
-	 * something.  For "the the" a suggestion can be replacing the first
-	 * "the" with itself, since "the" wasn't banned. */
-	if (badlen == (int)goodlen
-			    && STRNCMP(su->su_badword, goodword, badlen) == 0)
-	    return;
-    }
-
+    if (badlen == 0 && goodlen == 0)
+	/* goodword doesn't change anything; may happen for "the the" changing
+	 * the first "the" to itself. */
+	return;
 
     if (score <= su->su_maxscore)
     {
@@ -11143,18 +11197,44 @@
 	 * "thes" -> "these". */
 	stp = &SUG(*gap, 0);
 	for (i = gap->ga_len - 1; i >= 0; --i)
-	    if (STRCMP(stp[i].st_word, goodword) == 0
+	    if (STRLEN(stp[i].st_word) == goodlen
+			&& STRNCMP(stp[i].st_word, goodword, goodlen) == 0
 						&& stp[i].st_orglen == badlen)
 	    {
-		/* Found it.  Remember the lowest score. */
-		if (stp[i].st_score > score)
-		{
-		    stp[i].st_score = score;
-		    stp[i].st_altscore = altscore;
-		    stp[i].st_had_bonus = had_bonus;
-		}
+		/*
+		 * Found it.  Remember the lowest score.
+		 */
 		if (stp[i].st_slang == NULL)
 		    stp[i].st_slang = slang;
+
+		new_sug.st_score = score;
+		new_sug.st_altscore = altscore;
+		new_sug.st_had_bonus = had_bonus;
+
+		if (stp[i].st_had_bonus != had_bonus)
+		{
+		    /* Only one of the two had the soundalike score computed.
+		     * Need to do that for the other one now, otherwise the
+		     * scores can't be compared.  This happens because
+		     * suggest_try_change() doesn't compute the soundalike
+		     * word to keep it fast. */
+		    if (had_bonus)
+			rescore_one(su, &stp[i]);
+		    else
+		    {
+			new_sug.st_word = goodword;
+			new_sug.st_slang = stp[i].st_slang;
+			new_sug.st_orglen = badlen;
+			rescore_one(su, &new_sug);
+		    }
+		}
+
+		if (stp[i].st_score > new_sug.st_score)
+		{
+		    stp[i].st_score = new_sug.st_score;
+		    stp[i].st_altscore = new_sug.st_altscore;
+		    stp[i].st_had_bonus = new_sug.st_had_bonus;
+		}
 		break;
 	    }
 
@@ -11162,7 +11242,7 @@
 	{
 	    /* Add a suggestion. */
 	    stp = &SUG(*gap, gap->ga_len);
-	    stp->st_word = vim_strsave(goodword);
+	    stp->st_word = vim_strnsave(goodword, goodlen);
 	    if (stp->st_word != NULL)
 	    {
 		stp->st_score = score;
@@ -11180,9 +11260,6 @@
 	    }
 	}
     }
-
-    if (p != NULL)
-	*p = c;		/* restore "goodword" */
 }
 
 /*
@@ -11244,62 +11321,47 @@
 }
 
 /*
- * Recompute the score if sound-folding is possible.  This is slow,
- * thus only done for the final results.
+ * Recompute the score for all suggestions if sound-folding is possible.  This
+ * is slow, thus only done for the final results.
  */
     static void
 rescore_suggestions(su)
     suginfo_T	*su;
 {
-    langp_T	*lp;
-    suggest_T	*stp;
-    char_u	sal_badword[MAXWLEN];
-    char_u	sal_badword2[MAXWLEN];
     int		i;
-    int		lpi;
-    slang_T	*slang_first = NULL;
-    slang_T	*slang;
 
-    for (lpi = 0; lpi < curbuf->b_langp.ga_len; ++lpi)
-    {
-	lp = LANGP_ENTRY(curbuf->b_langp, lpi);
-	if (lp->lp_slang->sl_sal.ga_len > 0)
-	{
-	    /* soundfold the bad word */
-	    slang_first = lp->lp_slang;
-	    spell_soundfold(slang_first, su->su_fbadword, TRUE, sal_badword);
-	    break;
-	}
-    }
-
-    if (slang_first != NULL)
-    {
+    if (su->su_sallang != NULL)
 	for (i = 0; i < su->su_ga.ga_len; ++i)
+	    rescore_one(su, &SUG(su->su_ga, i));
+}
+
+/*
+ * Recompute the score for one suggestion if sound-folding is possible.
+ */
+    static void
+rescore_one(su, stp)
+    suginfo_T *su;
+    suggest_T *stp;
+{
+    slang_T	*slang = stp->st_slang;
+    char_u	sal_badword[MAXWLEN];
+
+    /* Only rescore suggestions that have no sal score yet and do have a
+     * language. */
+    if (slang != NULL && slang->sl_sal.ga_len > 0 && !stp->st_had_bonus)
+    {
+	if (slang == su->su_sallang)
+	    stp->st_altscore = stp_sal_score(stp, su,
+						   slang, su->su_sal_badword);
+	else
 	{
-	    /* Only rescore suggestions that have no sal score yet and do have
-	     * a language. */
-	    stp = &SUG(su->su_ga, i);
-	    if (!stp->st_had_bonus && stp->st_slang != NULL)
-	    {
-		slang = stp->st_slang;
-		if (slang->sl_sal.ga_len > 0)
-		{
-		    if (slang == slang_first)
-			stp->st_altscore = stp_sal_score(stp, su,
-							  slang, sal_badword);
-		    else
-		    {
-			spell_soundfold(slang, su->su_fbadword,
-							  TRUE, sal_badword2);
-			stp->st_altscore = stp_sal_score(stp, su,
-							 slang, sal_badword2);
-		    }
-		    if (stp->st_altscore == SCORE_MAXMAX)
-			stp->st_altscore = SCORE_BIG;
-		    stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
-		}
-	    }
+	    spell_soundfold(slang, su->su_fbadword, TRUE, sal_badword);
+	    stp->st_altscore = stp_sal_score(stp, su, slang, sal_badword);
 	}
+	if (stp->st_altscore == SCORE_MAXMAX)
+	    stp->st_altscore = SCORE_BIG;
+	stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
+	stp->st_had_bonus = TRUE;
     }
 }
 
diff --git a/src/testdir/test58.ok b/src/testdir/test58.ok
index 736e992..75caa7e 100644
--- a/src/testdir/test58.ok
+++ b/src/testdir/test58.ok
@@ -30,7 +30,7 @@
 Ok
 ['OK', 'Uk', 'Put']
 test
-['test', 'Test', 'testn']
+['Test', 'testn', 'testen']
 déôl
 ['deol', 'déôr', 'test']
 end
@@ -87,7 +87,7 @@
 the
 ['put', 'uk', 'test']
 test
-['test', 'Test', 'testn']
+['Test', 'testn', 'testen']
 déôl
 ['deol', 'déôr', 'test']
 
@@ -99,13 +99,13 @@
 bad
 ['foo', 'mï']
 bar
-['foobar', 'foo', 'mï']
+['barfoo', 'foobar', 'foo']
 la
 ['mï', 'foo']
 foomï
 ['foo mï', 'foo', 'foofoo']
 barmï
-['barfoo', 'barbar', 'mï']
+['barfoo', 'mï', 'barbar']
 mïfoo
 ['mï foo', 'foo', 'foofoo']
 mïbar
diff --git a/src/testdir/test59.ok b/src/testdir/test59.ok
index 8f47667..9c49be4 100644
--- a/src/testdir/test59.ok
+++ b/src/testdir/test59.ok
@@ -30,7 +30,7 @@
 Ok
 ['OK', 'Uk', 'Put']
 test
-['test', 'Test', 'testn']
+['Test', 'testn', 'testen']
 déôl
 ['deol', 'déôr', 'test']
 end
@@ -87,7 +87,7 @@
 the
 ['put', 'uk', 'test']
 test
-['test', 'Test', 'testn']
+['Test', 'testn', 'testen']
 déôl
 ['deol', 'déôr', 'test']
 
@@ -99,13 +99,13 @@
 bad
 ['foo', 'mï']
 bar
-['foobar', 'foo', 'mï']
+['barfoo', 'foobar', 'foo']
 la
 ['mï', 'foo']
 foomï
 ['foo mï', 'foo', 'foofoo']
 barmï
-['barfoo', 'barbar', 'mï']
+['barfoo', 'mï', 'barbar']
 mïfoo
 ['mï foo', 'foo', 'foofoo']
 mïbar
diff --git a/src/ui.c b/src/ui.c
index 04e273a..4449bfd 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -1142,6 +1142,10 @@
     int		row2 = clip_star.end.lnum;
     int		col2 = clip_star.end.col;
 
+    /* Can't use ScreenLines unless initialized */
+    if (ScreenLines == NULL)
+	return;
+
     /*
      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
      */
@@ -1312,7 +1316,7 @@
     int		mboff;
 #endif
 
-    if (row >= screen_Rows || col >= screen_Columns)
+    if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL)
 	return;
 
     p = ScreenLines + LineOffset[row];
@@ -1367,7 +1371,7 @@
 {
     int	    i;
 
-    if (row >= screen_Rows)
+    if (row >= screen_Rows || ScreenLines == NULL)
 	return 0;
     for (i = screen_Columns; i > 0; i--)
 	if (ScreenLines[LineOffset[row] + i - 1] != ' ')
@@ -2432,7 +2436,8 @@
 #ifdef FEAT_FOLDING
     /* Remember the character under the mouse, it might be a '-' or '+' in the
      * fold column. */
-    if (row >= 0 && row < Rows && col >= 0 && col <= Columns)
+    if (row >= 0 && row < Rows && col >= 0 && col <= Columns
+						       && ScreenLines != NULL)
 	mouse_char = ScreenLines[LineOffset[row] + col];
     else
 	mouse_char = ' ';
diff --git a/src/version.h b/src/version.h
index cf19c79..70e2f4d 100644
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT	"vim70aa"
 #define VIM_VERSION_SHORT	"7.0aa"
 #define VIM_VERSION_MEDIUM	"7.0aa ALPHA"
-#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Sep 25)"
-#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Sep 25, compiled "
+#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Sep 29)"
+#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Sep 29, compiled "
diff --git a/src/vim.h b/src/vim.h
index c20541c..9c420a0 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1116,7 +1116,7 @@
  * When making changes, also update HL_FLAGS below!  And update the default
  * value of 'highlight' in option.c.
  */
-enum hlf_value
+typedef enum
 {
     HLF_8 = 0	    /* Meta & special keys listed with ":map", text that is
 		       displayed different from what it is */
@@ -1151,7 +1151,7 @@
     , HLF_SPR	    /* SpellRare */
     , HLF_SPL	    /* SpellLocal */
     , HLF_COUNT	    /* MUST be the last one */
-};
+} hlf_T;
 
 /* the HL_FLAGS must be in the same order as the HLF_ enums! */
 #define HL_FLAGS {'8', '@', 'd', 'e', 'h', 'i', 'l', 'm', 'M', \