updated for version 7.0c12
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index cff6d4c..a88e798 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -2177,7 +2177,12 @@
 	    goto doend;
 	}
 #ifdef FEAT_AUTOCMD
+	/* Disallow editing another buffer when "curbuf_lock" is set.
+	 * Do allow ":edit" (check for argument later).
+	 * Do allow ":checktime" (it's postponed). */
 	if (!(ea.argt & CMDWIN)
+		&& ea.cmdidx != CMD_edit
+		&& ea.cmdidx != CMD_checktime
 # ifdef FEAT_USR_CMDS
 		&& !USER_CMDIDX(ea.cmdidx)
 # endif
@@ -7402,6 +7407,12 @@
 #endif
 	    )
     {
+#ifdef FEAT_AUTOCMD
+	/* Can't edit another file when "curbuf_lock" is set.  Only ":edit"
+	 * can bring us here, others are stopped earlier. */
+	if (*eap->arg != NUL && curbuf_locked())
+	    return;
+#endif
 	n = readonlymode;
 	if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview)
 	    readonlymode = TRUE;
diff --git a/src/fileio.c b/src/fileio.c
index 6d92c07..e0ae301 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6071,7 +6071,7 @@
 
     if (!stuff_empty() || global_busy || !typebuf_typed()
 #ifdef FEAT_AUTOCMD
-			|| autocmd_busy
+			|| autocmd_busy || curbuf_lock > 0
 #endif
 					)
 	need_check_timestamps = TRUE;		/* check later */
diff --git a/src/getchar.c b/src/getchar.c
index 07c595f..60a2a9b 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1822,7 +1822,7 @@
      * Using ":normal" can also do this, but it saves the typeahead buffer,
      * thus it should be OK.  But don't get a key from the user then.
      */
-    if (vgetc_busy
+    if (vgetc_busy > 0
 #ifdef FEAT_EX_EXTRA
 	    && ex_normal_busy == 0
 #endif
@@ -1831,7 +1831,7 @@
 
     local_State = get_real_state();
 
-    vgetc_busy = TRUE;
+    ++vgetc_busy;
 
     if (advance)
 	KeyStuffed = FALSE;
@@ -2316,10 +2316,25 @@
 #ifdef FEAT_EVAL
 			/*
 			 * Handle ":map <expr>": evaluate the {rhs} as an
-			 * expression.
+			 * expression.  Save and restore the typeahead so that
+			 * getchar() can be used.
 			 */
 			if (mp->m_expr)
-			    s = eval_to_string(mp->m_str, NULL, FALSE);
+			{
+			    tasave_T	tabuf;
+			    int		save_vgetc_busy = vgetc_busy;
+
+			    save_typeahead(&tabuf);
+			    if (tabuf.typebuf_valid)
+			    {
+				vgetc_busy = 0;
+				s = eval_to_string(mp->m_str, NULL, FALSE);
+				vgetc_busy = save_vgetc_busy;
+			    }
+			    else
+				s = NULL;
+			    restore_typeahead(&tabuf);
+			}
 			else
 #endif
 			    s = mp->m_str;
@@ -2689,7 +2704,7 @@
 	gui_update_cursor(TRUE, FALSE);
 #endif
 
-    vgetc_busy = FALSE;
+    --vgetc_busy;
 
     return c;
 }
diff --git a/src/globals.h b/src/globals.h
index 9203f2a..2287116 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -202,7 +202,7 @@
 # endif
 #endif
 EXTERN int	ex_keep_indent INIT(= FALSE); /* getexmodeline(): keep indent */
-EXTERN int	vgetc_busy INIT(= FALSE);   /* inside vgetc() now */
+EXTERN int	vgetc_busy INIT(= 0);	    /* when inside vgetc() then > 0 */
 
 EXTERN int	didset_vim INIT(= FALSE);   /* did set $VIM ourselves */
 EXTERN int	didset_vimruntime INIT(= FALSE);   /* idem for $VIMRUNTIME */
diff --git a/src/gui_w48.c b/src/gui_w48.c
index 0f6cb7b..b940a27 100644
--- a/src/gui_w48.c
+++ b/src/gui_w48.c
@@ -1114,22 +1114,19 @@
 #ifdef FEAT_TOOLBAR
     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
 	SendMessage(s_toolbarhwnd, WM_SIZE,
-		(WPARAM)0, (LPARAM)(w + ((long)(TOOLBAR_BUTTON_HEIGHT+8)<<16)));
+	      (WPARAM)0, (LPARAM)(w + ((long)(TOOLBAR_BUTTON_HEIGHT+8)<<16)));
 #endif
 #if defined(FEAT_GUI_TABLINE)
     if (showing_tabline)
     {
 	int	top = 0;
-	RECT	rect;
 
 #ifdef FEAT_TOOLBAR
 	if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
 	    top = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
 #endif
-
-	SetRect(&rect, 0, top, w, TABLINE_HEIGHT);
-	TabCtrl_AdjustRect(s_tabhwnd, TRUE, &rect);
-	MoveWindow(s_tabhwnd, 0, top, rect.right, rect.bottom, TRUE);
+	GetClientRect(s_hwnd, &rect);
+	MoveWindow(s_tabhwnd, 0, top, rect.right, TABLINE_HEIGHT, TRUE);
     }
 #endif
 
