Merge tag 'v8.0.0117' into HEAD
diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt
index 7310598..4fb55bf 100644
--- a/runtime/doc/channel.txt
+++ b/runtime/doc/channel.txt
@@ -155,7 +155,13 @@
 	func MyCloseHandler(channel)
 <		Vim will invoke callbacks that handle data before invoking
 		close_cb, thus when this function is called no more data will
-		be received.
+		be passed to the callbacks.
+							*channel-drop*
+"drop"		Specifies when to drop messages:
+		    "auto"	When there is no callback to handle a message.
+				The "close_cb" is also considered for this.
+		    "never"	All messages will be kept.
+
 							*waittime*
 "waittime"	The time to wait for the connection to be made in
 		milliseconds.  A negative number waits forever.
@@ -418,7 +424,11 @@
 message that is available: >
 	let output = ch_read(channel, {'timeout': 0})
 When no message was available then the result is v:none for a JSON or JS mode
-channels, an empty string for a RAW or NL channel.
+channels, an empty string for a RAW or NL channel.  You can use |ch_canread()|
+to check if there is something to read.
+
+Note that when there is no callback message are dropped.  To avoid that add a
+close callback to the channel.
 
 To read all output from a RAW channel that is available: >
 	let output = ch_readraw(channel)
@@ -470,6 +480,11 @@
 of a pipe causes the read end to get EOF).  To avoid this make the job sleep
 for a short while before it exits.
 
+Note that if the job exits before you read the output, the output may be lost.
+This depends on the system (on Unix this happens because closing the write end
+of a pipe causes the read end to get EOF).  To avoid this make the job sleep
+for a short while before it exits.
+
 The handler defined for "out_cb" will not receive stderr.  If you want to
 handle that separately, add an "err_cb" handler: >
     let job = job_start(command, {"out_cb": "MyHandler",
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 8eb3a93..e05e6d3 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -359,8 +359,11 @@
 		List entries 6 to 12 from the search history: >
 			:history / 6,12
 <
-		List the recent five entries from all histories: >
-			:history all -5,
+		List the penultimate entry from all histories: >
+			:history all -2
+<
+		List the most recent two entries from all histories: >
+			:history all -2,
 
 :keepp[atterns] {command}			*:keepp* *:keeppatterns*
 		Execute {command}, without adding anything to the search
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 1a11a41..75c2ea1 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2009,6 +2009,7 @@
 call({func}, {arglist} [, {dict}])
 				any	call {func} with arguments {arglist}
 ceil({expr})			Float	round {expr} up
+ch_canread({handle})		Number	check if there is something to read
 ch_close({handle})		none	close {handle}
 ch_close_in({handle})		none	close in part of {handle}
 ch_evalexpr({handle}, {expr} [, {options}])
@@ -2980,16 +2981,28 @@
 		don't fit, a vertical layout is used anyway.  For some systems
 		the horizontal layout is always used.
 
+ch_canread({handle})						*ch_canread()*
+		Return non-zero when there is something to read from {handle}.
+		{handle} can be a Channel or a Job that has a Channel.
+
+		This is useful to read from a channel at a convenient time,
+		e.g. from a timer.
+
+		Note that messages are dropped when the channel does not have
+		a callback.  Add a close callback to avoid that.
+
+		{only available when compiled with the |+channel| feature}
+
 ch_close({handle})						*ch_close()*
 		Close {handle}.  See |channel-close|.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 		A close callback is not invoked.
 
 		{only available when compiled with the |+channel| feature}
 
 ch_close_in({handle})						*ch_close_in()*
 		Close the "in" part of {handle}.  See |channel-close-in|.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 		A close callback is not invoked.
 
 		{only available when compiled with the |+channel| feature}
@@ -2998,7 +3011,7 @@
 		Send {expr} over {handle}.  The {expr} is encoded
 		according to the type of channel.  The function cannot be used
 		with a raw channel.  See |channel-use|.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 								*E917*
 		{options} must be a Dictionary.  It must not have a "callback"
 		entry.  It can have a "timeout" entry to specify the timeout
@@ -3012,7 +3025,7 @@
 
 ch_evalraw({handle}, {string} [, {options}])		*ch_evalraw()*
 		Send {string} over {handle}.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 
 		Works like |ch_evalexpr()|, but does not encode the request or
 		decode the response.  The caller is responsible for the
@@ -3025,7 +3038,7 @@
 
 ch_getbufnr({handle}, {what})				 *ch_getbufnr()*
 		Get the buffer number that {handle} is using for {what}.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 		{what} can be "err" for stderr, "out" for stdout or empty for
 		socket output.
 		Returns -1 when there is no buffer.
@@ -3099,7 +3112,7 @@
 
 ch_read({handle} [, {options}])					*ch_read()*
 		Read from {handle} and return the received message.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 		See |channel-more|.
 		{only available when compiled with the |+channel| feature}
 
@@ -3113,7 +3126,7 @@
 		according to the type of channel.  The function cannot be used
 		with a raw channel.
 		See |channel-use|.				*E912*
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 
 		{only available when compiled with the |+channel| feature}
 
@@ -3134,7 +3147,7 @@
 			"timeout"	default read timeout in msec
 			"mode"		mode for the whole channel
 		See |ch_open()| for more explanation.
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 
 		Note that changing the mode may cause queued messages to be
 		lost.
@@ -3148,7 +3161,7 @@
 			"open"		channel can be used
 			"buffered"	channel can be read, not written to
 			"closed"	channel can not be used
-		{handle} can be Channel or a Job that has a Channel.
+		{handle} can be a Channel or a Job that has a Channel.
 		"buffered" is used when the channel was closed but there is
 		still data that can be obtained with |ch_read()|.
 
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index 63f7fa9..b292720 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -81,6 +81,13 @@
 STATIC_STDCPLUS=no
 endif
 
+
+# Link against the shared version of libwinpthread by default.  Set
+# STATIC_WINPTHREAD to "yes" to link against static version instead.
+ifndef STATIC_WINPTHREAD
+STATIC_WINPTHREAD=$(STATIC_STDCPLUS)
+endif
+
 # If the user doesn't want gettext, undefine it.
 ifeq (no, $(GETTEXT))
 GETTEXT=
@@ -817,6 +824,10 @@
 endif
 endif
 
+ifeq (yes, $(STATIC_WINPTHREAD))
+LIB += -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic
+endif
+
 all: $(TARGET) vimrun.exe xxd/xxd.exe install.exe uninstal.exe GvimExt/gvimext.dll
 
 vimrun.exe: vimrun.c
diff --git a/src/Makefile b/src/Makefile
index 7a65677..a24eb7b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1684,21 +1684,30 @@
 	objects/memfile.o \
 	objects/message.o
 
-JSON_TEST_OBJ = $(OBJ_COMMON) \
+OBJ_JSON_TEST = \
 	objects/memfile.o \
 	objects/message.o \
 	objects/json_test.o
 
-MEMFILE_TEST_OBJ = $(OBJ_COMMON) \
+JSON_TEST_OBJ = $(OBJ_COMMON) $(OBJ_JSON_TEST)
+
+OBJ_MEMFILE_TEST = \
 	objects/json.o \
 	objects/message.o \
 	objects/memfile_test.o
 
-MESSAGE_TEST_OBJ = $(OBJ_COMMON) \
+MEMFILE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MEMFILE_TEST)
+
+OBJ_MESSAGE_TEST = \
 	objects/json.o \
 	objects/memfile.o \
 	objects/message_test.o
 
+MESSAGE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MESSAGE_TEST)
+
+ALL_OBJ = $(OBJ_COMMON) $(OBJ_JSON_TEST) $(OBJ_MEMFILE_TEST) $(OBJ_MESSAGE_TEST)
+
+
 PRO_AUTO = \
 	arabic.pro \
 	blowfish.pro \
@@ -2052,7 +2061,7 @@
 	test60 test64 test65 test66 test67 test68 test69 \
 	test70 test72 test73 test74 test75 test77 test78 test79 \
 	test80 test82 test83 test84 test85 test86 test87 test88 test89 \
-	test90 test91 test92 test93 test94 test95 test97 test98 test99 \
+	test90 test91 test94 test95 test97 test98 test99 \
 	test100 test101 test103 test104 test107 test108:
 	cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
 
@@ -2118,6 +2127,8 @@
 	test_matchadd_conceal_utf8 \
 	test_menu \
 	test_messages \
+	test_mksession \
+	test_mksession_utf8 \
 	test_nested_function \
 	test_netbeans \
 	test_normal \
@@ -2851,8 +2862,14 @@
 # commands understand putting object files in another directory, it must be
 # specified for each file separately.
 