@@ -1460,7 +1457,7 @@
 	if (fname == NULL)
 	    return INVALCOLOR;
 
-	fd = fopen((char *)fname, "rt");
+	fd = mch_fopen((char *)fname, "rt");
 	vim_free(fname);
 	if (fd == NULL)
 	    return INVALCOLOR;
diff --git a/src/mbyte.c b/src/mbyte.c
index e208700..5db5c04 100644
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -3532,6 +3532,7 @@
 im_show_info(void)
 {
     int	    old_vgetc_busy;
+
     old_vgetc_busy = vgetc_busy;
     vgetc_busy = TRUE;
     showmode();
diff --git a/src/message.c b/src/message.c
index 481236b..0d56759 100644
--- a/src/message.c
+++ b/src/message.c
@@ -869,7 +869,7 @@
  * end. Adjust cmdline_row to avoid the next message overwriting the last one.
  * When inside vgetc(), we can't wait for a typed character at all.
  */
-    if (vgetc_busy)
+    if (vgetc_busy > 0)
 	return;
     if (no_wait_return)
     {
diff --git a/src/os_unix.c b/src/os_unix.c
index 1072b8e..9012974 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4872,7 +4872,7 @@
 # define SEEK_END 2
 #endif
 
-#define SHELL_SPECIAL (char_u *)"\t \"&';<>()\\|"
+#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
 
 /* ARGSUSED */
     int
diff --git a/src/spell.c b/src/spell.c
index f747570..fba3857 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -356,18 +356,22 @@
 #define WF_CAPMASK (WF_ONECAP | WF_ALLCAP | WF_KEEPCAP | WF_FIXCAP)
 
 /* flags for <pflags> */
-#define WFP_RARE    0x01	/* rare prefix */
-#define WFP_NC	    0x02	/* prefix is not combining */
-#define WFP_UP	    0x04	/* to-upper prefix */
+#define WFP_RARE	    0x01	/* rare prefix */
+#define WFP_NC		    0x02	/* prefix is not combining */
+#define WFP_UP		    0x04	/* to-upper prefix */
+#define WFP_COMPPERMIT	    0x08	/* prefix with COMPOUNDPERMITFLAG */
+#define WFP_COMPFORBID	    0x10	/* prefix with COMPOUNDFORBIDFLAG */
 
-/* Flags for postponed prefixes.  Must be above affixID (one byte)
- * and prefcondnr (two bytes). */
-#define WF_RAREPFX  (WFP_RARE << 24)	/* in sl_pidxs: flag for rare
-					 * postponed prefix */
-#define WF_PFX_NC   (WFP_NC << 24)	/* in sl_pidxs: flag for non-combining
-					 * postponed prefix */
-#define WF_PFX_UP   (WFP_UP << 24)	/* in sl_pidxs: flag for to-upper
-					 * postponed prefix */
+/* Flags for postponed prefixes in "sl_pidxs".  Must be above affixID (one
+ * byte) and prefcondnr (two bytes). */
+#define WF_RAREPFX  (WFP_RARE << 24)	/* rare postponed prefix */
+#define WF_PFX_NC   (WFP_NC << 24)	/* non-combining postponed prefix */
+#define WF_PFX_UP   (WFP_UP << 24)	/* to-upper postponed prefix */
+#define WF_PFX_COMPPERMIT (WFP_COMPPERMIT << 24) /* postponed prefix with
+						  * COMPOUNDPERMITFLAG */
+#define WF_PFX_COMPFORBID (WFP_COMPFORBID << 24) /* postponed prefix with
+						  * COMPOUNDFORBIDFLAG */
+
 
 /* flags for <compoptions> */
 #define COMP_CHECKDUP		1	/* CHECKCOMPOUNDDUP */
@@ -3473,9 +3477,11 @@
 					    /* <comppatlen> <comppattext> */
 		if (cnt < 0)
 		    return cnt;
-		todo -= cnt + 2;
+		todo -= cnt + 1;
 	    }
     }
+    if (todo < 0)
+	return SP_FORMERROR;
 
     /* Turn the COMPOUNDRULE items into a regexp pattern:
      * "a[bc]/a*b+" -> "^\(a[bc]\|a*b\+\)$".
@@ -4683,6 +4689,8 @@
     char_u	*ae_flags;	/* flags on the affix (can be NULL) */
     char_u	*ae_cond;	/* condition (NULL for ".") */
     regprog_T	*ae_prog;	/* regexp program for ae_cond or NULL */
+    char	ae_compforbid;	/* COMPOUNDFORBIDFLAG found */
+    char	ae_comppermit;	/* COMPOUNDPERMITFLAG found */
 };
 
 #ifdef FEAT_MBYTE
@@ -4842,6 +4850,7 @@
 } spellinfo_T;
 
 static afffile_T *spell_read_aff __ARGS((spellinfo_T *spin, char_u *fname));
+static void aff_process_flags __ARGS((afffile_T *affile, affentry_T *entry));
 static int spell_info_item __ARGS((char_u *s));
 static unsigned affitem2flag __ARGS((int flagtype, char_u *item, char_u	*fname, int lnum));
 static unsigned get_affitem __ARGS((int flagtype, char_u **pp));
@@ -5273,12 +5282,18 @@
 	    {
 		aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
 								 fname, lnum);
+		if (aff->af_pref.ht_used > 0)
+		    smsg((char_u *)_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
+			    fname, lnum);
 	    }
 	    else if (STRCMP(items[0], "COMPOUNDPERMITFLAG") == 0
 				   && itemcnt == 2 && aff->af_comppermit == 0)
 	    {
 		aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
 								 fname, lnum);
+		if (aff->af_pref.ht_used > 0)
+		    smsg((char_u *)_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
+			    fname, lnum);
 	    }
 	    else if (STRCMP(items[0], "COMPOUNDFLAG") == 0 && itemcnt == 2
 							 && compflags == NULL)
@@ -5528,10 +5543,13 @@
 		{
 		    aff_entry->ae_add = getroom_save(spin, items[3]);
 
-		    /* Recognize flags on the affix: abcd/1234 */
+		    /* Recognize flags on the affix: abcd/XYZ */
 		    aff_entry->ae_flags = vim_strchr(aff_entry->ae_add, '/');
 		    if (aff_entry->ae_flags != NULL)
+		    {
 			*aff_entry->ae_flags++ = NUL;
+			aff_process_flags(aff, aff_entry);
+		    }
 		}
 
 		/* Don't use an affix entry with non-ASCII characters when
@@ -5560,7 +5578,8 @@
 
 		    /* For postponed prefixes we need an entry in si_prefcond
 		     * for the condition.  Use an existing one if possible.
-		     * Can't be done for an affix with flags. */
+		     * Can't be done for an affix with flags, ignoring
+		     * COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG. */
 		    if (*items[0] == 'P' && aff->af_pfxpostpone
 					       && aff_entry->ae_flags == NULL)
 		    {
@@ -5653,10 +5672,6 @@
 							  aff_entry->ae_cond);
 			    }
 
-			    if (aff_entry->ae_flags != NULL)
-				smsg((char_u *)_("Affix flags ignored when PFXPOSTPONE used in %s line %d: %s"),
-						       fname, lnum, items[4]);
-
 			    /* Add the prefix to the prefix tree. */
 			    if (aff_entry->ae_add == NULL)
 				p = (char_u *)"";
@@ -5670,6 +5685,10 @@
 				n |= WFP_NC;
 			    if (upper)
 				n |= WFP_UP;
+			    if (aff_entry->ae_comppermit)
+				n |= WFP_COMPPERMIT;
+			    if (aff_entry->ae_compforbid)
+				n |= WFP_COMPFORBID;
 			    tree_add_word(spin, p, spin->si_prefroot, n,
 						      idx, cur_aff->ah_newID);
 			    did_postpone_prefix = TRUE;