-objects:
-	mkdir objects
+objects objects/.dirstamp:
+	mkdir -p objects
+	touch objects/.dirstamp
+
+# All object files depend on the objects directory, so that parallel make
+# works.  Can't depend on the directory itself, its timestamp changes all the
+# time.
+$(ALL_OBJ): objects/.dirstamp
 
 objects/arabic.o: arabic.c
 	$(CCC) -o $@ arabic.c
diff --git a/src/buffer.c b/src/buffer.c
index e5d2dde..e77fc04 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4858,8 +4858,8 @@
 	    wpnext = wp->w_next;
 	    buf = wp->w_buffer;
 	    if (buf->b_ffname == NULL
-		    || (!keep_tabs && buf->b_nwindows > 1)
-		    || wp->w_width != Columns)
+		    || (!keep_tabs && (buf->b_nwindows > 1
+			    || wp->w_width != Columns)))
 		i = opened_len;
 	    else
 	    {
diff --git a/src/channel.c b/src/channel.c
index 778a30e..32f3527 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1195,6 +1195,7 @@
     if (opt->jo_set & JO_CLOSE_CALLBACK)
 	set_callback(&channel->ch_close_cb, &channel->ch_close_partial,
 		opt->jo_close_cb, opt->jo_close_partial);
+    channel->ch_drop_never = opt->jo_drop_never;
 
     if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
     {
@@ -1918,6 +1919,7 @@
 		clear_tv(&listtv);
 	    else
 	    {
+		item->jq_no_callback = FALSE;
 		item->jq_value = alloc_tv();
 		if (item->jq_value == NULL)
 		{
@@ -2050,11 +2052,17 @@
  * When "id" is positive it must match the first number in the list.
  * When "id" is zero or negative jut get the first message.  But not the one
  * with id ch_block_id.
+ * When "without_callback" is TRUE also get messages that were pushed back.
  * Return OK when found and return the value in "rettv".
  * Return FAIL otherwise.
  */
     static int
-channel_get_json(channel_T *channel, ch_part_T part, int id, typval_T **rettv)
+channel_get_json(
+	channel_T   *channel,
+	ch_part_T   part,
+	int	    id,
+	int	    without_callback,
+	typval_T    **rettv)
 {
     jsonq_T   *head = &channel->ch_part[part].ch_json_head;
     jsonq_T   *item = head->jq_next;
@@ -2064,10 +2072,11 @@
 	list_T	    *l = item->jq_value->vval.v_list;
 	typval_T    *tv = &l->lv_first->li_tv;
 
-	if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
+	if ((without_callback || !item->jq_no_callback)
+	    && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
 	      || (id <= 0 && (tv->v_type != VAR_NUMBER
 		 || tv->vval.v_number == 0
-		 || tv->vval.v_number != channel->ch_part[part].ch_block_id)))
+		 || tv->vval.v_number != channel->ch_part[part].ch_block_id))))
 	{
 	    *rettv = item->jq_value;
 	    if (tv->v_type == VAR_NUMBER)
@@ -2080,6 +2089,65 @@
     return FAIL;
 }
 
+/*
+ * Put back "rettv" into the JSON queue, there was no callback for it.
+ * Takes over the values in "rettv".
+ */
+    static void
+channel_push_json(channel_T *channel, ch_part_T part, typval_T *rettv)
+{
+    jsonq_T   *head = &channel->ch_part[part].ch_json_head;
+    jsonq_T   *item = head->jq_next;
+    jsonq_T   *newitem;
+
+    if (head->jq_prev != NULL && head->jq_prev->jq_no_callback)
+	/* last item was pushed back, append to the end */
+	item = NULL;
+    else while (item != NULL && item->jq_no_callback)
+	/* append after the last item that was pushed back */
+	item = item->jq_next;
+
+    newitem = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
+    if (newitem == NULL)
+	clear_tv(rettv);
+    else
+    {
+	newitem->jq_value = alloc_tv();
+	if (newitem->jq_value == NULL)
+	{
+	    vim_free(newitem);
+	    clear_tv(rettv);
+	}
+	else
+	{
+	    newitem->jq_no_callback = FALSE;
+	    *newitem->jq_value = *rettv;
+	    if (item == NULL)
+	    {
+		/* append to the end */
+		newitem->jq_prev = head->jq_prev;
+		head->jq_prev = newitem;
+		newitem->jq_next = NULL;
+		if (newitem->jq_prev == NULL)
+		    head->jq_next = newitem;
+		else
+		    newitem->jq_prev->jq_next = newitem;
+	    }
+	    else
+	    {
+		/* append after "item" */
+		newitem->jq_prev = item;
+		newitem->jq_next = item->jq_next;
+		item->jq_next = newitem;
+		if (newitem->jq_next == NULL)
+		    head->jq_prev = newitem;
+		else
+		    newitem->jq_next->jq_prev = newitem;
+	    }
+	}
+    }
+}
+
 #define CH_JSON_MAX_ARGS 4
 
 /*
@@ -2410,11 +2478,11 @@
 	int		argc = 0;
 
 	/* Get any json message in the queue. */
-	if (channel_get_json(channel, part, -1, &listtv) == FAIL)
+	if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
 	{
 	    /* Parse readahead, return when there is still no message. */
 	    channel_parse_json(channel, part);
-	    if (channel_get_json(channel, part, -1, &listtv) == FAIL)
+	    if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
 		return FALSE;
 	}
 
@@ -2454,7 +2522,7 @@
 	{
 	    /* If there is a close callback it may use ch_read() to get the
 	     * messages. */
-	    if (channel->ch_close_cb == NULL)
+	    if (channel->ch_close_cb == NULL && !channel->ch_drop_never)
 		drop_messages(channel, part);
 	    return FALSE;
 	}
@@ -2531,7 +2599,7 @@
     {
 	int	done = FALSE;
 
-	/* invoke the one-time callback with the matching nr */
+	/* JSON or JS mode: invoke the one-time callback with the matching nr */
 	for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
 	    if (cbitem->cq_seq_nr == seq_nr)
 	    {
@@ -2540,7 +2608,17 @@
 		break;
 	    }
 	if (!done)
-	    ch_logn(channel, "Dropping message %d without callback", seq_nr);
+	{
+	    if (channel->ch_drop_never)
+	    {
+		/* message must be read with ch_read() */
+		channel_push_json(channel, part, listtv);
+		listtv = NULL;
+	    }
+	    else
+		ch_logn(channel, "Dropping message %d without callback",
+								       seq_nr);
+	}
     }
     else if (callback != NULL || buffer != NULL)
     {
@@ -2567,7 +2645,7 @@
 	}
     }
     else
-	ch_log(channel, "Dropping message");
+	ch_logn(channel, "Dropping message %d", seq_nr);
 
     if (listtv != NULL)
 	free_tv(listtv);
@@ -2603,7 +2681,7 @@
 /*
  * Return TRUE if "channel" has JSON or other typeahead.
  */
-    static int
+    int
 channel_has_readahead(channel_T *channel, ch_part_T part)
 {
     ch_mode_T	ch_mode = channel->ch_part[part].ch_mode;
@@ -2792,9 +2870,10 @@
 	      redraw_after_callback();
 	  }
 
-	  /* any remaining messages are useless now */
-	  for (part = PART_SOCK; part < PART_IN; ++part)
-	      drop_messages(channel, part);
+	  if (!channel->ch_drop_never)
+	      /* any remaining messages are useless now */
+	      for (part = PART_SOCK; part < PART_IN; ++part)
+		  drop_messages(channel, part);
     }
 
     channel->ch_nb_close_cb = NULL;
@@ -3091,9 +3170,9 @@
 channel_close_now(channel_T *channel)
 {
     ch_log(channel, "Closing channel because all readable fds are closed");
-    channel_close(channel, TRUE);
     if (channel->ch_nb_close_cb != NULL)
 	(*channel->ch_nb_close_cb)();
+    channel_close(channel, TRUE);
 }
 
 /*
@@ -3243,7 +3322,7 @@
  * When "id" is -1 accept any message;
  * Blocks until the message is received or the timeout is reached.
  */
-    int
+    static int
 channel_read_json_block(
 	channel_T   *channel,
 	ch_part_T   part,
@@ -3264,7 +3343,7 @@
 	more = channel_parse_json(channel, part);
 
 	/* search for message "id" */
-	if (channel_get_json(channel, part, id, rettv) == OK)
+	if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
 	{
 	    chanpart->ch_block_id = 0;
 	    return OK;
@@ -3815,6 +3894,11 @@
     int		ret = FALSE;
     int		r;
     ch_part_T	part = PART_SOCK;
+#ifdef ELAPSED_FUNC
+    ELAPSED_TYPE  start_tv;
+
+    ELAPSED_INIT(start_tv);
+#endif
 
     ++safe_to_invoke_callback;
 
@@ -3859,7 +3943,14 @@
 	    r = may_invoke_callback(channel, part);
 	    if (r == OK)
 		ret = TRUE;
-	    if (channel_unref(channel) || r == OK)
+	    if (channel_unref(channel) || (r == OK
+#ifdef ELAPSED_FUNC
+			/* Limit the time we loop here to 100 msec, otherwise
+			 * Vim becomes unresponsive when the callback takes
+			 * more than a bit of time. */
+			&& ELAPSED_FUNC(start_tv) < 100L
+#endif
+			))
 	    {
 		/* channel was freed or something was done, start over */
 		channel = first_channel;
@@ -3888,6 +3979,31 @@
 }
 
 /*
+ * Return TRUE if any channel has readahead.  That means we should not block on
+ * waiting for input.
+ */
+    int
+channel_any_readahead(void)
+{
+    channel_T	*channel = first_channel;
+    ch_part_T	part = PART_SOCK;
+
+    while (channel != NULL)
+    {
+	if (channel_has_readahead(channel, part))
+	    return TRUE;
+	if (part < PART_ERR)
+	    ++part;
+	else
+	{
+	    channel = channel->ch_next;
+	    part = PART_SOCK;
+	}
+    }
+    return FALSE;
+}
+
+/*
  * Mark references to lists used in channels.
  */
     int
@@ -4253,6 +4369,20 @@
 		    return FAIL;
 		}
 	    }
+	    else if (STRCMP(hi->hi_key, "drop") == 0)
+	    {
+		int never = FALSE;
+		val = get_tv_string(item);
+
+		if (STRCMP(val, "never") == 0)
+		    never = TRUE;
+		else if (STRCMP(val, "auto") != 0)
+		{
+		    EMSG2(_(e_invarg2), "drop");
+		    return FAIL;
+		}
+		opt->jo_drop_never = never;
+	    }
 	    else if (STRCMP(hi->hi_key, "exit_cb") == 0)
 	    {
 		if (!(supported & JO_EXIT_CB))
diff --git a/src/config.h.in b/src/config.h.in
index 5baac7d..38b0ccf 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -154,7 +154,6 @@
 #undef BAD_GETCWD
 
 /* Define if you the function: */
-#undef HAVE_BCMP
 #undef HAVE_FCHDIR
 #undef HAVE_FCHOWN
 #undef HAVE_FSEEKO
@@ -170,7 +169,6 @@
 #undef HAVE_ICONV
 #undef HAVE_NL_LANGINFO_CODESET
 #undef HAVE_LSTAT
-#undef HAVE_MEMCMP
 #undef HAVE_MEMSET
 #undef HAVE_MKDTEMP
 #undef HAVE_NANOSLEEP
diff --git a/src/configure.ac b/src/configure.ac
index f6a4469..3a31f97 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -3594,8 +3594,8 @@
 
 dnl Check for functions in one big call, to reduce the size of configure.
 dnl Can only be used for functions that do not require any include.
-AC_CHECK_FUNCS(bcmp fchdir fchown fsync getcwd getpseudotty \
-	getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
+AC_CHECK_FUNCS(fchdir fchown fsync getcwd getpseudotty \
+	getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat \
 	memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
 	setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
 	sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 846a914..6721173 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -76,6 +76,7 @@
 static void f_ceil(typval_T *argvars, typval_T *rettv);
 #endif
 #ifdef FEAT_JOB_CHANNEL
+static void f_ch_canread(typval_T *argvars, typval_T *rettv);
 static void f_ch_close(typval_T *argvars, typval_T *rettv);
 static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
@@ -499,6 +500,7 @@
     {"ceil",		1, 1, f_ceil},
 #endif
 #ifdef FEAT_JOB_CHANNEL
+    {"ch_canread",	1, 1, f_ch_canread},
     {"ch_close",	1, 1, f_ch_close},
     {"ch_close_in",	1, 1, f_ch_close_in},
     {"ch_evalexpr",	2, 3, f_ch_evalexpr},
@@ -1779,6 +1781,21 @@
 
 #ifdef FEAT_JOB_CHANNEL
 /*
+ * "ch_canread()" function
+ */
+    static void
+f_ch_canread(typval_T *argvars, typval_T *rettv)
+{
+    channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+    rettv->vval.v_number = 0;
+    if (channel != NULL)
+	rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
+			    || channel_has_readahead(channel, PART_OUT)
+			    || channel_has_readahead(channel, PART_ERR);
+}
+
+/*
  * "ch_close()" function
  */
     static void
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 02c5ed1..eae37bf 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -2297,19 +2297,24 @@
 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
 #endif
 
+static void get_work_area(RECT *spi_rect);
+
 /*
  * A quick little routine that will center one window over another, handy for
- * dialog boxes.  Taken from the Win32SDK samples.
+ * dialog boxes.  Taken from the Win32SDK samples and modified for multiple
+ * monitors.
  */
     static BOOL
 CenterWindow(
     HWND hwndChild,
     HWND hwndParent)
 {
-    RECT    rChild, rParent;
-    int     wChild, hChild, wParent, hParent;
-    int     wScreen, hScreen, xNew, yNew;
-    HDC     hdc;
+    HMONITOR	    mon;
+    MONITORINFO	    moninfo;
+    RECT	    rChild, rParent, rScreen;
+    int		    wChild, hChild, wParent, hParent;
+    int		    xNew, yNew;
+    HDC		    hdc;
 
     GetWindowRect(hwndChild, &rChild);
     wChild = rChild.right - rChild.left;
@@ -2317,32 +2322,39 @@
 
     /* If Vim is minimized put the window in the middle of the screen. */
     if (hwndParent == NULL || IsMinimized(hwndParent))
-	SystemParametersInfo(SPI_GETWORKAREA, 0, &rParent, 0);
+	get_work_area(&rParent);
     else
 	GetWindowRect(hwndParent, &rParent);
     wParent = rParent.right - rParent.left;
     hParent = rParent.bottom - rParent.top;
 
-    hdc = GetDC(hwndChild);
-    wScreen = GetDeviceCaps (hdc, HORZRES);
-    hScreen = GetDeviceCaps (hdc, VERTRES);
-    ReleaseDC(hwndChild, hdc);
-
-    xNew = rParent.left + ((wParent - wChild) /2);
-    if (xNew < 0)
+    moninfo.cbSize = sizeof(MONITORINFO);
+    mon = MonitorFromWindow(hwndChild, MONITOR_DEFAULTTOPRIMARY);
+    if (mon != NULL && GetMonitorInfo(mon, &moninfo))
     {
-	xNew = 0;
+	rScreen = moninfo.rcWork;
     }
-    else if ((xNew+wChild) > wScreen)
+    else
     {
-	xNew = wScreen - wChild;
+	hdc = GetDC(hwndChild);
+	rScreen.left = 0;
+	rScreen.top = 0;
+	rScreen.right = GetDeviceCaps(hdc, HORZRES);
+	rScreen.bottom = GetDeviceCaps(hdc, VERTRES);
+	ReleaseDC(hwndChild, hdc);
     }
 
-    yNew = rParent.top	+ ((hParent - hChild) /2);
-    if (yNew < 0)
-	yNew = 0;
-    else if ((yNew+hChild) > hScreen)
-	yNew = hScreen - hChild;
+    xNew = rParent.left + ((wParent - wChild) / 2);
+    if (xNew < rScreen.left)
+	xNew = rScreen.left;
+    else if ((xNew + wChild) > rScreen.right)
+	xNew = rScreen.right - wChild;
+
+    yNew = rParent.top + ((hParent - hChild) / 2);
+    if (yNew < rScreen.top)
+	yNew = rScreen.top;
+    else if ((yNew + hChild) > rScreen.bottom)
+	yNew = rScreen.bottom - hChild;
 
     return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0,
 						   SWP_NOSIZE | SWP_NOZORDER);
@@ -3539,12 +3551,12 @@
     filterp = convert_filterW(filter);
 
     vim_memset(&fileStruct, 0, sizeof(OPENFILENAMEW));
-#ifdef OPENFILENAME_SIZE_VERSION_400W
+#  ifdef OPENFILENAME_SIZE_VERSION_400W
     /* be compatible with Windows NT 4.0 */
     fileStruct.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
-#else
+#  else
     fileStruct.lStructSize = sizeof(fileStruct);
-#endif
+#  endif
 
     if (title != NULL)
 	titlep = enc_to_utf16(title, NULL);
@@ -3581,10 +3593,10 @@
      * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
      */
     fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY);
-#ifdef FEAT_SHORTCUT
+#  ifdef FEAT_SHORTCUT
     if (curbuf->b_p_bin)
 	fileStruct.Flags |= OFN_NODEREFERENCELINKS;
-#endif
+#  endif
     if (saving)
     {
 	if (!GetSaveFileNameW(&fileStruct))
@@ -5559,7 +5571,7 @@
     MONITORINFO	    moninfo;
 
     /* work out which monitor the window is on, and get *it's* work area */
-    mon = MonitorFromWindow(s_hwnd, 1 /*MONITOR_DEFAULTTOPRIMARY*/);
+    mon = MonitorFromWindow(s_hwnd, MONITOR_DEFAULTTOPRIMARY);
     if (mon != NULL)
     {
 	moninfo.cbSize = sizeof(MONITORINFO);
diff --git a/src/message.c b/src/message.c
index 32360a9..7dda6fa 100644
--- a/src/message.c
+++ b/src/message.c
@@ -42,6 +42,9 @@
 static char_u	*confirm_msg = NULL;		/* ":confirm" message */
 static char_u	*confirm_msg_tail;		/* tail of confirm_msg */
 #endif
+#ifdef FEAT_JOB_CHANNEL
+static int emsg_to_channel_log = FALSE;
+#endif
 
 struct msg_hist
 {
@@ -166,6 +169,14 @@
 		&& STRCMP(s, last_msg_hist->msg)))
 	add_msg_hist(s, -1, attr);
 
+#ifdef FEAT_JOB_CHANNEL
+    if (emsg_to_channel_log)
+    {
+	/* Write message in the channel log. */
+	ch_logs(NULL, "ERROR: %s", (char *)s);
+    }
+#endif
+
     /* When displaying keep_msg, don't let msg_start() free it, caller must do
      * that. */
     if (s == keep_msg)
@@ -556,6 +567,7 @@
 {
     int		attr;
     char_u	*p;
+    int		r;
 #ifdef FEAT_EVAL
     int		ignore = FALSE;
     int		severe;
@@ -624,6 +636,9 @@
 		}
 		redir_write(s, -1);
 	    }
+#ifdef FEAT_JOB_CHANNEL
+	    ch_logs(NULL, "ERROR: %s", (char *)s);
+#endif
 	    return TRUE;
 	}
 
@@ -650,6 +665,9 @@
 				     * and a redraw is expected because
 				     * msg_scrolled is non-zero */
 
+#ifdef FEAT_JOB_CHANNEL
+    emsg_to_channel_log = TRUE;
+#endif
     /*
      * Display name and line number for the source of the error.
      */
@@ -659,7 +677,12 @@
      * Display the error message itself.
      */
     msg_nowait = FALSE;			/* wait for this msg */
-    return msg_attr(s, attr);
+    r = msg_attr(s, attr);
+
+#ifdef FEAT_JOB_CHANNEL
+    emsg_to_channel_log = FALSE;
+#endif
+    return r;
 }
 
 