@@ -5930,6 +5949,43 @@
 }
 
 /*
+ * For affix "entry" move COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG from
+ * ae_flags to ae_comppermit and ae_compforbid.
+ */
+    static void
+aff_process_flags(affile, entry)
+    afffile_T	*affile;
+    affentry_T	*entry;
+{
+    char_u	*p;
+    char_u	*prevp;
+    int		flag;
+
+    if (entry->ae_flags != NULL
+		&& (affile->af_compforbid != 0 || affile->af_comppermit != 0))
+    {
+	for (p = entry->ae_flags; *p != NUL; )
+	{
+	    prevp = p;
+	    flag = get_affitem(affile->af_flagtype, &p);
+	    if (flag == affile->af_comppermit || flag == affile->af_compforbid)
+	    {
+		mch_memmove(prevp, p, STRLEN(p) + 1);
+		p = prevp;
+		if (flag == affile->af_comppermit)
+		    entry->ae_comppermit = TRUE;
+		else
+		    entry->ae_compforbid = TRUE;
+	    }
+	    if (affile->af_flagtype == AFT_NUM && *p == ',')
+		++p;
+	}
+	if (*entry->ae_flags == NUL)
+	    entry->ae_flags = NULL;	/* nothing left */
+    }
+}
+
+/*
  * Return TRUE if "s" is the name of an info item in the affix file.
  */
     static int
@@ -6379,28 +6435,6 @@
 	    continue;	/* empty line */
 	line[l] = NUL;
 
-	/* Truncate the word at the "/", set "afflist" to what follows.
-	 * Replace "\/" by "/" and "\\" by "\". */
-	afflist = NULL;
-	for (p = line; *p != NUL; mb_ptr_adv(p))
-	{
-	    if (*p == '\\' && (p[1] == '\\' || p[1] == '/'))
-		mch_memmove(p, p + 1, STRLEN(p));
-	    else if (*p == '/')
-	    {
-		*p = NUL;
-		afflist = p + 1;
-		break;
-	    }
-	}
-
-	/* Skip non-ASCII words when "spin->si_ascii" is TRUE. */
-	if (spin->si_ascii && has_non_ascii(line))
-	{
-	    ++non_ascii;
-	    continue;
-	}
-
 #ifdef FEAT_MBYTE
 	/* Convert from "SET" to 'encoding' when needed. */
 	if (spin->si_conv.vc_type != CONV_NONE)
@@ -6421,6 +6455,28 @@
 	    w = line;
 	}
 
+	/* Truncate the word at the "/", set "afflist" to what follows.
+	 * Replace "\/" by "/" and "\\" by "\". */
+	afflist = NULL;
+	for (p = w; *p != NUL; mb_ptr_adv(p))
+	{
+	    if (*p == '\\' && (p[1] == '\\' || p[1] == '/'))
+		mch_memmove(p, p + 1, STRLEN(p));
+	    else if (*p == '/')
+	    {
+		*p = NUL;
+		afflist = p + 1;
+		break;
+	    }
+	}
+
+	/* Skip non-ASCII words when "spin->si_ascii" is TRUE. */
+	if (spin->si_ascii && has_non_ascii(w))
+	{
+	    ++non_ascii;
+	    continue;
+	}
+
 	/* This takes time, print a message every 10000 words. */
 	if (spin->si_verbose && spin->si_msg_count > 10000)
 	{
@@ -6825,12 +6881,7 @@
 
 			/* Obey a "COMPOUNDFORBIDFLAG" of the affix: don't
 			 * use the compound flags. */
-			if (use_pfxlist != NULL
-				&& affile->af_compforbid != 0
-				&& ae->ae_flags != NULL
-				&& flag_in_afflist(
-				    affile->af_flagtype, ae->ae_flags,
-						       affile->af_compforbid))
+			if (use_pfxlist != NULL && ae->ae_compforbid)
 			{
 			    vim_strncpy(pfx_pfxlist, use_pfxlist, use_pfxlen);
 			    use_pfxlist = pfx_pfxlist;
@@ -6854,12 +6905,7 @@
 			/* When compounding is supported and there is no
 			 * "COMPOUNDPERMITFLAG" then forbid compounding on the
 			 * side where the affix is applied. */
-			if (spin->si_compflags != NULL
-				&& (affile->af_comppermit == 0
-				    || ae->ae_flags == NULL
-				    || !flag_in_afflist(
-					    affile->af_flagtype, ae->ae_flags,
-						      affile->af_comppermit)))
+			if (spin->si_compflags != NULL && !ae->ae_comppermit)
 			{
 			    if (xht != NULL)
 				use_flags |= WF_NOCOMPAFT;
@@ -10677,7 +10723,7 @@
 	    if (dotp == NULL || fnamecmp(dotp, ".spl") != 0)
 		continue;
 	    STRCPY(dotp, ".sug");
-	    fd = fopen((char *)slang->sl_fname, "r");
+	    fd = mch_fopen((char *)slang->sl_fname, "r");
 	    if (fd == NULL)
 		goto nextone;