diff --git a/src/misc2.c b/src/misc2.c
index 27d26be..baa614d 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1740,27 +1740,6 @@
 }
 #endif
 
-#ifdef VIM_MEMCMP
-/*
- * Return zero when "b1" and "b2" are the same for "len" bytes.
- * Return non-zero otherwise.
- */
-    int
-vim_memcmp(void *b1, void *b2, size_t len)
-{
-    char_u  *p1 = (char_u *)b1, *p2 = (char_u *)b2;
-
-    for ( ; len > 0; --len)
-    {
-	if (*p1 != *p2)
-	    return 1;
-	++p1;
-	++p2;
-    }
-    return 0;
-}
-#endif
-
 /* skipped when generating prototypes, the prototype is in vim.h */
 #ifdef VIM_MEMMOVE
 /*
@@ -6263,3 +6242,31 @@
 # endif
 }
 #endif
+
+#ifdef ELAPSED_TIMEVAL  /* no PROTO here, proto is defined in vim.h */
+/*
+ * Return time in msec since "start_tv".
+ */
+    long
+elapsed(struct timeval *start_tv)
+{
+    struct timeval  now_tv;
+
+    gettimeofday(&now_tv, NULL);
+    return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
+	 + (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
+}
+#endif
+
+#ifdef ELAPSED_TICKCOUNT
+/*
+ * Return time in msec since "start_tick".
+ */
+    long
+elapsed(DWORD start_tick)
+{
+    DWORD	now = GetTickCount();
+
+    return (long)now - (long)start_tick;
+}
+#endif
diff --git a/src/option.c b/src/option.c
index 2b9ba2d..7356816 100644
--- a/src/option.c
+++ b/src/option.c
@@ -452,10 +452,11 @@
 #define P_NFNAME       0x400000L /* only normal file name chars allowed */
 #define P_INSECURE     0x800000L /* option was set from a modeline */
 #define P_PRI_MKRC    0x1000000L /* priority for :mkvimrc (setting option has
-				   side effects) */
+				    side effects) */
 #define P_NO_ML       0x2000000L /* not allowed in modeline */
 #define P_CURSWANT    0x4000000L /* update curswant required; not needed when
 				  * there is a redraw flag */
+#define P_NDNAME      0x8000000L /* only normal dir name chars allowed */
 
 #define ISK_LATIN1  (char_u *)"@,48-57,_,192-255"
 
@@ -992,7 +993,7 @@
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
-    {"dictionary",  "dict", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP,
+    {"dictionary",  "dict", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
 #ifdef FEAT_INS_EXPAND
 			    (char_u *)&p_dict, PV_DICT,
 #else
@@ -2058,7 +2059,7 @@
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCRIPTID_INIT},
-    {"printexpr", "pexpr",  P_STRING|P_VI_DEF,
+    {"printexpr", "pexpr",  P_STRING|P_VI_DEF|P_SECURE,
 #ifdef FEAT_POSTSCRIPT
 			    (char_u *)&p_pexpr, PV_NONE,
 			    {(char_u *)"", (char_u *)0L}
@@ -2659,7 +2660,7 @@
     {"textwidth",   "tw",   P_NUM|P_VI_DEF|P_VIM|P_RBUF,
 			    (char_u *)&p_tw, PV_TW,
 			    {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
-    {"thesaurus",   "tsr",  P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP,
+    {"thesaurus",   "tsr",  P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
 #ifdef FEAT_INS_EXPAND
 			    (char_u *)&p_tsr, PV_TSR,
 #else
@@ -5876,11 +5877,15 @@
 	errmsg = e_secure;
     }
 
-    /* Check for a "normal" file name in some options.  Disallow a path
-     * separator (slash and/or backslash), wildcards and characters that are
-     * often illegal in a file name. */
-    else if ((options[opt_idx].flags & P_NFNAME)
-			 && vim_strpbrk(*varp, (char_u *)"/\\*?[|<>") != NULL)
+    /* Check for a "normal" directory or file name in some options.  Disallow a
+     * path separator (slash and/or backslash), wildcards and characters that
+     * are often illegal in a file name. Be more permissive if "secure" is off.
+     */
+    else if (((options[opt_idx].flags & P_NFNAME)
+		    && vim_strpbrk(*varp, (char_u *)(secure
+			    ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
+	  || ((options[opt_idx].flags & P_NDNAME)
+		    && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL))
     {
 	errmsg = e_invarg;
     }
@@ -7021,6 +7026,7 @@
 
 
 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+    /* 'toolbar' */
     else if (varp == &p_toolbar)
     {
 	if (opt_strings_flags(p_toolbar, p_toolbar_values,
@@ -7235,6 +7241,7 @@
 #endif
 
 #if defined(FEAT_RENDER_OPTIONS)
+    /* 'renderoptions' */
     else if (varp == &p_rop && gui.in_use)
     {
 	if (!gui_mch_set_rendering_options(p_rop))
@@ -7262,19 +7269,19 @@
     else
     {
 	p = NULL;
-	if (varp == &p_ww)
+	if (varp == &p_ww) /* 'whichwrap' */
 	    p = (char_u *)WW_ALL;
-	if (varp == &p_shm)
+	if (varp == &p_shm) /* 'shortmess' */
 	    p = (char_u *)SHM_ALL;
-	else if (varp == &(p_cpo))
+	else if (varp == &(p_cpo)) /* 'cpoptions' */
 	    p = (char_u *)CPO_ALL;
-	else if (varp == &(curbuf->b_p_fo))
+	else if (varp == &(curbuf->b_p_fo)) /* 'formatoptions' */
 	    p = (char_u *)FO_ALL;
 #ifdef FEAT_CONCEAL
-	else if (varp == &curwin->w_p_cocu)
+	else if (varp == &curwin->w_p_cocu) /* 'concealcursor' */
 	    p = (char_u *)COCU_ALL;
 #endif
-	else if (varp == &p_mouse)
+	else if (varp == &p_mouse) /* 'mouse' */
 	{
 #ifdef FEAT_MOUSE
 	    p = (char_u *)MOUSE_ALL;
@@ -7284,7 +7291,7 @@
 #endif
 	}
 #if defined(FEAT_GUI)
-	else if (varp == &p_go)
+	else if (varp == &p_go) /* 'guioptions' */
 	    p = (char_u *)GO_ALL;
 #endif
 	if (p != NULL)
diff --git a/src/os_mswin.c b/src/os_mswin.c
index dc55389..408438e 100644
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -40,7 +40,7 @@
 #  include <dlgs.h>
 #  include <winspool.h>
 #  include <commdlg.h>
-#endif
+# endif
 
 #endif /* PROTO */
 
@@ -1619,7 +1619,9 @@
 
 	if (psettings->n_uncollated_copies == 0)
 	    psettings->n_uncollated_copies = 1;
-    } else {
+    }
+    else
+    {
 	psettings->n_collated_copies = 1;
 	psettings->n_uncollated_copies = 1;
     }
diff --git a/src/os_unix.c b/src/os_unix.c
index a63eb6e..aa3c3e5 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -376,21 +376,6 @@
 	RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
 }
 
-#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-/*
- * Return time in msec since "start_tv".
- */
-    static long
-elapsed(struct timeval *start_tv)
-{
-    struct timeval  now_tv;
-
-    gettimeofday(&now_tv, NULL);
-    return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
-	 + (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
-}
-#endif
-
 /*
  * mch_inchar(): low level input function.
  * Get a characters from the keyboard.
@@ -411,10 +396,10 @@
     int		did_start_blocking = FALSE;
     long	wait_time;
     long	elapsed_time = 0;
-#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-    struct timeval  start_tv;
+#ifdef ELAPSED_FUNC
+    ELAPSED_TYPE start_tv;
 
-    gettimeofday(&start_tv, NULL);
+    ELAPSED_INIT(start_tv);
 #endif
 
     /* repeat until we got a character or waited long enough */
@@ -438,8 +423,8 @@
 	    else
 		/* going to block after p_ut */
 		wait_time = p_ut;
-#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-	    elapsed_time = elapsed(&start_tv);
+#ifdef ELAPSED_FUNC
+	    elapsed_time = ELAPSED_FUNC(start_tv);
 #endif
 	    wait_time -= elapsed_time;
 	    if (wait_time < 0)
@@ -477,6 +462,10 @@
 	/* Checking if a job ended requires polling.  Do this every 100 msec. */
 	if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
 	    wait_time = 100L;
+	/* If there is readahead then parse_queued_messages() timed out and we
+	 * should call it again soon. */
+	if ((wait_time < 0 || wait_time > 100L) && channel_any_readahead())
+	    wait_time = 10L;
 #endif
 
 	/*
@@ -1554,18 +1543,16 @@
 
 #ifdef FEAT_X11
 
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
+# if defined(ELAPSED_TIMEVAL) \
 	&& (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
 
-static void xopen_message(struct timeval *start_tv);
-
 /*
  * Give a message about the elapsed time for opening the X window.
  */
     static void
-xopen_message(struct timeval *start_tv)
+xopen_message(long elapsed_msec)
 {
-    smsg((char_u *)_("Opening the X display took %ld msec"), elapsed(start_tv));
+    smsg((char_u *)_("Opening the X display took %ld msec"), elapsed_msec);
 }
 # endif
 #endif
@@ -1864,11 +1851,11 @@
 #endif
 	if (x11_display != NULL)
 	{
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# ifdef ELAPSED_FUNC
 	    if (p_verbose > 0)
 	    {
 		verbose_enter();
-		xopen_message(&start_tv);
+		xopen_message(ELAPSED_FUNC(start_tv));
 		verbose_leave();
 	    }
 # endif
@@ -4630,8 +4617,8 @@
 		    ga_init2(&ga, 1, BUFLEN);
 
 		noread_cnt = 0;
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-		gettimeofday(&start_tv, NULL);
+# ifdef ELAPSED_FUNC
+		ELAPSED_INIT(start_tv);
 # endif
 		for (;;)
 		{
@@ -4666,8 +4653,8 @@
 			  /* Get extra characters when we don't have any.
 			   * Reset the counter and timer. */
 			  noread_cnt = 0;
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-			  gettimeofday(&start_tv, NULL);
+# ifdef ELAPSED_FUNC
+			  ELAPSED_INIT(start_tv);
 # endif
 			  len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
 		      }
@@ -4886,10 +4873,10 @@
 			if (got_int)
 			    break;
 
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# ifdef ELAPSED_FUNC
 			if (wait_pid == 0)
 			{
-			    long	    msec = elapsed(&start_tv);
+			    long	msec = ELAPSED_FUNC(start_tv);
 
 			    /* Avoid that we keep looping here without
 			     * checking for a CTRL-C for a long time.  Don't
@@ -5632,15 +5619,14 @@
     /* May retry getting characters after an event was handled. */
 # define MAY_LOOP
 
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# ifdef ELAPSED_FUNC
     /* Remember at what time we started, so that we know how much longer we
      * should wait after being interrupted. */
-#  define USE_START_TV
     long	    start_msec = msec;
-    struct timeval  start_tv;
+    ELAPSED_TYPE  start_tv;
 
     if (msec > 0)
-	gettimeofday(&start_tv, NULL);
+	ELAPSED_INIT(start_tv);
 # endif
 
     /* Handle being called recursively.  This may happen for the session
@@ -5947,9 +5933,9 @@
 	/* We're going to loop around again, find out for how long */
 	if (msec > 0)
 	{
-# ifdef USE_START_TV
+# ifdef ELAPSED_FUNC
 	    /* Compute remaining wait time. */
-	    msec = start_msec - elapsed(&start_tv);
+	    msec = start_msec - ELAPSED_FUNC(start_tv);
 # else
 	    /* Guess we got interrupted halfway. */
 	    msec = msec / 2;
@@ -7046,11 +7032,11 @@
 #if defined(HAVE_SETJMP_H)
 	int (*oldIOhandler)();
 #endif
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-	struct timeval  start_tv;
+# ifdef ELAPSED_FUNC
+	ELAPSED_TYPE  start_tv;
 
 	if (p_verbose > 0)
-	    gettimeofday(&start_tv, NULL);
+	    ELAPSED_INIT(start_tv);
 # endif
 
 	/* Ignore X errors while opening the display */
@@ -7092,11 +7078,11 @@
 	/* Catch terminating error of the X server connection. */
 	(void)XSetIOErrorHandler(x_IOerror_handler);
 
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# ifdef ELAPSED_FUNC
 	if (p_verbose > 0)
 	{
 	    verbose_enter();
-	    xopen_message(&start_tv);
+	    xopen_message(ELAPSED_FUNC(start_tv));
 	    verbose_leave();
 	}
 # endif
diff --git a/src/os_vms_conf.h b/src/os_vms_conf.h
index 5c110f2..9aa7526 100644
--- a/src/os_vms_conf.h
+++ b/src/os_vms_conf.h
@@ -101,7 +101,6 @@
 #define HAVE_STRTOL
 #define HAVE_TGETENT
 #define HAVE_MEMSET
-#define HAVE_MEMCMP
 #define HAVE_STRERROR
 #define HAVE_FCHOWN
 #define HAVE_RENAME
diff --git a/src/os_win32.c b/src/os_win32.c
index 34b2ca8..e08adcb 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -1351,9 +1351,15 @@
 	    DWORD dwWaitTime = dwEndTime - dwNow;
 
 #ifdef FEAT_JOB_CHANNEL
-	    /* Check channel while waiting input. */
+	    /* Check channel while waiting for input. */
 	    if (dwWaitTime > 100)
+	    {
 		dwWaitTime = 100;
+		/* If there is readahead then parse_queued_messages() timed out
+		 * and we should call it again soon. */
+		if (channel_any_readahead())
+		    dwWaitTime = 10;
+	    }
 #endif
 #ifdef FEAT_MZSCHEME
 	    if (mzthreads_allowed() && p_mzq > 0
@@ -4287,9 +4293,6 @@
 		    /* Get extra characters when we don't have any.  Reset the
 		     * counter and timer. */
 		    noread_cnt = 0;
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
-		    gettimeofday(&start_tv, NULL);
-# endif
 		    len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
 		}
 		if (ta_len > 0 || len > 0)
diff --git a/src/osdef1.h.in b/src/osdef1.h.in
index a11e6ea..5519104 100644
--- a/src/osdef1.h.in
+++ b/src/osdef1.h.in
@@ -50,12 +50,7 @@
 #ifdef HAVE_MEMSET
 extern void	*memset(void *, int, size_t);
 #endif
-#ifdef HAVE_BCMP
-extern int	bcmp(void *, void *, size_t);
-#endif
-#ifdef HAVE_MEMCMP
 extern int	memcmp(const void *, const void *, size_t);
-#endif
 #ifdef HAVE_STRPBRK
 extern char	*strpbrk(const char *, const char *);
 #endif
diff --git a/src/popupmnu.c b/src/popupmnu.c
index 19d215b..307dbbe 100644
--- a/src/popupmnu.c
+++ b/src/popupmnu.c
@@ -105,7 +105,8 @@
 
     /* Put the pum below "row" if possible.  If there are few lines decide on
      * where there is more room. */
-    if (row - above_row >= below_row - row)
+    if (row + 2 >= below_row - pum_height
+			    && row - above_row > (below_row - above_row) / 2)
     {
 	/* pum above "row" */
 
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 6a52d8b..a54d387 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -25,6 +25,7 @@
 int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
 int channel_can_write_to(channel_T *channel);
 int channel_is_open(channel_T *channel);
+int channel_has_readahead(channel_T *channel, ch_part_T part);
 char *channel_status(channel_T *channel, int req_part);
 void channel_info(channel_T *channel, dict_T *dict);
 void channel_close(channel_T *channel, int invoke_close_cb);
@@ -32,7 +33,6 @@
 void channel_clear(channel_T *channel);
 void channel_free_all(void);
 char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout);
-int channel_read_json_block(channel_T *channel, ch_part_T part, int timeout_arg, int id, typval_T **rettv);
 void common_channel_read(typval_T *argvars, typval_T *rettv, int raw);
 channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
 void channel_handle_events(void);
@@ -44,6 +44,7 @@
 int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in);
 int channel_select_check(int ret_in, void *rfds_in, void *wfds_in);
 int channel_parse_messages(void);
+int channel_any_readahead(void);
 int set_ref_in_channel(int copyID);
 ch_part_T channel_part_send(channel_T *channel);
 ch_part_T channel_part_read(channel_T *channel);
diff --git a/src/search.c b/src/search.c
index cedcad9..36410e5 100644
--- a/src/search.c
+++ b/src/search.c
@@ -1695,7 +1695,8 @@
 		}
 		else
 		{
-		    if (vim_memcmp(p + col, lastc_bytes, lastc_bytelen) == 0 && stop)
+		    if (memcmp(p + col, lastc_bytes, lastc_bytelen) == 0
+								       && stop)
 			break;
 		}
 		stop = TRUE;
diff --git a/src/structs.h b/src/structs.h
index 1b73e37..3fdfb5f 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1474,6 +1474,7 @@
     typval_T	*jq_value;
     jsonq_T	*jq_next;
     jsonq_T	*jq_prev;
+    int		jq_no_callback; /* TRUE when no callback was found */
 };
 
 struct cbq_S
@@ -1597,6 +1598,7 @@
     partial_T	*ch_partial;
     char_u	*ch_close_cb;	/* call when channel is closed */
     partial_T	*ch_close_partial;
+    int		ch_drop_never;
 
     job_T	*ch_job;	/* Job that uses this channel; this does not
 				 * count as a reference to avoid a circular
@@ -1684,6 +1686,7 @@
     partial_T	*jo_close_partial; /* not referenced! */
     char_u	*jo_exit_cb;	/* not allocated! */
     partial_T	*jo_exit_partial; /* not referenced! */
+    int		jo_drop_never;
     int		jo_waittime;
     int		jo_timeout;
     int		jo_out_timeout;
diff --git a/src/tag.c b/src/tag.c
index 14fdcf8..646cbcd 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -742,7 +742,7 @@
 			/* skip backslash used for escaping a command char or
 			 * a backslash */
 			if (*p == '\\' && (*(p + 1) == *tagp.command
-				        || *(p + 1) == '\\'))
+					|| *(p + 1) == '\\'))
 			    ++p;
 
 			if (*p == TAB)
@@ -1356,6 +1356,7 @@
     char_u	*help_lang_find = NULL;		/* lang to be found */
     char_u	help_lang[3];			/* lang of current tags file */
     char_u	*saved_pat = NULL;		/* copy of pat[] */
+    int		is_txt = FALSE;			/* flag of file extension */
 #endif
 
     pat_T	orgpat;			/* holds unconverted pattern info */
@@ -1388,7 +1389,7 @@
      */
     switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags)
     {
-	case TC_FOLLOWIC:                break;
+	case TC_FOLLOWIC:		 break;
 	case TC_IGNORE:    p_ic = TRUE;  break;
 	case TC_MATCH:     p_ic = FALSE; break;
 	case TC_FOLLOWSCS: p_ic = ignorecase(pat); break;
@@ -1476,6 +1477,15 @@
      * When the tag file is case-fold sorted, it is either one or the other.
      * Only ignore case when TAG_NOIC not used or 'ignorecase' set.
      */
+#ifdef FEAT_MULTI_LANG
+    /* Set a flag if the file extension is .txt */
+    if ((flags & TAG_KEEP_LANG)
+	    && help_lang_find == NULL
+	    && curbuf->b_fname != NULL
+	    && (i = (int)STRLEN(curbuf->b_fname)) > 4
+	    && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0)
+	is_txt = TRUE;
+#endif
 #ifdef FEAT_TAG_BINS
     orgpat.regmatch.rm_ic = ((p_ic || !noic)
 				&& (findall || orgpat.headlen == 0 || !p_tbs));
@@ -1509,14 +1519,19 @@
 #ifdef FEAT_MULTI_LANG
 	    if (curbuf->b_help)
 	    {
-		/* Prefer help tags according to 'helplang'.  Put the
-		 * two-letter language name in help_lang[]. */
-		i = (int)STRLEN(tag_fname);
-		if (i > 3 && tag_fname[i - 3] == '-')
-		    STRCPY(help_lang, tag_fname + i - 2);
-		else
+		/* Keep en if the file extension is .txt*/
+		if (is_txt)
 		    STRCPY(help_lang, "en");
-
+		else
+		{
+		    /* Prefer help tags according to 'helplang'.  Put the
+		     * two-letter language name in help_lang[]. */
+		    i = (int)STRLEN(tag_fname);
+		    if (i > 3 && tag_fname[i - 3] == '-')
+			STRCPY(help_lang, tag_fname + i - 2);
+		    else
+			STRCPY(help_lang, "en");
+		}
 		/* When searching for a specific language skip tags files
 		 * for other languages. */
 		if (help_lang_find != NULL
@@ -2400,7 +2415,7 @@
 			      mfp2 = ((struct match_found **)
 						  (ga_match[mtt].ga_data))[i];
 			      if (mfp2->len == mfp->len
-				      && vim_memcmp(mfp2->match, mfp->match,
+				      && memcmp(mfp2->match, mfp->match,
 						       (size_t)mfp->len) == 0)
 				  break;
 			      fast_breakcheck();
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 49d2de0..17c70f3 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -63,8 +63,6 @@
 	test88.out \
 	test90.out \
 	test91.out \
-	test92.out \
-	test93.out \
 	test94.out \
 	test95.out \
 	test98.out \
@@ -167,6 +165,8 @@
 	    test_man.res \
 	    test_marks.res \
 	    test_matchadd_conceal.res \
+	    test_mksession.res \
+	    test_mksession_utf8.res \
 	    test_nested_function.res \
 	    test_netbeans.res \
 	    test_normal.res \
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
index 6962cf0..43e1416 100644
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -92,7 +92,7 @@
        test72.out test75.out \
        test77a.out test78.out test79.out test80.out \
        test82.out test84.out test88.out test89.out \
-       test90.out test91.out test92.out test93.out test94.out \
+       test90.out test91.out test94.out \
        test95.out test98.out test99.out \
        test103.out test104.out \
        test107.out test108.out\
diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim
index 45a2ea4..8160af3 100644
--- a/src/testdir/shared.vim
+++ b/src/testdir/shared.vim
@@ -88,7 +88,7 @@
 
     call call(function(a:testfunc), [port])
   catch
-    call assert_false(1, "Caught exception: " . v:exception)
+    call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint)
   finally
     call s:kill_server(a:cmd)
   endtry
diff --git a/src/testdir/test92.in b/src/testdir/test92.in
deleted file mode 100644
index 9593aec..0000000
--- a/src/testdir/test92.in
+++ /dev/null
@@ -1,48 +0,0 @@
-vim: set ft=vim fenc=utf-8:
-
-Tests if :mksession saves cursor columns correctly in presence of tab and 
-multibyte characters when fileencoding=utf-8.
-
-STARTTEST
-:so mbyte.vim
-:if !has('mksession')
-:  e! test.ok
-:  wq! test.out
-:endif
-:set sessionoptions=buffers splitbelow fileencoding=utf-8
-/^start:
-:vsplit
-j16|:split
-j16|:split
-j16|:split
-j8|:split
-j8|:split
-j16|:split
-j16|:split
-j16|:wincmd l
-/^start:
-:set nowrap
-j16|3zl:split
-j016|3zl:split
-j016|3zl:split
-j08|3zl:split
-j08|3zl:split
-j016|3zl:split
-j016|3zl:split
-j016|3zl:split
-:mksession! test.out
-:new test.out
-:v/\(^ *normal! 0\|^ *exe 'normal!\)/d
-:w! test.out
-:qa!
-ENDTEST
-
-start:
-no multibyte chAracter
-	one leaDing tab
-    four leadinG spaces
-two		consecutive tabs
-two	tabs	in one line
-one … multibyteCharacter
-a “b” two multiByte characters
-“c”1€ three mulTibyte characters
diff --git a/src/testdir/test92.ok b/src/testdir/test92.ok
deleted file mode 100644
index cca5ec4..0000000
--- a/src/testdir/test92.ok
+++ /dev/null
@@ -1,26 +0,0 @@
-normal! 016|
-normal! 016|
-normal! 016|
-normal! 08|
-normal! 08|
-normal! 016|
-normal! 016|
-normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 8 . '|'
-  normal! 08|
-  exe 'normal! ' . s:c . '|zs' . 8 . '|'
-  normal! 08|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
diff --git a/src/testdir/test93.in b/src/testdir/test93.in
deleted file mode 100644
index 877838c..0000000
--- a/src/testdir/test93.in
+++ /dev/null
@@ -1,48 +0,0 @@
-vim: set ft=vim fenc=latin1:
-
-Tests if :mksession saves cursor columns correctly in presence of tab and 
-multibyte characters when fileencoding=latin1.
-
-STARTTEST
-:so mbyte.vim
-:if !has('mksession')
-:  e! test.ok
-:  wq! test.out
-:endif
-:set sessionoptions=buffers splitbelow fileencoding=latin1
-/^start:
-:vsplit
-j16|:split
-j16|:split
-j16|:split
-j8|:split
-j8|:split
-j16|:split
-j16|:split
-j16|:wincmd l
-/^start:
-:set nowrap
-j16|3zl:split
-j016|3zl:split
-j016|3zl:split
-j08|3zl:split
-j08|3zl:split
-j016|3zl:split
-j016|3zl:split
-j016|3zl:split
-:mksession! test.out
-:new test.out
-:v/\(^ *normal! 0\|^ *exe 'normal!\)/d
-:w! test.out
-:qa!
-ENDTEST
-
-start:
-no multibyte chAracter
-	one leaDing tab
-    four leadinG spaces
-two		consecutive tabs
-two	tabs	in one line
-one ä multibyteCharacter
-aä Ä  two multiByte characters
-Aäöü  three mulTibyte characters
diff --git a/src/testdir/test93.ok b/src/testdir/test93.ok
deleted file mode 100644
index cca5ec4..0000000
--- a/src/testdir/test93.ok
+++ /dev/null
@@ -1,26 +0,0 @@
-normal! 016|
-normal! 016|
-normal! 016|
-normal! 08|
-normal! 08|
-normal! 016|
-normal! 016|
-normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 8 . '|'
-  normal! 08|
-  exe 'normal! ' . s:c . '|zs' . 8 . '|'
-  normal! 08|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
-  exe 'normal! ' . s:c . '|zs' . 16 . '|'
-  normal! 016|
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 42e0e04..31c2e50 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -58,6 +58,9 @@
   " string with ][ should work
   call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that'))
 
+  " nothing to read now
+  call assert_equal(0, ch_canread(handle))
+
   " sending three messages quickly then reading should work
   for i in range(3)
     call ch_sendexpr(handle, 'echo hello ' . i)
@@ -126,6 +129,9 @@
   call ch_setoptions(handle, {'mode': 'json'})
   call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475")
   call ch_setoptions(handle, {'callback': ''})
+  call ch_setoptions(handle, {'drop': 'never'})
+  call ch_setoptions(handle, {'drop': 'auto'})
+  call assert_fails("call ch_setoptions(handle, {'drop': 'bad'})", "E475")
 
   " Send an eval request that works.
   call assert_equal('ok', ch_evalexpr(handle, 'eval-works'))
@@ -246,6 +252,7 @@
 """""""""
 
 func Ch_handler(chan, msg)
+  call ch_log('Ch_handler()')
   unlet g:Ch_reply
   let g:Ch_reply = a:msg
 endfunc
@@ -269,6 +276,7 @@
 endfunc
 
 func Test_channel_handler()
+call ch_logfile('channellog', 'w')
   call ch_log('Test_channel_handler()')
   let g:Ch_reply = ""
   let s:chopt.callback = 'Ch_handler'
@@ -368,7 +376,7 @@
   endif
   call ch_setoptions(handle, {'mode': 'raw'})
 
-  " The message are sent raw, we do our own JSON strings here.
+  " The messages are sent raw, we do our own JSON strings here.
   call ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'})
   call WaitFor('g:Ch_reply1 != ""')
   call assert_equal("[1, \"got it\"]", g:Ch_reply1)
@@ -431,7 +439,10 @@
     return
   endif
   call ch_log('Test_raw_pipe()')
-  let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'})
+  " Add a dummy close callback to avoid that messages are dropped when calling
+  " ch_canread().
+  let job = job_start(s:python . " test_channel_pipe.py",
+	\ {'mode': 'raw', 'drop': 'never'})
   call assert_equal(v:t_job, type(job))
   call assert_equal("run", job_status(job))
 
@@ -458,6 +469,9 @@
     call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
 
     call ch_sendraw(job, "double this\n")
+    let g:handle = job_getchannel(job)
+    call WaitFor('ch_canread(g:handle)')
+    unlet g:handle
     let msg = ch_readraw(job)
     call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
 
diff --git a/src/testdir/test_help_tagjump.vim b/src/testdir/test_help_tagjump.vim
index d11a1fa..1d44389 100644
--- a/src/testdir/test_help_tagjump.vim
+++ b/src/testdir/test_help_tagjump.vim
@@ -141,4 +141,36 @@
   endtry
 endfunc
 
+func Test_help_respect_current_file_lang()
+  try
+    let list = []
+    call s:doc_config_setup()
+
+    if has('multi_lang')
+      function s:check_help_file_ext(help_keyword, ext)
+        exec 'help ' . a:help_keyword
+        call assert_equal(a:ext, expand('%:e'))
+        call feedkeys("\<C-]>", 'tx')
+        call assert_equal(a:ext, expand('%:e'))
+        pop
+        helpclose
+      endfunc
+
+      set rtp+=Xdir1/doc-ab
+      set rtp+=Xdir1/doc-ja
+
+      set helplang=ab
+      call s:check_help_file_ext('test-char', 'abx')
+      call s:check_help_file_ext('test-char@ja', 'jax')
+      set helplang=ab,ja
+      call s:check_help_file_ext('test-char@ja', 'jax')
+      call s:check_help_file_ext('test-char@en', 'txt')
+    endif
+  catch
+    call assert_exception('X')
+  finally
+    call s:doc_config_teardown()
+  endtry
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim
index ee6acff..243ede7 100644
--- a/src/testdir/test_history.vim
+++ b/src/testdir/test_history.vim
@@ -31,6 +31,30 @@
   call assert_equal('ls', histget(a:hist, -1))
   call assert_equal(4, histnr(a:hist))
 
+  let a=execute('history ' . a:hist)
+  call assert_match("^\n      #  \\S* history\n      3  buffers\n>     4  ls$", a)
+  let a=execute('history all')
+  call assert_match("^\n      #  .* history\n      3  buffers\n>     4  ls", a)
+
+  if len(a:hist) > 0
+    let a=execute('history ' . a:hist . ' 2')
+    call assert_match("^\n      #  \\S* history$", a)
+    let a=execute('history ' . a:hist . ' 3')
+    call assert_match("^\n      #  \\S* history\n      3  buffers$", a)
+    let a=execute('history ' . a:hist . ' 4')
+    call assert_match("^\n      #  \\S* history\n>     4  ls$", a)
+    let a=execute('history ' . a:hist . ' 3,4')
+    call assert_match("^\n      #  \\S* history\n      3  buffers\n>     4  ls$", a)
+    let a=execute('history ' . a:hist . ' -1')
+    call assert_match("^\n      #  \\S* history\n>     4  ls$", a)
+    let a=execute('history ' . a:hist . ' -2')
+    call assert_match("^\n      #  \\S* history\n      3  buffers$", a)
+    let a=execute('history ' . a:hist . ' -2,')
+    call assert_match("^\n      #  \\S* history\n      3  buffers\n>     4  ls$", a)
+    let a=execute('history ' . a:hist . ' -3')
+    call assert_match("^\n      #  \\S* history$", a)
+  endif
+
   " Test for removing entries matching a pattern
   for i in range(1, 3)
       call histadd(a:hist, 'text_' . i)
diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim
new file mode 100644
index 0000000..c19f3c5
--- /dev/null
+++ b/src/testdir/test_mksession.vim
@@ -0,0 +1,104 @@
+" Test for :mksession, :mkview and :loadview in latin1 encoding
+
+set encoding=latin1
+scriptencoding latin1
+
+if !has('multi_byte') || !has('mksession')
+  finish
+endif
+
+func Test_mksession()
+  tabnew
+  let wrap_save = &wrap
+  set sessionoptions=buffers splitbelow fileencoding=latin1
+  call setline(1, [
+    \   'start:',
+    \   'no multibyte chAracter',
+    \   '	one leaDing tab',
+    \   '    four leadinG spaces',
+    \   'two		consecutive tabs',
+    \   'two	tabs	in one line',
+    \   'one ä multibyteCharacter',
+    \   'aä Ä  two multiByte characters',
+    \   'Aäöü  three mulTibyte characters'
+    \ ])
+  let tmpfile = tempname()
+  exec 'w! ' . tmpfile
+  /^start:
+  set wrap
+  vsplit
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j8|
+  split
+  norm! j8|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  wincmd l
+
+  set nowrap
+  /^start:
+  norm! j16|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j08|3zl
+  split
+  norm! j08|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  call wincol()
+  mksession! test_mks.out
+  let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
+  let expected = [
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 08|',
+    \   'normal! 08|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+    \   "  normal! 08|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+    \   "  normal! 08|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|"
+    \ ]
+  call assert_equal(expected, li)
+  tabclose!
+
+  call delete('test_mks.out')
+  call delete(tmpfile)
+  let &wrap = wrap_save
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_mksession_utf8.vim b/src/testdir/test_mksession_utf8.vim
new file mode 100644
index 0000000..c05a1d3
--- /dev/null
+++ b/src/testdir/test_mksession_utf8.vim
@@ -0,0 +1,104 @@
+" Test for :mksession, :mkview and :loadview in utf-8 encoding
+
+set encoding=utf-8
+scriptencoding utf-8
+
+if !has('multi_byte') || !has('mksession')
+  finish
+endif
+
+func Test_mksession_utf8()
+  tabnew
+  let wrap_save = &wrap
+  set sessionoptions=buffers splitbelow fileencoding=utf-8
+  call setline(1, [
+    \   'start:',
+    \   'no multibyte chAracter',
+    \   '	one leaDing tab',
+    \   '    four leadinG spaces',
+    \   'two		consecutive tabs',
+    \   'two	tabs	in one line',
+    \   'one … multibyteCharacter',
+    \   'a “b” two multiByte characters',
+    \   '“c”1€ three mulTibyte characters'
+    \ ])
+  let tmpfile = tempname()
+  exec 'w! ' . tmpfile
+  /^start:
+  set wrap
+  vsplit
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j8|
+  split
+  norm! j8|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  split
+  norm! j16|
+  wincmd l
+
+  set nowrap
+  /^start:
+  norm! j16|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j08|3zl
+  split
+  norm! j08|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  norm! j016|3zl
+  split
+  call wincol()
+  mksession! test_mks.out
+  let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
+  let expected = [
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 08|',
+    \   'normal! 08|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   'normal! 016|',
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+    \   "  normal! 08|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+    \   "  normal! 08|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|",
+    \   "  exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+    \   "  normal! 016|"
+    \ ]
+  call assert_equal(expected, li)
+  tabclose!
+
+  call delete('test_mks.out')
+  call delete(tmpfile)
+  let &wrap = wrap_save
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 3b6f662..6dfb1bb 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -106,3 +106,26 @@
   call assert_fails(":set kmp=trunc\x00name", "E544:")
   call assert_fails(":set kmp=trunc\x00name", "trunc")
 endfunc
+
+func Check_dir_option(name)
+  " Check that it's possible to set the option.
+  exe 'set ' . a:name . '=/usr/share/dict/words'
+  call assert_equal('/usr/share/dict/words', eval('&' . a:name))
+  exe 'set ' . a:name . '=/usr/share/dict/words,/and/there'
+  call assert_equal('/usr/share/dict/words,/and/there', eval('&' . a:name))
+  exe 'set ' . a:name . '=/usr/share/dict\ words'
+  call assert_equal('/usr/share/dict words', eval('&' . a:name))
+
+  " Check rejecting weird characters.
+  call assert_fails("set " . a:name . "=/not&there", "E474:")
+  call assert_fails("set " . a:name . "=/not>there", "E474:")
+  call assert_fails("set " . a:name . "=/not.*there", "E474:")
+endfunc
+
+func Test_dictionary()
+  call Check_dir_option('dictionary')
+endfunc
+
+func Test_thesaurus()
+  call Check_dir_option('thesaurus')
+endfunc
diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim
index 3f69fb9..1720107 100644
--- a/src/testdir/test_tabpage.vim
+++ b/src/testdir/test_tabpage.vim
@@ -65,6 +65,15 @@
     call assert_true(tabpagenr() == 2 && tabpagewinnr(2, '$') == 2 && tabpagewinnr(2) == 1)
     tabclose
     q
+    "
+    "
+    " Test for ":tab drop vertical-split-window" to jump test1 buffer
+    tabedit test1
+    vnew
+    tabfirst
+    tab drop test1
+    call assert_equal([2, 2, 2, 2], [tabpagenr('$'), tabpagenr(), tabpagewinnr(2, '$'), tabpagewinnr(2)])
+    1tabonly
   endif
   "
   "
diff --git a/src/version.c b/src/version.c
index 497746f..372d92f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,48 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    117,
+/**/
+    116,
+/**/
+    115,
+/**/
+    114,
+/**/
+    113,
+/**/
+    112,
+/**/
+    111,
+/**/
+    110,
+/**/
+    109,
+/**/
+    108,
+/**/
+    107,
+/**/
+    106,
+/**/
+    105,
+/**/
+    104,
+/**/
+    103,
+/**/
+    102,
+/**/
+    101,
+/**/
+    100,
+/**/
+    99,
+/**/
+    98,
+/**/
+    97,
+/**/
     96,
 /**/
     95,
diff --git a/src/vim.h b/src/vim.h
index eec3e4f..de26c63 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1733,17 +1733,6 @@
 void *vim_memset(void *, int, size_t);
 #endif
 
-#ifdef HAVE_MEMCMP
-# define vim_memcmp(p1, p2, len)   memcmp((p1), (p2), (len))
-#else
-# ifdef HAVE_BCMP
-#  define vim_memcmp(p1, p2, len)   bcmp((p1), (p2), (len))
-# else
-int vim_memcmp(void *, void *, size_t);
-#  define VIM_MEMCMP
-# endif
-#endif
-
 #if defined(UNIX) || defined(FEAT_GUI) || defined(VMS) \
 	|| defined(FEAT_CLIENTSERVER)
 # define USE_INPUT_BUF
@@ -2503,4 +2492,20 @@
 # define OPEN_CHR_FILES
 #endif
 
+#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# define ELAPSED_TIMEVAL
+# define ELAPSED_INIT(v) gettimeofday(&v, NULL)
+# define ELAPSED_FUNC(v) elapsed(&v)
+# define ELAPSED_TYPE struct timeval
+    long elapsed(struct timeval *start_tv);
+#else
+# if defined(WIN32)
+#  define ELAPSED_TICKCOUNT
+#  define ELAPSED_INIT(v) v = GetTickCount()
+#  define ELAPSED_FUNC(v) elapsed(v)
+#  define ELAPSED_TYPE DWORD
+    long elapsed(DWORD start_tick);
+# endif
+#endif
+
 #endif /* VIM__H */