diff src/os_unix.c @ 7:3fc0f57ecb91 v7.0001

updated for version 7.0001
author vimboss
date Sun, 13 Jun 2004 20:20:40 +0000
parents
children 4424b47a0797
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/os_unix.c
@@ -0,0 +1,6189 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved	by Bram Moolenaar
+ *	      OS/2 port by Paul Slootman
+ *	      VMS merge by Zoltan Arpadffy
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
+ *	     Also for OS/2, using the excellent EMX package!!!
+ *	     Also for BeOS and Atari MiNT.
+ *
+ * A lot of this file was originally written by Juergen Weigert and later
+ * changed beyond recognition.
+ */
+
+/*
+ * Some systems have a prototype for select() that has (int *) instead of
+ * (fd_set *), which is wrong. This define removes that prototype. We define
+ * our own prototype below.
+ * Don't use it for the Mac, it causes a warning for precompiled headers.
+ * TODO: use a configure check for precompiled headers?
+ */
+#ifndef __APPLE__
+# define select select_declared_wrong
+#endif
+
+#include "vim.h"
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include "os_unixx.h"	    /* unix includes for os_unix.c only */
+
+#ifdef USE_XSMP
+# include <X11/SM/SMlib.h>
+#endif
+
+/*
+ * Use this prototype for select, some include files have a wrong prototype
+ */
+#undef select
+#ifdef __BEOS__
+# define select	beos_select
+#endif
+
+#if defined(HAVE_SELECT)
+extern int   select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
+#endif
+
+#ifdef FEAT_MOUSE_GPM
+# include <gpm.h>
+/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
+ * I just copied relevant defines here. A cleaner solution would be to put gpm
+ * code into separate file and include there linux/keyboard.h
+ */
+/* #include <linux/keyboard.h> */
+# define KG_SHIFT	0
+# define KG_CTRL	2
+# define KG_ALT		3
+# define KG_ALTGR	1
+# define KG_SHIFTL	4
+# define KG_SHIFTR	5
+# define KG_CTRLL	6
+# define KG_CTRLR	7
+# define KG_CAPSSHIFT	8
+
+static void gpm_close __ARGS((void));
+static int gpm_open __ARGS((void));
+static int mch_gpm_process __ARGS((void));
+#endif
+
+/*
+ * end of autoconf section. To be extended...
+ */
+
+/* Are the following #ifdefs still required? And why? Is that for X11? */
+
+#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
+# ifdef SIGWINCH
+#  undef SIGWINCH
+# endif
+# ifdef TIOCGWINSZ
+#  undef TIOCGWINSZ
+# endif
+#endif
+
+#if defined(SIGWINDOW) && !defined(SIGWINCH)	/* hpux 9.01 has it */
+# define SIGWINCH SIGWINDOW
+#endif
+
+#ifdef FEAT_X11
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xatom.h>
+# ifdef FEAT_XCLIPBOARD
+#  include <X11/Intrinsic.h>
+#  include <X11/Shell.h>
+#  include <X11/StringDefs.h>
+static Widget	xterm_Shell = (Widget)0;
+static void xterm_update __ARGS((void));
+# endif
+
+# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
+Window	    x11_window = 0;
+# endif
+Display	    *x11_display = NULL;
+
+# ifdef FEAT_TITLE
+static int  get_x11_windis __ARGS((void));
+static void set_x11_title __ARGS((char_u *));
+static void set_x11_icon __ARGS((char_u *));
+# endif
+#endif
+
+#ifdef FEAT_TITLE
+static int get_x11_title __ARGS((int));
+static int get_x11_icon __ARGS((int));
+
+static char_u	*oldtitle = NULL;
+static int	did_set_title = FALSE;
+static char_u	*oldicon = NULL;
+static int	did_set_icon = FALSE;
+#endif
+
+static void may_core_dump __ARGS((void));
+
+static int  WaitForChar __ARGS((long));
+#if defined(__BEOS__)
+int  RealWaitForChar __ARGS((int, long, int *));
+#else
+static int  RealWaitForChar __ARGS((int, long, int *));
+#endif
+
+#ifdef FEAT_XCLIPBOARD
+static int do_xterm_trace __ARGS((void));
+#define XT_TRACE_DELAY	50	/* delay for xterm tracing */
+#endif
+
+static void handle_resize __ARGS((void));
+
+#if defined(SIGWINCH)
+static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
+#endif
+#if defined(SIGINT)
+static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
+#endif
+#if defined(SIGPWR)
+static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
+#endif
+#if defined(SIGALRM) && defined(FEAT_X11) \
+	&& defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
+# define SET_SIG_ALARM
+static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
+static int sig_alarm_called;
+#endif
+static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
+
+static void set_signals __ARGS((void));
+static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
+#ifndef __EMX__
+static int  have_wildcard __ARGS((int, char_u **));
+static int  have_dollars __ARGS((int, char_u **));
+#endif
+
+#ifndef NO_EXPANDPATH
+static int	pstrcmp __ARGS((const void *, const void *));
+static int	unix_expandpath __ARGS((garray_T *gap, char_u *path, int wildoff, int flags));
+#endif
+
+#ifndef __EMX__
+static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
+#endif
+
+#ifndef SIG_ERR
+# define SIG_ERR	((RETSIGTYPE (*)())-1)
+#endif
+
+static int	do_resize = FALSE;
+#ifndef __EMX__
+static char_u	*extra_shell_arg = NULL;
+static int	show_shell_mess = TRUE;
+#endif
+static int	deadly_signal = 0;	    /* The signal we caught */
+
+static int curr_tmode = TMODE_COOK;	/* contains current terminal mode */
+
+#ifdef USE_XSMP
+typedef struct
+{
+    SmcConn smcconn;	    /* The SM connection ID */
+    IceConn iceconn;	    /* The ICE connection ID */
+    Bool save_yourself;     /* If we're in the middle of a save_yourself */
+    Bool shutdown;	    /* If we're in shutdown mode */
+} xsmp_config_T;
+
+static xsmp_config_T xsmp;
+#endif
+
+#ifdef SYS_SIGLIST_DECLARED
+/*
+ * I have seen
+ *  extern char *_sys_siglist[NSIG];
+ * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
+ * that describe the signals. That is nearly what we want here.  But
+ * autoconf does only check for sys_siglist (without the underscore), I
+ * do not want to change everything today.... jw.
+ * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
+ */
+#endif
+
+static struct signalinfo
+{
+    int	    sig;	/* Signal number, eg. SIGSEGV etc */
+    char    *name;	/* Signal name (not char_u!). */
+    char    deadly;	/* Catch as a deadly signal? */
+} signal_info[] =
+{
+#ifdef SIGHUP
+    {SIGHUP,	    "HUP",	TRUE},
+#endif
+#ifdef SIGQUIT
+    {SIGQUIT,	    "QUIT",	TRUE},
+#endif
+#ifdef SIGILL
+    {SIGILL,	    "ILL",	TRUE},
+#endif
+#ifdef SIGTRAP
+    {SIGTRAP,	    "TRAP",	TRUE},
+#endif
+#ifdef SIGABRT
+    {SIGABRT,	    "ABRT",	TRUE},
+#endif
+#ifdef SIGEMT
+    {SIGEMT,	    "EMT",	TRUE},
+#endif
+#ifdef SIGFPE
+    {SIGFPE,	    "FPE",	TRUE},
+#endif
+#ifdef SIGBUS
+    {SIGBUS,	    "BUS",	TRUE},
+#endif
+#ifdef SIGSEGV
+    {SIGSEGV,	    "SEGV",	TRUE},
+#endif
+#ifdef SIGSYS
+    {SIGSYS,	    "SYS",	TRUE},
+#endif
+#ifdef SIGALRM
+    {SIGALRM,	    "ALRM",	FALSE},	/* Perl's alarm() can trigger it */
+#endif
+#ifdef SIGTERM
+    {SIGTERM,	    "TERM",	TRUE},
+#endif
+#ifdef SIGVTALRM
+    {SIGVTALRM,	    "VTALRM",	TRUE},
+#endif
+#ifdef SIGPROF
+    {SIGPROF,	    "PROF",	TRUE},
+#endif
+#ifdef SIGXCPU
+    {SIGXCPU,	    "XCPU",	TRUE},
+#endif
+#ifdef SIGXFSZ
+    {SIGXFSZ,	    "XFSZ",	TRUE},
+#endif
+#ifdef SIGUSR1
+    {SIGUSR1,	    "USR1",	TRUE},
+#endif
+#ifdef SIGUSR2
+    {SIGUSR2,	    "USR2",	TRUE},
+#endif
+#ifdef SIGINT
+    {SIGINT,	    "INT",	FALSE},
+#endif
+#ifdef SIGWINCH
+    {SIGWINCH,	    "WINCH",	FALSE},
+#endif
+#ifdef SIGTSTP
+    {SIGTSTP,	    "TSTP",	FALSE},
+#endif
+#ifdef SIGPIPE
+    {SIGPIPE,	    "PIPE",	FALSE},
+#endif
+    {-1,	    "Unknown!", FALSE}
+};
+
+    void
+mch_write(s, len)
+    char_u	*s;
+    int		len;
+{
+    write(1, (char *)s, len);
+    if (p_wd)		/* Unix is too fast, slow down a bit more */
+	RealWaitForChar(read_cmd_fd, p_wd, NULL);
+}
+
+/*
+ * mch_inchar(): low level input funcion.
+ * Get a characters from the keyboard.
+ * Return the number of characters that are available.
+ * If wtime == 0 do not wait for characters.
+ * If wtime == n wait a short time for characters.
+ * If wtime == -1 wait forever for characters.
+ */
+    int
+mch_inchar(buf, maxlen, wtime, tb_change_cnt)
+    char_u	*buf;
+    int		maxlen;
+    long	wtime;	    /* don't use "time", MIPS cannot handle it */
+    int		tb_change_cnt;
+{
+    int		len;
+#ifdef FEAT_AUTOCMD
+    static int	once_already = 0;
+#endif
+
+    /* Check if window changed size while we were busy, perhaps the ":set
+     * columns=99" command was used. */
+    while (do_resize)
+	handle_resize();
+
+    if (wtime >= 0)
+    {
+	while (WaitForChar(wtime) == 0)		/* no character available */
+	{
+	    if (!do_resize)	/* return if not interrupted by resize */
+	    {
+#ifdef FEAT_AUTOCMD
+		once_already = 0;
+#endif
+		return 0;
+	    }
+	    handle_resize();
+	}
+    }
+    else	/* wtime == -1 */
+    {
+#ifdef FEAT_AUTOCMD
+	if (once_already == 2)
+	    updatescript(0);
+	else if (once_already == 1)
+	{
+	    setcursor();
+	    once_already = 2;
+	    return 0;
+	}
+	else
+#endif
+	/*
+	 * If there is no character available within 'updatetime' seconds
+	 * flush all the swap files to disk
+	 * Also done when interrupted by SIGWINCH.
+	 */
+	if (WaitForChar(p_ut) == 0)
+	{
+#ifdef FEAT_AUTOCMD
+	    if (has_cursorhold() && get_real_state() == NORMAL_BUSY)
+	    {
+		apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf);
+		update_screen(VALID);
+		once_already = 1;
+		return 0;
+	    }
+	    else
+#endif
+		updatescript(0);
+	}
+    }
+
+    for (;;)	/* repeat until we got a character */
+    {
+	while (do_resize)    /* window changed size */
+	    handle_resize();
+	/*
+	 * we want to be interrupted by the winch signal
+	 */
+	WaitForChar(-1L);
+	if (do_resize)	    /* interrupted by SIGWINCH signal */
+	    continue;
+
+	/* If input was put directly in typeahead buffer bail out here. */
+	if (typebuf_changed(tb_change_cnt))
+	    return 0;
+
+	/*
+	 * For some terminals we only get one character at a time.
+	 * We want the get all available characters, so we could keep on
+	 * trying until none is available
+	 * For some other terminals this is quite slow, that's why we don't do
+	 * it.
+	 */
+	len = read_from_input_buf(buf, (long)maxlen);
+	if (len > 0)
+	{
+#ifdef OS2
+	    int i;
+
+	    for (i = 0; i < len; i++)
+		if (buf[i] == 0)
+		    buf[i] = K_NUL;
+#endif
+#ifdef FEAT_AUTOCMD
+	    once_already = 0;
+#endif
+	    return len;
+	}
+    }
+}
+
+    static void
+handle_resize()
+{
+    do_resize = FALSE;
+    shell_resized();
+}
+
+/*
+ * return non-zero if a character is available
+ */
+    int
+mch_char_avail()
+{
+    return WaitForChar(0L);
+}
+
+#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
+# ifdef HAVE_SYS_RESOURCE_H
+#  include <sys/resource.h>
+# endif
+# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
+#  include <sys/sysctl.h>
+# endif
+# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
+#  include <sys/sysinfo.h>
+# endif
+
+/*
+ * Return total amount of memory available.  Doesn't change when memory has
+ * been allocated.
+ */
+/* ARGSUSED */
+    long_u
+mch_total_mem(special)
+    int special;
+{
+# ifdef __EMX__
+    return ulimit(3, 0L);   /* always 32MB? */
+# else
+    long_u	mem = 0;
+
+#  ifdef HAVE_SYSCTL
+    int		mib[2], physmem;
+    size_t	len;
+
+    /* BSD way of getting the amount of RAM available. */
+    mib[0] = CTL_HW;
+    mib[1] = HW_USERMEM;
+    len = sizeof(physmem);
+    if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
+	mem = (long_u)physmem;
+#  endif
+
+#  if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
+    if (mem == 0)
+    {
+	struct sysinfo sinfo;
+
+	/* Linux way of getting amount of RAM available */
+	if (sysinfo(&sinfo) == 0)
+	    mem = sinfo.totalram;
+    }
+#  endif
+
+#  ifdef HAVE_SYSCONF
+    if (mem == 0)
+    {
+	long	    pagesize, pagecount;
+
+	/* Solaris way of getting amount of RAM available */
+	pagesize = sysconf(_SC_PAGESIZE);
+	pagecount = sysconf(_SC_PHYS_PAGES);
+	if (pagesize > 0 && pagecount > 0)
+	    mem = (long_u)pagesize * pagecount;
+    }
+#  endif
+
+    /* Return the minimum of the physical memory and the user limit, because
+     * using more than the user limit may cause Vim to be terminated. */
+#  if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
+    {
+	struct rlimit	rlp;
+
+	if (getrlimit(RLIMIT_DATA, &rlp) == 0
+		&& rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
+#   ifdef RLIM_INFINITY
+		&& rlp.rlim_cur != RLIM_INFINITY
+#   endif
+		&& (long_u)rlp.rlim_cur < mem
+	   )
+	    return (long_u)rlp.rlim_cur;
+    }
+#  endif
+
+    if (mem > 0)
+	return mem;
+    return (long_u)0x7fffffff;
+# endif
+}
+#endif
+
+    void
+mch_delay(msec, ignoreinput)
+    long	msec;
+    int		ignoreinput;
+{
+    int		old_tmode;
+
+    if (ignoreinput)
+    {
+	/* Go to cooked mode without echo, to allow SIGINT interrupting us
+	 * here */
+	old_tmode = curr_tmode;
+	if (curr_tmode == TMODE_RAW)
+	    settmode(TMODE_SLEEP);
+
+	/*
+	 * Everybody sleeps in a different way...
+	 * Prefer nanosleep(), some versions of usleep() can only sleep up to
+	 * one second.
+	 */
+#ifdef HAVE_NANOSLEEP
+	{
+	    struct timespec ts;
+
+	    ts.tv_sec = msec / 1000;
+	    ts.tv_nsec = (msec % 1000) * 1000000;
+	    (void)nanosleep(&ts, NULL);
+	}
+#else
+# ifdef HAVE_USLEEP
+	while (msec >= 1000)
+	{
+	    usleep((unsigned int)(999 * 1000));
+	    msec -= 999;
+	}
+	usleep((unsigned int)(msec * 1000));
+# else
+#  ifndef HAVE_SELECT
+	poll(NULL, 0, (int)msec);
+#  else
+#   ifdef __EMX__
+	_sleep2(msec);
+#   else
+	{
+	    struct timeval tv;
+
+	    tv.tv_sec = msec / 1000;
+	    tv.tv_usec = (msec % 1000) * 1000;
+	    /*
+	     * NOTE: Solaris 2.6 has a bug that makes select() hang here.  Get
+	     * a patch from Sun to fix this.  Reported by Gunnar Pedersen.
+	     */
+	    select(0, NULL, NULL, NULL, &tv);
+	}
+#   endif /* __EMX__ */
+#  endif /* HAVE_SELECT */
+# endif /* HAVE_NANOSLEEP */
+#endif /* HAVE_USLEEP */
+
+	settmode(old_tmode);
+    }
+    else
+	WaitForChar(msec);
+}
+
+#if defined(HAVE_GETRLIMIT) \
+	|| (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
+# define HAVE_CHECK_STACK_GROWTH
+/*
+ * Support for checking for an almost-out-of-stack-space situation.
+ */
+
+/*
+ * Return a pointer to an item on the stack.  Used to find out if the stack
+ * grows up or down.
+ */
+static void check_stack_growth __ARGS((char *p));
+static int stack_grows_downwards;
+
+/*
+ * Find out if the stack grows upwards or downwards.
+ * "p" points to a variable on the stack of the caller.
+ */
+    static void
+check_stack_growth(p)
+    char	*p;
+{
+    int		i;
+
+    stack_grows_downwards = (p > (char *)&i);
+}
+#endif
+
+#if defined(HAVE_GETRLIMIT) || defined(PROTO)
+static char *stack_limit = NULL;
+
+#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
+# include <pthread.h>
+# include <pthread_np.h>
+#endif
+
+/*
+ * Find out until how var the stack can grow without getting into trouble.
+ * Called when starting up and when switching to the signal stack in
+ * deathtrap().
+ */
+    static void
+get_stack_limit()
+{
+    struct rlimit	rlp;
+    int			i;
+    long		lim;
+
+    /* Set the stack limit to 15/16 of the allowable size.  Skip this when the
+     * limit doesn't fit in a long (rlim_cur might be "long long"). */
+    if (getrlimit(RLIMIT_STACK, &rlp) == 0
+	    && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
+#  ifdef RLIM_INFINITY
+	    && rlp.rlim_cur != RLIM_INFINITY
+#  endif
+       )
+    {
+	lim = (long)rlp.rlim_cur;
+#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
+	{
+	    pthread_attr_t  attr;
+	    size_t	    size;
+
+	    /* On FreeBSD the initial thread always has a fixed stack size, no
+	     * matter what the limits are set to.  Normally it's 1 Mbyte. */
+	    pthread_attr_init(&attr);
+	    if (pthread_attr_get_np(pthread_self(), &attr) == 0)
+	    {
+		pthread_attr_getstacksize(&attr, &size);
+		if (lim > (long)size)
+		    lim = (long)size;
+	    }
+	    pthread_attr_destroy(&attr);
+	}
+#endif
+	if (stack_grows_downwards)
+	{
+	    stack_limit = (char *)((long)&i - (lim / 16L * 15L));
+	    if (stack_limit >= (char *)&i)
+		/* overflow, set to 1/16 of current stack position */
+		stack_limit = (char *)((long)&i / 16L);
+	}
+	else
+	{
+	    stack_limit = (char *)((long)&i + (lim / 16L * 15L));
+	    if (stack_limit <= (char *)&i)
+		stack_limit = NULL;	/* overflow */
+	}
+    }
+}
+
+/*
+ * Return FAIL when running out of stack space.
+ * "p" must point to any variable local to the caller that's on the stack.
+ */
+    int
+mch_stackcheck(p)
+    char	*p;
+{
+    if (stack_limit != NULL)
+    {
+	if (stack_grows_downwards)
+	{
+	    if (p < stack_limit)
+		return FAIL;
+	}
+	else if (p > stack_limit)
+	    return FAIL;
+    }
+    return OK;
+}
+#endif
+
+#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+/*
+ * Support for using the signal stack.
+ * This helps when we run out of stack space, which causes a SIGSEGV.  The
+ * signal handler then must run on another stack, since the normal stack is
+ * completely full.
+ */
+
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 8000    /* just a guess of how much stack is needed... */
+#endif
+
+# ifdef HAVE_SIGALTSTACK
+static stack_t sigstk;			/* for sigaltstack() */
+# else
+static struct sigstack sigstk;		/* for sigstack() */
+# endif
+
+static void init_signal_stack __ARGS((void));
+static char *signal_stack;
+
+    static void
+init_signal_stack()
+{
+    if (signal_stack != NULL)
+    {
+# ifdef HAVE_SIGALTSTACK
+#  ifdef __APPLE__
+	/* missing prototype.  Adding it to osdef?.h.in doesn't work, because
+	 * "struct sigaltstack" needs to be declared. */
+	extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
+#  endif
+
+#  ifdef HAVE_SS_BASE
+	sigstk.ss_base = signal_stack;
+#  else
+	sigstk.ss_sp = signal_stack;
+#  endif
+	sigstk.ss_size = SIGSTKSZ;
+	sigstk.ss_flags = 0;
+	(void)sigaltstack(&sigstk, NULL);
+# else
+	sigstk.ss_sp = signal_stack;
+	if (stack_grows_downwards)
+	    sigstk.ss_sp += SIGSTKSZ - 1;
+	sigstk.ss_onstack = 0;
+	(void)sigstack(&sigstk, NULL);
+# endif
+    }
+}
+#endif
+
+/*
+ * We need correct potatotypes for a signal function, otherwise mean compilers
+ * will barf when the second argument to signal() is ``wrong''.
+ * Let me try it with a few tricky defines from my own osdef.h	(jw).
+ */
+#if defined(SIGWINCH)
+/* ARGSUSED */
+    static RETSIGTYPE
+sig_winch SIGDEFARG(sigarg)
+{
+    /* this is not required on all systems, but it doesn't hurt anybody */
+    signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
+    do_resize = TRUE;
+    SIGRETURN;
+}
+#endif
+
+#if defined(SIGINT)
+/* ARGSUSED */
+    static RETSIGTYPE
+catch_sigint SIGDEFARG(sigarg)
+{
+    /* this is not required on all systems, but it doesn't hurt anybody */
+    signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
+    got_int = TRUE;
+    SIGRETURN;
+}
+#endif
+
+#if defined(SIGPWR)
+/* ARGSUSED */
+    static RETSIGTYPE
+catch_sigpwr SIGDEFARG(sigarg)
+{
+    /*
+     * I'm not sure we get the SIGPWR signal when the system is really going
+     * down or when the batteries are almost empty.  Just preserve the swap
+     * files and don't exit, that can't do any harm.
+     */
+    ml_sync_all(FALSE, FALSE);
+    SIGRETURN;
+}
+#endif
+
+#ifdef SET_SIG_ALARM
+/*
+ * signal function for alarm().
+ */
+/* ARGSUSED */
+    static RETSIGTYPE
+sig_alarm SIGDEFARG(sigarg)
+{
+    /* doesn't do anything, just to break a system call */
+    sig_alarm_called = TRUE;
+    SIGRETURN;
+}
+#endif
+
+#if defined(HAVE_SETJMP_H) || defined(PROTO)
+/*
+ * A simplistic version of setjmp() that only allows one level of using.
+ * Don't call twice before calling mch_endjmp()!.
+ * Usage:
+ *	mch_startjmp();
+ *	if (SETJMP(lc_jump_env) != 0)
+ *	{
+ *	    mch_didjmp();
+ *	    EMSG("crash!");
+ *	}
+ *	else
+ *	{
+ *	    do_the_work;
+ *	    mch_endjmp();
+ *	}
+ * Note: Can't move SETJMP() here, because a function calling setjmp() must
+ * not return before the saved environment is used.
+ * Returns OK for normal return, FAIL when the protected code caused a
+ * problem and LONGJMP() was used.
+ */
+    void
+mch_startjmp()
+{
+#ifdef SIGHASARG
+    lc_signal = 0;
+#endif
+    lc_active = TRUE;
+}
+
+    void
+mch_endjmp()
+{
+    lc_active = FALSE;
+}
+
+    void
+mch_didjmp()
+{
+# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+    /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
+     * otherwise catching the signal only works once. */
+    init_signal_stack();
+# endif
+}
+#endif
+
+/*
+ * This function handles deadly signals.
+ * It tries to preserve any swap file and exit properly.
+ * (partly from Elvis).
+ */
+    static RETSIGTYPE
+deathtrap SIGDEFARG(sigarg)
+{
+    static int	entered = 0;	    /* count the number of times we got here.
+				       Note: when memory has been corrupted
+				       this may get an arbitrary value! */
+#ifdef SIGHASARG
+    int		i;
+#endif
+
+#if defined(HAVE_SETJMP_H)
+    /*
+     * Catch a crash in protected code.
+     * Restores the environment saved in lc_jump_env, which looks like
+     * SETJMP() returns 1.
+     */
+    if (lc_active)
+    {
+# if defined(SIGHASARG)
+	lc_signal = sigarg;
+# endif
+	lc_active = FALSE;	/* don't jump again */
+	LONGJMP(lc_jump_env, 1);
+	/* NOTREACHED */
+    }
+#endif
+
+    /* Remember how often we have been called. */
+    ++entered;
+
+#ifdef FEAT_EVAL
+    /* Set the v:dying variable. */
+    set_vim_var_nr(VV_DYING, (long)entered);
+#endif
+
+#ifdef HAVE_GETRLIMIT
+    /* Since we are now using the signal stack, need to reset the stack
+     * limit.  Otherwise using a regexp will fail. */
+    get_stack_limit();
+#endif
+
+#ifdef SIGHASARG
+    /* try to find the name of this signal */
+    for (i = 0; signal_info[i].sig != -1; i++)
+	if (sigarg == signal_info[i].sig)
+	    break;
+    deadly_signal = sigarg;
+#endif
+
+    full_screen = FALSE;	/* don't write message to the GUI, it might be
+				 * part of the problem... */
+    /*
+     * If something goes wrong after entering here, we may get here again.
+     * When this happens, give a message and try to exit nicely (resetting the
+     * terminal mode, etc.)
+     * When this happens twice, just exit, don't even try to give a message,
+     * stack may be corrupt or something weird.
+     * When this still happens again (or memory was corrupted in such a way
+     * that "entered" was clobbered) use _exit(), don't try freeing resources.
+     */
+    if (entered >= 3)
+    {
+	reset_signals();	/* don't catch any signals anymore */
+	may_core_dump();
+	if (entered >= 4)
+	    _exit(8);
+	exit(7);
+    }
+    if (entered == 2)
+    {
+	OUT_STR(_("Vim: Double signal, exiting\n"));
+	out_flush();
+	getout(1);
+    }
+
+#ifdef SIGHASARG
+    sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
+							 signal_info[i].name);
+#else
+    sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
+#endif
+    preserve_exit();		    /* preserve files and exit */
+
+    SIGRETURN;
+}
+
+#ifdef _REENTRANT
+/*
+ * On Solaris with multi-threading, suspending might not work immediately.
+ * Catch the SIGCONT signal, which will be used as an indication whether the
+ * suspending has been done or not.
+ */
+static int sigcont_received;
+static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
+
+/*
+ * signal handler for SIGCONT
+ */
+/* ARGSUSED */
+    static RETSIGTYPE
+sigcont_handler SIGDEFARG(sigarg)
+{
+    sigcont_received = TRUE;
+    SIGRETURN;
+}
+#endif
+
+/*
+ * If the machine has job control, use it to suspend the program,
+ * otherwise fake it by starting a new shell.
+ */
+    void
+mch_suspend()
+{
+    /* BeOS does have SIGTSTP, but it doesn't work. */
+#if defined(SIGTSTP) && !defined(__BEOS__)
+    out_flush();	    /* needed to make cursor visible on some systems */
+    settmode(TMODE_COOK);
+    out_flush();	    /* needed to disable mouse on some systems */
+
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+    /* Since we are going to sleep, we can't respond to requests for the X
+     * selections.  Lose them, otherwise other applications will hang.  But
+     * first copy the text to cut buffer 0. */
+    if (clip_star.owned || clip_plus.owned)
+    {
+	x11_export_final_selection();
+	if (clip_star.owned)
+	    clip_lose_selection(&clip_star);
+	if (clip_plus.owned)
+	    clip_lose_selection(&clip_plus);
+	if (x11_display != NULL)
+	    XFlush(x11_display);
+    }
+# endif
+
+# ifdef _REENTRANT
+    sigcont_received = FALSE;
+# endif
+    kill(0, SIGTSTP);	    /* send ourselves a STOP signal */
+# ifdef _REENTRANT
+    /* When we didn't suspend immediately in the kill(), do it now.  Happens
+     * on multi-threaded Solaris. */
+    if (!sigcont_received)
+	pause();
+# endif
+
+# ifdef FEAT_TITLE
+    /*
+     * Set oldtitle to NULL, so the current title is obtained again.
+     */
+    vim_free(oldtitle);
+    oldtitle = NULL;
+# endif
+    settmode(TMODE_RAW);
+    need_check_timestamps = TRUE;
+    did_check_timestamps = FALSE;
+#else
+    suspend_shell();
+#endif
+}
+
+    void
+mch_init()
+{
+    Columns = 80;
+    Rows = 24;
+
+    out_flush();
+    set_signals();
+}
+
+    static void
+set_signals()
+{
+#if defined(SIGWINCH)
+    /*
+     * WINDOW CHANGE signal is handled with sig_winch().
+     */
+    signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
+#endif
+
+    /*
+     * We want the STOP signal to work, to make mch_suspend() work.
+     * For "rvim" the STOP signal is ignored.
+     */
+#ifdef SIGTSTP
+    signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+#endif
+#ifdef _REENTRANT
+    signal(SIGCONT, sigcont_handler);
+#endif
+
+    /*
+     * We want to ignore breaking of PIPEs.
+     */
+#ifdef SIGPIPE
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    /*
+     * We want to catch CTRL-C (only works while in Cooked mode).
+     */
+#ifdef SIGINT
+    signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
+#endif
+
+    /*
+     * Ignore alarm signals (Perl's alarm() generates it).
+     */
+#ifdef SIGALRM
+    signal(SIGALRM, SIG_IGN);
+#endif
+
+    /*
+     * Catch SIGPWR (power failure?) to preserve the swap files, so that no
+     * work will be lost.
+     */
+#ifdef SIGPWR
+    signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
+#endif
+
+    /*
+     * Arrange for other signals to gracefully shutdown Vim.
+     */
+    catch_signals(deathtrap, SIG_ERR);
+
+#if defined(FEAT_GUI) && defined(SIGHUP)
+    /*
+     * When the GUI is running, ignore the hangup signal.
+     */
+    if (gui.in_use)
+	signal(SIGHUP, SIG_IGN);
+#endif
+}
+
+    void
+reset_signals()
+{
+    catch_signals(SIG_DFL, SIG_DFL);
+#ifdef _REENTRANT
+    /* SIGCONT isn't in the list, because its default action is ignore */
+    signal(SIGCONT, SIG_DFL);
+#endif
+}
+
+    static void
+catch_signals(func_deadly, func_other)
+    RETSIGTYPE (*func_deadly)();
+    RETSIGTYPE (*func_other)();
+{
+    int	    i;
+
+    for (i = 0; signal_info[i].sig != -1; i++)
+	if (signal_info[i].deadly)
+	{
+#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
+	    struct sigaction sa;
+
+	    /* Setup to use the alternate stack for the signal function. */
+	    sa.sa_handler = func_deadly;
+	    sigemptyset(&sa.sa_mask);
+# if defined(__linux__) && defined(_REENTRANT)
+	    /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
+	     * thread handling in combination with using the alternate stack:
+	     * pthread library functions try to use the stack pointer to
+	     * identify the current thread, causing a SEGV signal, which
+	     * recursively calls deathtrap() and hangs. */
+	    sa.sa_flags = 0;
+# else
+	    sa.sa_flags = SA_ONSTACK;
+# endif
+	    sigaction(signal_info[i].sig, &sa, NULL);
+#else
+# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
+	    struct sigvec sv;
+
+	    /* Setup to use the alternate stack for the signal function. */
+	    sv.sv_handler = func_deadly;
+	    sv.sv_mask = 0;
+	    sv.sv_flags = SV_ONSTACK;
+	    sigvec(signal_info[i].sig, &sv, NULL);
+# else
+	    signal(signal_info[i].sig, func_deadly);
+# endif
+#endif
+	}
+	else if (func_other != SIG_ERR)
+	    signal(signal_info[i].sig, func_other);
+}
+
+/*
+ * Check_win checks whether we have an interactive stdout.
+ */
+/* ARGSUSED */
+    int
+mch_check_win(argc, argv)
+    int	    argc;
+    char    **argv;
+{
+#ifdef OS2
+    /*
+     * Store argv[0], may be used for $VIM.  Only use it if it is an absolute
+     * name, mostly it's just "vim" and found in the path, which is unusable.
+     */
+    if (mch_isFullName(argv[0]))
+	exe_name = vim_strsave((char_u *)argv[0]);
+#endif
+    if (isatty(1))
+	return OK;
+    return FAIL;
+}
+
+/*
+ * Return TRUE if the input comes from a terminal, FALSE otherwise.
+ */
+    int
+mch_input_isatty()
+{
+    if (isatty(read_cmd_fd))
+	return TRUE;
+    return FALSE;
+}
+
+#ifdef FEAT_X11
+
+# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
+	&& (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
+
+static void xopen_message __ARGS((struct timeval *tvp));
+
+/*
+ * Give a message about the elapsed time for opening the X window.
+ */
+    static void
+xopen_message(tvp)
+    struct timeval *tvp;	/* must contain start time */
+{
+    struct timeval  end_tv;
+
+    /* Compute elapsed time. */
+    gettimeofday(&end_tv, NULL);
+    smsg((char_u *)_("Opening the X display took %ld msec"),
+	    (end_tv.tv_sec - tvp->tv_sec) * 1000L
+	    + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
+}
+# endif
+#endif
+
+#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
+/*
+ * A few functions shared by X11 title and clipboard code.
+ */
+static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
+static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
+static int x_connect_to_server __ARGS((void));
+static int test_x11_window __ARGS((Display *dpy));
+
+static int	got_x_error = FALSE;
+
+/*
+ * X Error handler, otherwise X just exits!  (very rude) -- webb
+ */
+    static int
+x_error_handler(dpy, error_event)
+    Display	*dpy;
+    XErrorEvent	*error_event;
+{
+    XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
+    STRCAT(IObuff, _("\nVim: Got X error\n"));
+
+    /* We cannot print a message and continue, because no X calls are allowed
+     * here (causes my system to hang).  Silently continuing might be an
+     * alternative... */
+    preserve_exit();		    /* preserve files and exit */
+
+    return 0;		/* NOTREACHED */
+}
+
+/*
+ * Another X Error handler, just used to check for errors.
+ */
+/* ARGSUSED */
+    static int
+x_error_check(dpy, error_event)
+    Display *dpy;
+    XErrorEvent	*error_event;
+{
+    got_x_error = TRUE;
+    return 0;
+}
+
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+# if defined(HAVE_SETJMP_H)
+/*
+ * An X IO Error handler, used to catch error while opening the display.
+ */
+static int x_IOerror_check __ARGS((Display *dpy));
+
+/* ARGSUSED */
+    static int
+x_IOerror_check(dpy)
+    Display *dpy;
+{
+    /* This function should not return, it causes exit().  Longjump instead. */
+    LONGJMP(lc_jump_env, 1);
+    /*NOTREACHED*/
+    return 0;
+}
+# endif
+
+/*
+ * An X IO Error handler, used to catch terminal errors.
+ */
+static int x_IOerror_handler __ARGS((Display *dpy));
+
+/* ARGSUSED */
+    static int
+x_IOerror_handler(dpy)
+    Display *dpy;
+{
+    xterm_dpy = NULL;
+    x11_window = 0;
+    x11_display = NULL;
+    xterm_Shell = (Widget)0;
+
+    /* This function should not return, it causes exit().  Longjump instead. */
+    LONGJMP(x_jump_env, 1);
+    /*NOTREACHED*/
+    return 0;
+}
+#endif
+
+/*
+ * Return TRUE when connection to the X server is desired.
+ */
+    static int
+x_connect_to_server()
+{
+    regmatch_T	regmatch;
+
+#if defined(FEAT_CLIENTSERVER)
+    if (x_force_connect)
+	return TRUE;
+#endif
+    if (x_no_connect)
+	return FALSE;
+
+    /* Check for a match with "exclude:" from 'clipboard'. */
+    if (clip_exclude_prog != NULL)
+    {
+	regmatch.rm_ic = FALSE;		/* Don't ignore case */
+	regmatch.regprog = clip_exclude_prog;
+	if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
+	    return FALSE;
+    }
+    return TRUE;
+}
+
+/*
+ * Test if "dpy" and x11_window are valid by getting the window title.
+ * I don't actually want it yet, so there may be a simpler call to use, but
+ * this will cause the error handler x_error_check() to be called if anything
+ * is wrong, such as the window pointer being invalid (as can happen when the
+ * user changes his DISPLAY, but not his WINDOWID) -- webb
+ */
+    static int
+test_x11_window(dpy)
+    Display	*dpy;
+{
+    int			(*old_handler)();
+    XTextProperty	text_prop;
+
+    old_handler = XSetErrorHandler(x_error_check);
+    got_x_error = FALSE;
+    if (XGetWMName(dpy, x11_window, &text_prop))
+	XFree((void *)text_prop.value);
+    XSync(dpy, False);
+    (void)XSetErrorHandler(old_handler);
+
+    if (p_verbose > 0 && got_x_error)
+	MSG(_("Testing the X display failed"));
+
+    return (got_x_error ? FAIL : OK);
+}
+#endif
+
+#ifdef FEAT_TITLE
+
+#ifdef FEAT_X11
+
+static int get_x11_thing __ARGS((int get_title, int test_only));
+
+/*
+ * try to get x11 window and display
+ *
+ * return FAIL for failure, OK otherwise
+ */
+    static int
+get_x11_windis()
+{
+    char	    *winid;
+    static int	    result = -1;
+#define XD_NONE	 0	/* x11_display not set here */
+#define XD_HERE	 1	/* x11_display opened here */
+#define XD_GUI	 2	/* x11_display used from gui.dpy */
+#define XD_XTERM 3	/* x11_display used from xterm_dpy */
+    static int	    x11_display_from = XD_NONE;
+    static int	    did_set_error_handler = FALSE;
+
+    if (!did_set_error_handler)
+    {
+	/* X just exits if it finds an error otherwise! */
+	(void)XSetErrorHandler(x_error_handler);
+	did_set_error_handler = TRUE;
+    }
+
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+    if (gui.in_use)
+    {
+	/*
+	 * If the X11 display was opened here before, for the window where Vim
+	 * was started, close that one now to avoid a memory leak.
+	 */
+	if (x11_display_from == XD_HERE && x11_display != NULL)
+	{
+	    XCloseDisplay(x11_display);
+	    x11_display_from = XD_NONE;
+	}
+	if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
+	{
+	    x11_display_from = XD_GUI;
+	    return OK;
+	}
+	x11_display = NULL;
+	return FAIL;
+    }
+    else if (x11_display_from == XD_GUI)
+    {
+	/* GUI must have stopped somehow, clear x11_display */
+	x11_window = 0;
+	x11_display = NULL;
+	x11_display_from = XD_NONE;
+    }
+#endif
+
+    /* When started with the "-X" argument, don't try connecting. */
+    if (!x_connect_to_server())
+	return FAIL;
+
+    /*
+     * If WINDOWID not set, should try another method to find out
+     * what the current window number is. The only code I know for
+     * this is very complicated.
+     * We assume that zero is invalid for WINDOWID.
+     */
+    if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
+	x11_window = (Window)atol(winid);
+
+#ifdef FEAT_XCLIPBOARD
+    if (xterm_dpy != NULL && x11_window != 0)
+    {
+	/* Checked it already. */
+	if (x11_display_from == XD_XTERM)
+	    return OK;
+
+	/*
+	 * If the X11 display was opened here before, for the window where Vim
+	 * was started, close that one now to avoid a memory leak.
+	 */
+	if (x11_display_from == XD_HERE && x11_display != NULL)
+	    XCloseDisplay(x11_display);
+	x11_display = xterm_dpy;
+	x11_display_from = XD_XTERM;
+	if (test_x11_window(x11_display) == FAIL)
+	{
+	    /* probably bad $WINDOWID */
+	    x11_window = 0;
+	    x11_display = NULL;
+	    x11_display_from = XD_NONE;
+	    return FAIL;
+	}
+	return OK;
+    }
+#endif
+
+    if (x11_window == 0 || x11_display == NULL)
+	result = -1;
+
+    if (result != -1)	    /* Have already been here and set this */
+	return result;	    /* Don't do all these X calls again */
+
+    if (x11_window != 0 && x11_display == NULL)
+    {
+#ifdef SET_SIG_ALARM
+	RETSIGTYPE (*sig_save)();
+#endif
+#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+	struct timeval  start_tv;
+
+	if (p_verbose > 0)
+	    gettimeofday(&start_tv, NULL);
+#endif
+
+#ifdef SET_SIG_ALARM
+	/*
+	 * Opening the Display may hang if the DISPLAY setting is wrong, or
+	 * the network connection is bad.  Set an alarm timer to get out.
+	 */
+	sig_alarm_called = FALSE;
+	sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
+						 (RETSIGTYPE (*)())sig_alarm);
+	alarm(2);
+#endif
+	x11_display = XOpenDisplay(NULL);
+
+#ifdef SET_SIG_ALARM
+	alarm(0);
+	signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
+	if (p_verbose > 0 && sig_alarm_called)
+	    MSG(_("Opening the X display timed out"));
+#endif
+	if (x11_display != NULL)
+	{
+# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+	    if (p_verbose > 0)
+		xopen_message(&start_tv);
+# endif
+	    if (test_x11_window(x11_display) == FAIL)
+	    {
+		/* Maybe window id is bad */
+		x11_window = 0;
+		XCloseDisplay(x11_display);
+		x11_display = NULL;
+	    }
+	    else
+		x11_display_from = XD_HERE;
+	}
+    }
+    if (x11_window == 0 || x11_display == NULL)
+	return (result = FAIL);
+    return (result = OK);
+}
+
+/*
+ * Determine original x11 Window Title
+ */
+    static int
+get_x11_title(test_only)
+    int		test_only;
+{
+    int		retval;
+
+    retval = get_x11_thing(TRUE, test_only);
+
+    /* could not get old title: oldtitle == NULL */
+
+    return retval;
+}
+
+/*
+ * Determine original x11 Window icon
+ */
+    static int
+get_x11_icon(test_only)
+    int		test_only;
+{
+    int		retval = FALSE;
+
+    retval = get_x11_thing(FALSE, test_only);
+
+    /* could not get old icon, use terminal name */
+    if (oldicon == NULL && !test_only)
+    {
+	if (STRNCMP(T_NAME, "builtin_", 8) == 0)
+	    oldicon = T_NAME + 8;
+	else
+	    oldicon = T_NAME;
+    }
+
+    return retval;
+}
+
+    static int
+get_x11_thing(get_title, test_only)
+    int		get_title;	/* get title string */
+    int		test_only;
+{
+    XTextProperty	text_prop;
+    int			retval = FALSE;
+    Status		status;
+
+    if (get_x11_windis() == OK)
+    {
+	/* Get window/icon name if any */
+	if (get_title)
+	    status = XGetWMName(x11_display, x11_window, &text_prop);
+	else
+	    status = XGetWMIconName(x11_display, x11_window, &text_prop);
+
+	/*
+	 * If terminal is xterm, then x11_window may be a child window of the
+	 * outer xterm window that actually contains the window/icon name, so
+	 * keep traversing up the tree until a window with a title/icon is
+	 * found.
+	 */
+	/* Previously this was only done for xterm and alikes.  I don't see a
+	 * reason why it would fail for other terminal emulators.
+	 * if (term_is_xterm) */
+	{
+	    Window	    root;
+	    Window	    parent;
+	    Window	    win = x11_window;
+	    Window	   *children;
+	    unsigned int    num_children;
+
+	    while (!status || text_prop.value == NULL)
+	    {
+		if (!XQueryTree(x11_display, win, &root, &parent, &children,
+							       &num_children))
+		    break;
+		if (children)
+		    XFree((void *)children);
+		if (parent == root || parent == 0)
+		    break;
+
+		win = parent;
+		if (get_title)
+		    status = XGetWMName(x11_display, win, &text_prop);
+		else
+		    status = XGetWMIconName(x11_display, win, &text_prop);
+	    }
+	}
+	if (status && text_prop.value != NULL)
+	{
+	    retval = TRUE;
+	    if (!test_only)
+	    {
+#ifdef FEAT_XFONTSET
+		if (text_prop.encoding == XA_STRING)
+		{
+#endif
+		    if (get_title)
+			oldtitle = vim_strsave((char_u *)text_prop.value);
+		    else
+			oldicon = vim_strsave((char_u *)text_prop.value);
+#ifdef FEAT_XFONTSET
+		}
+		else
+		{
+		    char    **cl;
+		    Status  transform_status;
+		    int	    n = 0;
+
+		    transform_status = XmbTextPropertyToTextList(x11_display,
+								 &text_prop,
+								 &cl, &n);
+		    if (transform_status >= Success && n > 0 && cl[0])
+		    {
+			if (get_title)
+			    oldtitle = vim_strsave((char_u *) cl[0]);
+			else
+			    oldicon = vim_strsave((char_u *) cl[0]);
+			XFreeStringList(cl);
+		    }
+		    else
+		    {
+			if (get_title)
+			    oldtitle = vim_strsave((char_u *)text_prop.value);
+			else
+			    oldicon = vim_strsave((char_u *)text_prop.value);
+		    }
+		}
+#endif
+	    }
+	    XFree((void *)text_prop.value);
+	}
+    }
+    return retval;
+}
+
+/* Are Xutf8 functions available?  Avoid error from old compilers. */
+#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
+# if X_HAVE_UTF8_STRING
+#  define USE_UTF8_STRING
+# endif
+#endif
+
+/*
+ * Set x11 Window Title
+ *
+ * get_x11_windis() must be called before this and have returned OK
+ */
+    static void
+set_x11_title(title)
+    char_u	*title;
+{
+	/* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
+	 * when possible, COMPOUND_TEXT otherwise.  COMPOUND_TEXT isn't
+	 * supported everywhere and STRING doesn't work for multi-byte titles.
+	 */
+#ifdef USE_UTF8_STRING
+    if (enc_utf8)
+	Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
+					     NULL, NULL, 0, NULL, NULL, NULL);
+    else
+#endif
+    {
+#if XtSpecificationRelease >= 4
+# ifdef FEAT_XFONTSET
+	XmbSetWMProperties(x11_display, x11_window, (const char *)title,
+					     NULL, NULL, 0, NULL, NULL, NULL);
+# else
+	XTextProperty	text_prop;
+
+	/* directly from example 3-18 "basicwin" of Xlib Programming Manual */
+	(void)XStringListToTextProperty((char **)&title, 1, &text_prop);
+	XSetWMProperties(x11_display, x11_window, &text_prop,
+					     NULL, NULL, 0, NULL, NULL, NULL);
+# endif
+#else
+	XStoreName(x11_display, x11_window, (char *)title);
+#endif
+    }
+    XFlush(x11_display);
+}
+
+/*
+ * Set x11 Window icon
+ *
+ * get_x11_windis() must be called before this and have returned OK
+ */
+    static void
+set_x11_icon(icon)
+    char_u	*icon;
+{
+    /* See above for comments about using X*SetWMProperties(). */
+#ifdef USE_UTF8_STRING
+    if (enc_utf8)
+	Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
+						   NULL, 0, NULL, NULL, NULL);
+    else
+#endif
+    {
+#if XtSpecificationRelease >= 4
+# ifdef FEAT_XFONTSET
+	XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
+						   NULL, 0, NULL, NULL, NULL);
+# else
+	XTextProperty	text_prop;
+
+	(void)XStringListToTextProperty((char **)&icon, 1, &text_prop);
+	XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
+						   NULL, 0, NULL, NULL, NULL);
+# endif
+#else
+	XSetIconName(x11_display, x11_window, (char *)icon);
+#endif
+    }
+    XFlush(x11_display);
+}
+
+#else  /* FEAT_X11 */
+
+/*ARGSUSED*/
+    static int
+get_x11_title(test_only)
+    int	    test_only;
+{
+    return FALSE;
+}
+
+    static int
+get_x11_icon(test_only)
+    int	    test_only;
+{
+    if (!test_only)
+    {
+	if (STRNCMP(T_NAME, "builtin_", 8) == 0)
+	    oldicon = T_NAME + 8;
+	else
+	    oldicon = T_NAME;
+    }
+    return FALSE;
+}
+
+#endif /* FEAT_X11 */
+
+    int
+mch_can_restore_title()
+{
+    return get_x11_title(TRUE);
+}
+
+    int
+mch_can_restore_icon()
+{
+    return get_x11_icon(TRUE);
+}
+
+/*
+ * Set the window title and icon.
+ */
+    void
+mch_settitle(title, icon)
+    char_u *title;
+    char_u *icon;
+{
+    int		type = 0;
+    static int	recursive = 0;
+
+    if (T_NAME == NULL)	    /* no terminal name (yet) */
+	return;
+    if (title == NULL && icon == NULL)	    /* nothing to do */
+	return;
+
+    /* When one of the X11 functions causes a deadly signal, we get here again
+     * recursively.  Avoid hanging then (something is probably locked). */
+    if (recursive)
+	return;
+    ++recursive;
+
+    /*
+     * if the window ID and the display is known, we may use X11 calls
+     */
+#ifdef FEAT_X11
+    if (get_x11_windis() == OK)
+	type = 1;
+#else
+# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
+    if (gui.in_use)
+	type = 1;
+# endif
+# ifdef FEAT_GUI_BEOS
+    /* TODO: If this means (gui.in_use) why not merge with above? (Dany) */
+    /* we always have a 'window' */
+    type = 1;
+# endif
+#endif
+
+    /*
+     * Note: if "t_TS" is set, title is set with escape sequence rather
+     *	     than x11 calls, because the x11 calls don't always work
+     */
+
+    if ((type || *T_TS != NUL) && title != NULL)
+    {
+	if (oldtitle == NULL
+#ifdef FEAT_GUI
+		&& !gui.in_use
+#endif
+		)		/* first call but not in GUI, save title */
+	    (void)get_x11_title(FALSE);
+
+	if (*T_TS != NUL)		/* it's OK if t_fs is empty */
+	    term_settitle(title);
+#ifdef FEAT_X11
+	else
+# ifdef FEAT_GUI_GTK
+	if (!gui.in_use)		/* don't do this if GTK+ is running */
+# endif
+	    set_x11_title(title);		/* x11 */
+#endif
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_BEOS) \
+	|| defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
+	else
+	    gui_mch_settitle(title, icon);
+#endif
+	did_set_title = TRUE;
+    }
+
+    if ((type || *T_CIS != NUL) && icon != NULL)
+    {
+	if (oldicon == NULL
+#ifdef FEAT_GUI
+		&& !gui.in_use
+#endif
+		)		/* first call, save icon */
+	    get_x11_icon(FALSE);
+
+	if (*T_CIS != NUL)
+	{
+	    out_str(T_CIS);			/* set icon start */
+	    out_str_nf(icon);
+	    out_str(T_CIE);			/* set icon end */
+	    out_flush();
+	}
+#ifdef FEAT_X11
+	else
+# ifdef FEAT_GUI_GTK
+	if (!gui.in_use)		/* don't do this if GTK+ is running */
+# endif
+	    set_x11_icon(icon);			/* x11 */
+#endif
+	did_set_icon = TRUE;
+    }
+    --recursive;
+}
+
+/*
+ * Restore the window/icon title.
+ * "which" is one of:
+ *  1  only restore title
+ *  2  only restore icon
+ *  3  restore title and icon
+ */
+    void
+mch_restore_title(which)
+    int which;
+{
+    /* only restore the title or icon when it has been set */
+    mch_settitle(((which & 1) && did_set_title) ?
+			(oldtitle ? oldtitle : p_titleold) : NULL,
+			      ((which & 2) && did_set_icon) ? oldicon : NULL);
+}
+
+#endif /* FEAT_TITLE */
+
+/*
+ * Return TRUE if "name" looks like some xterm name.
+ */
+    int
+vim_is_xterm(name)
+    char_u *name;
+{
+    if (name == NULL)
+	return FALSE;
+    return (STRNICMP(name, "xterm", 5) == 0
+		|| STRNICMP(name, "nxterm", 6) == 0
+		|| STRNICMP(name, "kterm", 5) == 0
+		|| STRNICMP(name, "rxvt", 4) == 0
+		|| STRCMP(name, "builtin_xterm") == 0);
+}
+
+#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
+/*
+ * Return non-zero when using an xterm mouse, according to 'ttymouse'.
+ * Return 1 for "xterm".
+ * Return 2 for "xterm2".
+ */
+    int
+use_xterm_mouse()
+{
+    if (ttym_flags == TTYM_XTERM2)
+	return 2;
+    if (ttym_flags == TTYM_XTERM)
+	return 1;
+    return 0;
+}
+#endif
+
+    int
+vim_is_iris(name)
+    char_u  *name;
+{
+    if (name == NULL)
+	return FALSE;
+    return (STRNICMP(name, "iris-ansi", 9) == 0
+	    || STRCMP(name, "builtin_iris-ansi") == 0);
+}
+
+    int
+vim_is_vt300(name)
+    char_u  *name;
+{
+    if (name == NULL)
+	return FALSE;	       /* actually all ANSI comp. terminals should be here  */
+    return (STRNICMP(name, "vt3", 3) == 0     /* it will cover all from VT100-VT300 */
+	    || STRNICMP(name, "vt2", 3) == 0  /* TODO: from VT340 can hanle colors  */
+	    || STRNICMP(name, "vt1", 3) == 0
+	    || STRCMP(name, "builtin_vt320") == 0);
+}
+
+/*
+ * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
+ * This should include all windowed terminal emulators.
+ */
+    int
+vim_is_fastterm(name)
+    char_u  *name;
+{
+    if (name == NULL)
+	return FALSE;
+    if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
+	return TRUE;
+    return (   STRNICMP(name, "hpterm", 6) == 0
+	    || STRNICMP(name, "sun-cmd", 7) == 0
+	    || STRNICMP(name, "screen", 6) == 0
+	    || STRNICMP(name, "dtterm", 6) == 0);
+}
+
+/*
+ * Insert user name in s[len].
+ * Return OK if a name found.
+ */
+    int
+mch_get_user_name(s, len)
+    char_u  *s;
+    int	    len;
+{
+#ifdef VMS
+    STRNCPY((char *)s, cuserid(NULL), len);
+    return OK;
+#else
+    return mch_get_uname(getuid(), s, len);
+#endif
+}
+
+/*
+ * Insert user name for "uid" in s[len].
+ * Return OK if a name found.
+ */
+    int
+mch_get_uname(uid, s, len)
+    uid_t	uid;
+    char_u	*s;
+    int		len;
+{
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+    struct passwd   *pw;
+
+    if ((pw = getpwuid(uid)) != NULL
+	    && pw->pw_name != NULL && *(pw->pw_name) != NUL)
+    {
+	STRNCPY(s, pw->pw_name, len);
+	return OK;
+    }
+#endif
+    sprintf((char *)s, "%d", (int)uid);	    /* assumes s is long enough */
+    return FAIL;			    /* a number is not a name */
+}
+
+/*
+ * Insert host name is s[len].
+ */
+
+#ifdef HAVE_SYS_UTSNAME_H
+    void
+mch_get_host_name(s, len)
+    char_u  *s;
+    int	    len;
+{
+    struct utsname vutsname;
+
+    if (uname(&vutsname) < 0)
+	*s = NUL;
+    else
+	STRNCPY(s, vutsname.nodename, len);
+    s[len - 1] = NUL;	/* make sure it's terminated */
+}
+#else /* HAVE_SYS_UTSNAME_H */
+
+# ifdef HAVE_SYS_SYSTEMINFO_H
+#  define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
+# endif
+
+    void
+mch_get_host_name(s, len)
+    char_u  *s;
+    int	    len;
+{
+# ifdef VAXC
+    vaxc$gethostname((char *)s, len);
+# else
+    gethostname((char *)s, len);
+# endif
+    s[len - 1] = NUL;	/* make sure it's terminated */
+}
+#endif /* HAVE_SYS_UTSNAME_H */
+
+/*
+ * return process ID
+ */
+    long
+mch_get_pid()
+{
+    return (long)getpid();
+}
+
+#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
+static char *strerror __ARGS((int));
+
+    static char *
+strerror(err)
+    int err;
+{
+    extern int	    sys_nerr;
+    extern char	    *sys_errlist[];
+    static char	    er[20];
+
+    if (err > 0 && err < sys_nerr)
+	return (sys_errlist[err]);
+    sprintf(er, "Error %d", err);
+    return er;
+}
+#endif
+
+/*
+ * Get name of current directory into buffer 'buf' of length 'len' bytes.
+ * Return OK for success, FAIL for failure.
+ */
+    int
+mch_dirname(buf, len)
+    char_u  *buf;
+    int	    len;
+{
+#if defined(USE_GETCWD)
+    if (getcwd((char *)buf, len) == NULL)
+    {
+	STRCPY(buf, strerror(errno));
+	return FAIL;
+    }
+    return OK;
+#else
+    return (getwd((char *)buf) != NULL ? OK : FAIL);
+#endif
+}
+
+#if defined(OS2) || defined(PROTO)
+/*
+ * Replace all slashes by backslashes.
+ * When 'shellslash' set do it the other way around.
+ */
+    void
+slash_adjust(p)
+    char_u  *p;
+{
+    while (*p)
+    {
+	if (*p == psepcN)
+	    *p = psepc;
+#ifdef FEAT_MBYTE
+	if (has_mbyte)
+	    p += (*mb_ptr2len_check)(p);
+	else
+#endif
+	    ++p;
+    }
+}
+#endif
+
+/*
+ * Get absolute file name into buffer 'buf' of length 'len' bytes.
+ *
+ * return FAIL for failure, OK for success
+ */
+    int
+mch_FullName(fname, buf, len, force)
+    char_u	*fname, *buf;
+    int		len;
+    int		force;		/* also expand when already absolute path */
+{
+    int		l;
+#ifdef OS2
+    int		only_drive;	/* file name is only a drive letter */
+#endif
+#ifdef HAVE_FCHDIR
+    int		fd = -1;
+    static int	dont_fchdir = FALSE;	/* TRUE when fchdir() doesn't work */
+#endif
+    char_u	olddir[MAXPATHL];
+    char_u	*p;
+    int		retval = OK;
+
+#ifdef VMS
+    fname = vms_fixfilename(fname);
+#endif
+
+    /* expand it if forced or not an absolute path */
+    if (force || !mch_isFullName(fname))
+    {
+	/*
+	 * If the file name has a path, change to that directory for a moment,
+	 * and then do the getwd() (and get back to where we were).
+	 * This will get the correct path name with "../" things.
+	 */
+#ifdef OS2
+	only_drive = 0;
+	if (((p = vim_strrchr(fname, '/')) != NULL)
+		|| ((p = vim_strrchr(fname, '\\')) != NULL)
+		|| (((p = vim_strchr(fname,  ':')) != NULL) && ++only_drive))
+#else
+	if ((p = vim_strrchr(fname, '/')) != NULL)
+#endif
+	{
+#ifdef HAVE_FCHDIR
+	    /*
+	     * Use fchdir() if possible, it's said to be faster and more
+	     * reliable.  But on SunOS 4 it might not work.  Check this by
+	     * doing a fchdir() right now.
+	     */
+	    if (!dont_fchdir)
+	    {
+		fd = open(".", O_RDONLY | O_EXTRA, 0);
+		if (fd >= 0 && fchdir(fd) < 0)
+		{
+		    close(fd);
+		    fd = -1;
+		    dont_fchdir = TRUE;	    /* don't try again */
+		}
+	    }
+#endif
+
+	    /* Only change directory when we are sure we can return to where
+	     * we are now.  After doing "su" chdir(".") might not work. */
+	    if (
+#ifdef HAVE_FCHDIR
+		fd < 0 &&
+#endif
+			(mch_dirname(olddir, MAXPATHL) == FAIL
+					   || mch_chdir((char *)olddir) != 0))
+	    {
+		p = NULL;	/* can't get current dir: don't chdir */
+		retval = FAIL;
+	    }
+	    else
+	    {
+#ifdef OS2
+		/*
+		 * compensate for case where ':' from "D:" was the only
+		 * path separator detected in the file name; the _next_
+		 * character has to be removed, and then restored later.
+		 */
+		if (only_drive)
+		    p++;
+#endif
+		/* The directory is copied into buf[], to be able to remove
+		 * the file name without changing it (could be a string in
+		 * read-only memory) */
+		if (p - fname >= len)
+		    retval = FAIL;
+		else
+		{
+		    STRNCPY(buf, fname, p - fname);
+		    buf[p - fname] = NUL;
+		    if (mch_chdir((char *)buf))
+			retval = FAIL;
+		    else
+			fname = p + 1;
+		    *buf = NUL;
+		}
+#ifdef OS2
+		if (only_drive)
+		{
+		    p--;
+		    if (retval != FAIL)
+			fname--;
+		}
+#endif
+	    }
+	}
+	if (mch_dirname(buf, len) == FAIL)
+	{
+	    retval = FAIL;
+	    *buf = NUL;
+	}
+	if (p != NULL)
+	{
+#ifdef HAVE_FCHDIR
+	    if (fd >= 0)
+	    {
+		l = fchdir(fd);
+		close(fd);
+	    }
+	    else
+#endif
+		l = mch_chdir((char *)olddir);
+	    if (l != 0)
+		EMSG(_(e_prev_dir));
+	}
+
+	l = STRLEN(buf);
+	if (l >= len)
+	    retval = FAIL;
+#ifndef VMS
+	else
+	{
+	    if (l > 0 && buf[l - 1] != '/' && *fname != NUL
+						   && STRCMP(fname, ".") != 0)
+		STRCAT(buf, "/");
+	}
+#endif
+    }
+    /* Catch file names which are too long. */
+    if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
+	return FAIL;
+
+    /* Do not append ".", "/dir/." is equal to "/dir". */
+    if (STRCMP(fname, ".") != 0)
+	STRCAT(buf, fname);
+
+    return OK;
+}
+
+/*
+ * Return TRUE if "fname" does not depend on the current directory.
+ */
+    int
+mch_isFullName(fname)
+    char_u	*fname;
+{
+#ifdef __EMX__
+    return _fnisabs(fname);
+#else
+# ifdef VMS
+    return ( fname[0] == '/'	       || fname[0] == '.'	    ||
+	     strchr((char *)fname,':') || strchr((char *)fname,'"') ||
+	    (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
+	    (strchr((char *)fname,'<') && strchr((char *)fname,'>'))   );
+# else
+    return (*fname == '/' || *fname == '~');
+# endif
+#endif
+}
+
+/*
+ * Get file permissions for 'name'.
+ * Returns -1 when it doesn't exist.
+ */
+    long
+mch_getperm(name)
+    char_u *name;
+{
+    struct stat statb;
+
+    /* Keep the #ifdef outside of stat(), it may be a macro. */
+#ifdef VMS
+    if (stat((char *)vms_fixfilename(name), &statb))
+#else
+    if (stat((char *)name, &statb))
+#endif
+	return -1;
+    return statb.st_mode;
+}
+
+/*
+ * set file permission for 'name' to 'perm'
+ *
+ * return FAIL for failure, OK otherwise
+ */
+    int
+mch_setperm(name, perm)
+    char_u  *name;
+    long    perm;
+{
+    return (chmod((char *)
+#ifdef VMS
+		    vms_fixfilename(name),
+#else
+		    name,
+#endif
+		    (mode_t)perm) == 0 ? OK : FAIL);
+}
+
+#if defined(HAVE_ACL) || defined(PROTO)
+# ifdef HAVE_SYS_ACL_H
+#  include <sys/acl.h>
+# endif
+# ifdef HAVE_SYS_ACCESS_H
+#  include <sys/access.h>
+# endif
+
+# ifdef HAVE_SOLARIS_ACL
+typedef struct vim_acl_solaris_T {
+    int acl_cnt;
+    aclent_t *acl_entry;
+} vim_acl_solaris_T;
+# endif
+
+/*
+ * Return a pointer to the ACL of file "fname" in allocated memory.
+ * Return NULL if the ACL is not available for whatever reason.
+ */
+    vim_acl_T
+mch_get_acl(fname)
+    char_u	*fname;
+{
+    vim_acl_T	ret = NULL;
+#ifdef HAVE_POSIX_ACL
+    ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
+#else
+#ifdef HAVE_SOLARIS_ACL
+    vim_acl_solaris_T   *aclent;
+
+    aclent = malloc(sizeof(vim_acl_solaris_T));
+    if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
+    {
+	free(aclent);
+	return NULL;
+    }
+    aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
+    if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
+    {
+	free(aclent->acl_entry);
+	free(aclent);
+	return NULL;
+    }
+    ret = (vim_acl_T)aclent;
+#else
+#if defined(HAVE_AIX_ACL)
+    int		aclsize;
+    struct acl *aclent;
+
+    aclsize = sizeof(struct acl);
+    aclent = malloc(aclsize);
+    if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
+    {
+	if (errno == ENOSPC)
+	{
+	    aclsize = aclent->acl_len;
+	    aclent = realloc(aclent, aclsize);
+	    if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
+	    {
+		free(aclent);
+		return NULL;
+	    }
+	}
+	else
+	{
+	    free(aclent);
+	    return NULL;
+	}
+    }
+    ret = (vim_acl_T)aclent;
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_POSIX_ACL */
+    return ret;
+}
+
+/*
+ * Set the ACL of file "fname" to "acl" (unless it's NULL).
+ */
+    void
+mch_set_acl(fname, aclent)
+    char_u	*fname;
+    vim_acl_T	aclent;
+{
+    if (aclent == NULL)
+	return;
+#ifdef HAVE_POSIX_ACL
+    acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
+#else
+#ifdef HAVE_SOLARIS_ACL
+    acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
+	    ((vim_acl_solaris_T *)aclent)->acl_entry);
+#else
+#ifdef HAVE_AIX_ACL
+    chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_POSIX_ACL */
+}
+
+    void
+mch_free_acl(aclent)
+    vim_acl_T	aclent;
+{
+    if (aclent == NULL)
+	return;
+#ifdef HAVE_POSIX_ACL
+    acl_free((acl_t)aclent);
+#else
+#ifdef HAVE_SOLARIS_ACL
+    free(((vim_acl_solaris_T *)aclent)->acl_entry);
+    free(aclent);
+#else
+#ifdef HAVE_AIX_ACL
+    free(aclent);
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_POSIX_ACL */
+}
+#endif
+
+/*
+ * Set hidden flag for "name".
+ */
+/* ARGSUSED */
+    void
+mch_hide(name)
+    char_u	*name;
+{
+    /* can't hide a file */
+}
+
+/*
+ * return TRUE if "name" is a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+    int
+mch_isdir(name)
+    char_u *name;
+{
+    struct stat statb;
+
+    if (*name == NUL)	    /* Some stat()s don't flag "" as an error. */
+	return FALSE;
+    if (stat((char *)name, &statb))
+	return FALSE;
+#ifdef _POSIX_SOURCE
+    return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
+#else
+    return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
+#endif
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+static int executable_file __ARGS((char_u *name));
+
+/*
+ * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
+ */
+    static int
+executable_file(name)
+    char_u	*name;
+{
+    struct stat	st;
+
+    if (stat((char *)name, &st))
+	return 0;
+    return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
+}
+
+/*
+ * Return 1 if "name" can be found in $PATH and executed, 0 if not.
+ * Return -1 if unknown.
+ */
+    int
+mch_can_exe(name)
+    char_u	*name;
+{
+    char_u	*buf;
+    char_u	*p, *e;
+    int		retval;
+
+    /* If it's an absolute or relative path don't need to use $PATH. */
+    if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
+				      || (name[1] == '.' && name[2] == '/'))))
+	return executable_file(name);
+
+    p = (char_u *)getenv("PATH");
+    if (p == NULL || *p == NUL)
+	return -1;
+    buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
+    if (buf == NULL)
+	return -1;
+
+    /*
+     * Walk through all entries in $PATH to check if "name" exists there and
+     * is an executable file.
+     */
+    for (;;)
+    {
+	e = (char_u *)strchr((char *)p, ':');
+	if (e == NULL)
+	    e = p + STRLEN(p);
+	if (e - p <= 1)		/* empty entry means current dir */
+	    STRCPY(buf, "./");
+	else
+	{
+	    STRNCPY(buf, p, e - p);
+	    buf[e - p] = NUL;
+	    add_pathsep(buf);
+	}
+	STRCAT(buf, name);
+	retval = executable_file(buf);
+	if (retval == 1)
+	    break;
+
+	if (*e != ':')
+	    break;
+	p = e + 1;
+    }
+
+    vim_free(buf);
+    return retval;
+}
+#endif
+
+/*
+ * Check what "name" is:
+ * NODE_NORMAL: file or directory (or doesn't exist)
+ * NODE_WRITABLE: writable device, socket, fifo, etc.
+ * NODE_OTHER: non-writable things
+ */
+    int
+mch_nodetype(name)
+    char_u	*name;
+{
+    struct stat	st;
+
+    if (stat((char *)name, &st))
+	return NODE_NORMAL;
+    if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
+	return NODE_NORMAL;
+#ifndef OS2
+    if (S_ISBLK(st.st_mode))	/* block device isn't writable */
+	return NODE_OTHER;
+#endif
+    /* Everything else is writable? */
+    return NODE_WRITABLE;
+}
+
+    void
+mch_early_init()
+{
+#ifdef HAVE_CHECK_STACK_GROWTH
+    int			i;
+#endif
+
+#ifdef HAVE_CHECK_STACK_GROWTH
+    check_stack_growth((char *)&i);
+
+# ifdef HAVE_GETRLIMIT
+    get_stack_limit();
+# endif
+
+#endif
+
+    /*
+     * Setup an alternative stack for signals.  Helps to catch signals when
+     * running out of stack space.
+     * Use of sigaltstack() is preferred, it's more portable.
+     * Ignore any errors.
+     */
+#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+    signal_stack = malloc(SIGSTKSZ);
+    init_signal_stack();
+#endif
+}
+
+static void exit_scroll __ARGS((void));
+
+/*
+ * Output a newline when exiting.
+ * Make sure the newline goes to the same stream as the text.
+ */
+    static void
+exit_scroll()
+{
+    if (newline_on_exit || msg_didout)
+    {
+	if (msg_use_printf())
+	{
+	    if (info_message)
+		mch_msg("\n");
+	    else
+		mch_errmsg("\r\n");
+	}
+	else
+	    out_char('\n');
+    }
+    else
+    {
+	restore_cterm_colors();		/* get original colors back */
+	msg_clr_eos_force();		/* clear the rest of the display */
+	windgoto((int)Rows - 1, 0);	/* may have moved the cursor */
+    }
+}
+
+    void
+mch_exit(r)
+    int r;
+{
+    exiting = TRUE;
+
+#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
+    x11_export_final_selection();
+#endif
+
+#ifdef FEAT_GUI
+    if (!gui.in_use)
+#endif
+    {
+	settmode(TMODE_COOK);
+#ifdef FEAT_TITLE
+	mch_restore_title(3);	/* restore xterm title and icon name */
+#endif
+	/*
+	 * When t_ti is not empty but it doesn't cause swapping terminal
+	 * pages, need to output a newline when msg_didout is set.  But when
+	 * t_ti does swap pages it should not go to the shell page.  Do this
+	 * before stoptermcap().
+	 */
+	if (swapping_screen() && !newline_on_exit)
+	    exit_scroll();
+
+	/* Stop termcap: May need to check for T_CRV response, which
+	 * requires RAW mode. */
+	stoptermcap();
+
+	/*
+	 * A newline is only required after a message in the alternate screen.
+	 * This is set to TRUE by wait_return().
+	 */
+	if (!swapping_screen() || newline_on_exit)
+	    exit_scroll();
+
+	/* Cursor may have been switched off without calling starttermcap()
+	 * when doing "vim -u vimrc" and vimrc contains ":q". */
+	if (full_screen)
+	    cursor_on();
+    }
+    out_flush();
+    ml_close_all(TRUE);		/* remove all memfiles */
+    may_core_dump();
+#ifdef FEAT_GUI
+# ifndef FEAT_GUI_BEOS		/* BeOS always has GUI */
+    if (gui.in_use)
+# endif
+	gui_exit(r);
+#endif
+#ifdef __QNX__
+    /* A core dump won't be created if the signal handler
+     * doesn't return, so we can't call exit() */
+    if (deadly_signal != 0)
+	return;
+#endif
+
+    exit(r);
+}
+
+    static void
+may_core_dump()
+{
+    if (deadly_signal != 0)
+    {
+	signal(deadly_signal, SIG_DFL);
+	kill(getpid(), deadly_signal);	/* Die using the signal we caught */
+    }
+}
+
+#ifndef VMS
+
+    void
+mch_settmode(tmode)
+    int		tmode;
+{
+    static int first = TRUE;
+
+    /* Why is NeXT excluded here (and not in os_unixx.h)? */
+#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
+    /*
+     * for "new" tty systems
+     */
+# ifdef HAVE_TERMIOS_H
+    static struct termios told;
+	   struct termios tnew;
+# else
+    static struct termio told;
+	   struct termio tnew;
+# endif
+
+    if (first)
+    {
+	first = FALSE;
+# if defined(HAVE_TERMIOS_H)
+	tcgetattr(read_cmd_fd, &told);
+# else
+	ioctl(read_cmd_fd, TCGETA, &told);
+# endif
+    }
+
+    tnew = told;
+    if (tmode == TMODE_RAW)
+    {
+	/*
+	 * ~ICRNL enables typing ^V^M
+	 */
+	tnew.c_iflag &= ~ICRNL;
+	tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
+# if defined(IEXTEN) && !defined(__MINT__)
+		    | IEXTEN	    /* IEXTEN enables typing ^V on SOLARIS */
+				    /* but it breaks function keys on MINT */
+# endif
+				);
+# ifdef ONLCR	    /* don't map NL -> CR NL, we do it ourselves */
+	tnew.c_oflag &= ~ONLCR;
+# endif
+	tnew.c_cc[VMIN] = 1;		/* return after 1 char */
+	tnew.c_cc[VTIME] = 0;		/* don't wait */
+    }
+    else if (tmode == TMODE_SLEEP)
+	tnew.c_lflag &= ~(ECHO);
+
+# if defined(HAVE_TERMIOS_H)
+    {
+	int	n = 10;
+
+	/* A signal may cause tcsetattr() to fail (e.g., SIGCONT).  Retry a
+	 * few times. */
+	while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
+						   && errno == EINTR && n > 0)
+	    --n;
+    }
+# else
+    ioctl(read_cmd_fd, TCSETA, &tnew);
+# endif
+
+#else
+
+    /*
+     * for "old" tty systems
+     */
+# ifndef TIOCSETN
+#  define TIOCSETN TIOCSETP	/* for hpux 9.0 */
+# endif
+    static struct sgttyb ttybold;
+	   struct sgttyb ttybnew;
+
+    if (first)
+    {
+	first = FALSE;
+	ioctl(read_cmd_fd, TIOCGETP, &ttybold);
+    }
+
+    ttybnew = ttybold;
+    if (tmode == TMODE_RAW)
+    {
+	ttybnew.sg_flags &= ~(CRMOD | ECHO);
+	ttybnew.sg_flags |= RAW;
+    }
+    else if (tmode == TMODE_SLEEP)
+	ttybnew.sg_flags &= ~(ECHO);
+    ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
+#endif
+    curr_tmode = tmode;
+}
+
+/*
+ * Try to get the code for "t_kb" from the stty setting
+ *
+ * Even if termcap claims a backspace key, the user's setting *should*
+ * prevail.  stty knows more about reality than termcap does, and if
+ * somebody's usual erase key is DEL (which, for most BSD users, it will
+ * be), they're going to get really annoyed if their erase key starts
+ * doing forward deletes for no reason. (Eric Fischer)
+ */
+    void
+get_stty()
+{
+    char_u  buf[2];
+    char_u  *p;
+
+    /* Why is NeXT excluded here (and not in os_unixx.h)? */
+#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
+    /* for "new" tty systems */
+# ifdef HAVE_TERMIOS_H
+    struct termios keys;
+# else
+    struct termio keys;
+# endif
+
+# if defined(HAVE_TERMIOS_H)
+    if (tcgetattr(read_cmd_fd, &keys) != -1)
+# else
+    if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
+# endif
+    {
+	buf[0] = keys.c_cc[VERASE];
+	intr_char = keys.c_cc[VINTR];
+#else
+    /* for "old" tty systems */
+    struct sgttyb keys;
+
+    if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
+    {
+	buf[0] = keys.sg_erase;
+	intr_char = keys.sg_kill;
+#endif
+	buf[1] = NUL;
+	add_termcode((char_u *)"kb", buf, FALSE);
+
+	/*
+	 * If <BS> and <DEL> are now the same, redefine <DEL>.
+	 */
+	p = find_termcode((char_u *)"kD");
+	if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
+	    do_fixdel(NULL);
+    }
+#if 0
+    }	    /* to keep cindent happy */
+#endif
+}
+
+#endif /* VMS  */
+
+#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
+/*
+ * Set mouse clicks on or off.
+ */
+    void
+mch_setmouse(on)
+    int		on;
+{
+    static int	ison = FALSE;
+    int		xterm_mouse_vers;
+
+    if (on == ison)	/* return quickly if nothing to do */
+	return;
+
+    xterm_mouse_vers = use_xterm_mouse();
+    if (xterm_mouse_vers > 0)
+    {
+	if (on)	/* enable mouse events, use mouse tracking if available */
+	    out_str_nf((char_u *)
+		       (xterm_mouse_vers > 1
+			? IF_EB("\033[?1002h", ESC_STR "[?1002h")
+			: IF_EB("\033[?1000h", ESC_STR "[?1000h")));
+	else	/* disable mouse events, could probably always send the same */
+	    out_str_nf((char_u *)
+		       (xterm_mouse_vers > 1
+			? IF_EB("\033[?1002l", ESC_STR "[?1002l")
+			: IF_EB("\033[?1000l", ESC_STR "[?1000l")));
+	ison = on;
+    }
+
+# ifdef FEAT_MOUSE_DEC
+    else if (ttym_flags == TTYM_DEC)
+    {
+	if (on)	/* enable mouse events */
+	    out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
+	else	/* disable mouse events */
+	    out_str_nf((char_u *)"\033['z");
+	ison = on;
+    }
+# endif
+
+# ifdef FEAT_MOUSE_GPM
+    else
+    {
+	if (on)
+	{
+	    if (gpm_open())
+		ison = TRUE;
+	}
+	else
+	{
+	    gpm_close();
+	    ison = FALSE;
+	}
+    }
+# endif
+
+# ifdef FEAT_MOUSE_JSB
+    else
+    {
+	if (on)
+	{
+	    /* D - Enable Mouse up/down messages
+	     * L - Enable Left Button Reporting
+	     * M - Enable Middle Button Reporting
+	     * R - Enable Right Button Reporting
+	     * K - Enable SHIFT and CTRL key Reporting
+	     * + - Enable Advanced messaging of mouse moves and up/down messages
+	     * Q - Quiet No Ack
+	     * # - Numeric value of mouse pointer required
+	     *	  0 = Multiview 2000 cursor, used as standard
+	     *	  1 = Windows Arrow
+	     *	  2 = Windows I Beam
+	     *	  3 = Windows Hour Glass
+	     *	  4 = Windows Cross Hair
+	     *	  5 = Windows UP Arrow
+	     */
+#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
+	    out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
+					 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
+#else
+	    out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
+					ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
+#endif
+	    ison = TRUE;
+	}
+	else
+	{
+	    out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
+					      ESC_STR "[0~ZwQ" ESC_STR "\\"));
+	    ison = FALSE;
+	}
+    }
+# endif
+# ifdef FEAT_MOUSE_PTERM
+    else
+    {
+	/* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
+	if (on)
+	    out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
+	else
+	    out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
+	ison = on;
+    }
+# endif
+}
+
+/*
+ * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
+ */
+    void
+check_mouse_termcode()
+{
+# ifdef FEAT_MOUSE_XTERM
+    if (use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+    {
+	set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
+		  ? IF_EB("\233M", CSI_STR "M") : IF_EB("\033[M", ESC_STR "[M")));
+	if (*p_mouse != NUL)
+	{
+	    /* force mouse off and maybe on to send possibly new mouse
+	     * activation sequence to the xterm, with(out) drag tracing. */
+	    mch_setmouse(FALSE);
+	    setmouse();
+	}
+    }
+    else
+	del_mouse_termcode(KS_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_GPM
+    if (!use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+	set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
+# endif
+
+# ifdef FEAT_MOUSE_JSB
+    /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
+    if (!use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+	set_mouse_termcode(KS_JSBTERM_MOUSE,
+			       (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
+    else
+	del_mouse_termcode(KS_JSBTERM_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_NET
+    /* There is no conflict, but one may type ESC } from Insert mode.  Don't
+     * define it in the GUI or when using an xterm. */
+    if (!use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+	set_mouse_termcode(KS_NETTERM_MOUSE,
+				       (char_u *)IF_EB("\033}", ESC_STR "}"));
+    else
+	del_mouse_termcode(KS_NETTERM_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_DEC
+    /* conflicts with xterm mouse: "\033[" and "\033[M" */
+    if (!use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+	set_mouse_termcode(KS_DEC_MOUSE,
+				       (char_u *)IF_EB("\033[", ESC_STR "["));
+    else
+	del_mouse_termcode(KS_DEC_MOUSE);
+# endif
+# ifdef FEAT_MOUSE_PTERM
+    /* same as the dec mouse */
+    if (!use_xterm_mouse()
+#  ifdef FEAT_GUI
+	    && !gui.in_use
+#  endif
+	    )
+	set_mouse_termcode(KS_PTERM_MOUSE,
+				      (char_u *) IF_EB("\033[", ESC_STR "["));
+    else
+	del_mouse_termcode(KS_PTERM_MOUSE);
+# endif
+}
+#endif
+
+/*
+ * set screen mode, always fails.
+ */
+/* ARGSUSED */
+    int
+mch_screenmode(arg)
+    char_u   *arg;
+{
+    EMSG(_(e_screenmode));
+    return FAIL;
+}
+
+#ifndef VMS
+
+/*
+ * Try to get the current window size:
+ * 1. with an ioctl(), most accurate method
+ * 2. from the environment variables LINES and COLUMNS
+ * 3. from the termcap
+ * 4. keep using the old values
+ * Return OK when size could be determined, FAIL otherwise.
+ */
+    int
+mch_get_shellsize()
+{
+    long	rows = 0;
+    long	columns = 0;
+    char_u	*p;
+
+    /*
+     * For OS/2 use _scrsize().
+     */
+# ifdef __EMX__
+    {
+	int s[2];
+
+	_scrsize(s);
+	columns = s[0];
+	rows = s[1];
+    }
+# endif
+
+    /*
+     * 1. try using an ioctl. It is the most accurate method.
+     *
+     * Try using TIOCGWINSZ first, some systems that have it also define
+     * TIOCGSIZE but don't have a struct ttysize.
+     */
+# ifdef TIOCGWINSZ
+    {
+	struct winsize	ws;
+	int fd = 1;
+
+	/* When stdout is not a tty, use stdin for the ioctl(). */
+	if (!isatty(fd) && isatty(read_cmd_fd))
+	    fd = read_cmd_fd;
+	if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
+	{
+	    columns = ws.ws_col;
+	    rows = ws.ws_row;
+	}
+    }
+# else /* TIOCGWINSZ */
+#  ifdef TIOCGSIZE
+    {
+	struct ttysize	ts;
+	int fd = 1;
+
+	/* When stdout is not a tty, use stdin for the ioctl(). */
+	if (!isatty(fd) && isatty(read_cmd_fd))
+	    fd = read_cmd_fd;
+	if (ioctl(fd, TIOCGSIZE, &ts) == 0)
+	{
+	    columns = ts.ts_cols;
+	    rows = ts.ts_lines;
+	}
+    }
+#  endif /* TIOCGSIZE */
+# endif /* TIOCGWINSZ */
+
+    /*
+     * 2. get size from environment
+     */
+    if (columns == 0 || rows == 0)
+    {
+	if ((p = (char_u *)getenv("LINES")))
+	    rows = atoi((char *)p);
+	if ((p = (char_u *)getenv("COLUMNS")))
+	    columns = atoi((char *)p);
+    }
+
+#ifdef HAVE_TGETENT
+    /*
+     * 3. try reading "co" and "li" entries from termcap
+     */
+    if (columns == 0 || rows == 0)
+	getlinecol(&columns, &rows);
+#endif
+
+    /*
+     * 4. If everything fails, use the old values
+     */
+    if (columns <= 0 || rows <= 0)
+	return FAIL;
+
+    Rows = rows;
+    Columns = columns;
+    return OK;
+}
+
+/*
+ * Try to set the window size to Rows and Columns.
+ */
+    void
+mch_set_shellsize()
+{
+    if (*T_CWS)
+    {
+	/*
+	 * NOTE: if you get an error here that term_set_winsize() is
+	 * undefined, check the output of configure.  It could probably not
+	 * find a ncurses, termcap or termlib library.
+	 */
+	term_set_winsize((int)Rows, (int)Columns);
+	out_flush();
+	screen_start();			/* don't know where cursor is now */
+    }
+}
+
+#endif /* VMS */
+
+/*
+ * Rows and/or Columns has changed.
+ */
+    void
+mch_new_shellsize()
+{
+    /* Nothing to do. */
+}
+
+    int
+mch_call_shell(cmd, options)
+    char_u	*cmd;
+    int		options;	/* SHELL_*, see vim.h */
+{
+#ifdef VMS
+    char	*ifn = NULL;
+    char	*ofn = NULL;
+#endif
+    int		tmode = cur_tmode;
+#ifdef USE_SYSTEM	/* use system() to start the shell: simple but slow */
+    int	    x;
+# ifndef __EMX__
+    char_u  *newcmd;   /* only needed for unix */
+# else
+    /*
+     * Set the preferred shell in the EMXSHELL environment variable (but
+     * only if it is different from what is already in the environment).
+     * Emx then takes care of whether to use "/c" or "-c" in an
+     * intelligent way. Simply pass the whole thing to emx's system() call.
+     * Emx also starts an interactive shell if system() is passed an empty
+     * string.
+     */
+    char_u *p, *old;
+
+    if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
+    {
+	/* should check HAVE_SETENV, but I know we don't have it. */
+	p = alloc(10 + strlen(p_sh));
+	if (p)
+	{
+	    sprintf((char *)p, "EMXSHELL=%s", p_sh);
+	    putenv((char *)p);	/* don't free the pointer! */
+	}
+    }
+# endif
+
+    out_flush();
+
+    if (options & SHELL_COOKED)
+	settmode(TMODE_COOK);	    /* set to normal mode */
+
+# ifdef __EMX__
+    if (cmd == NULL)
+	x = system("");	/* this starts an interactive shell in emx */
+    else
+	x = system((char *)cmd);
+    /* system() returns -1 when error occurs in starting shell */
+    if (x == -1 && !emsg_silent)
+    {
+	MSG_PUTS(_("\nCannot execute shell "));
+	msg_outtrans(p_sh);
+	msg_putchar('\n');
+    }
+# else /* not __EMX__ */
+    if (cmd == NULL)
+	x = system((char *)p_sh);
+    else
+    {
+#  ifdef VMS
+	if (ofn = strchr((char *)cmd, '>'))
+	    *ofn++ = '\0';
+	if (ifn = strchr((char *)cmd, '<'))
+	{
+	    char *p;
+
+	    *ifn++ = '\0';
+	    p = strchr(ifn,' '); /* chop off any trailing spaces */
+	    if (p)
+		*p = '\0';
+	}
+	if (ofn)
+	    x = vms_sys((char *)cmd, ofn, ifn);
+	else
+	    x = system((char *)cmd);
+#  else
+	newcmd = lalloc(STRLEN(p_sh)
+		+ (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
+		+ STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
+	if (newcmd == NULL)
+	    x = 0;
+	else
+	{
+	    sprintf((char *)newcmd, "%s %s %s %s", p_sh,
+		    extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
+		    (char *)p_shcf,
+		    (char *)cmd);
+	    x = system((char *)newcmd);
+	    vim_free(newcmd);
+	}
+#  endif
+    }
+# ifdef VMS
+    x = vms_sys_status(x);
+# endif
+    if (emsg_silent)
+	;
+    else if (x == 127)
+	MSG_PUTS(_("\nCannot execute shell sh\n"));
+# endif	/* __EMX__ */
+    else if (x && !(options & SHELL_SILENT))
+    {
+	MSG_PUTS(_("\nshell returned "));
+	msg_outnum((long)x);
+	msg_putchar('\n');
+    }
+
+    if (tmode == TMODE_RAW)
+	settmode(TMODE_RAW);	/* set to raw mode */
+# ifdef FEAT_TITLE
+    resettitle();
+# endif
+    return x;
+
+#else /* USE_SYSTEM */	    /* don't use system(), use fork()/exec() */
+
+#define EXEC_FAILED 122	    /* Exit code when shell didn't execute.  Don't use
+			       127, some shell use that already */
+
+    char_u	*newcmd = NULL;
+    pid_t	pid;
+    pid_t	wait_pid = 0;
+# ifdef HAVE_UNION_WAIT
+    union wait	status;
+# else
+    int		status = -1;
+# endif
+    int		retval = -1;
+    char	**argv = NULL;
+    int		argc;
+    int		i;
+    char_u	*p;
+    int		inquote;
+# ifdef FEAT_GUI
+    int		pty_master_fd = -1;	    /* for pty's */
+    int		pty_slave_fd = -1;
+    char	*tty_name;
+    int		fd_toshell[2];	    /* for pipes */
+    int		fd_fromshell[2];
+    int		pipe_error = FALSE;
+#  ifdef HAVE_SETENV
+    char	envbuf[50];
+#  else
+    static char	envbuf_Rows[20];
+    static char	envbuf_Columns[20];
+#  endif
+# endif
+    int		did_settmode = FALSE; /* TRUE when settmode(TMODE_RAW) called */
+
+    out_flush();
+    if (options & SHELL_COOKED)
+	settmode(TMODE_COOK);		/* set to normal mode */
+
+    /*
+     * 1: find number of arguments
+     * 2: separate them and built argv[]
+     */
+    newcmd = vim_strsave(p_sh);
+    if (newcmd == NULL)		/* out of memory */
+	goto error;
+    for (i = 0; i < 2; ++i)
+    {
+	p = newcmd;
+	inquote = FALSE;
+	argc = 0;
+	for (;;)
+	{
+	    if (i == 1)
+		argv[argc] = (char *)p;
+	    ++argc;
+	    while (*p && (inquote || (*p != ' ' && *p != TAB)))
+	    {
+		if (*p == '"')
+		    inquote = !inquote;
+		++p;
+	    }
+	    if (*p == NUL)
+		break;
+	    if (i == 1)
+		*p++ = NUL;
+	    p = skipwhite(p);
+	}
+	if (i == 0)
+	{
+	    argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
+	    if (argv == NULL)	    /* out of memory */
+		goto error;
+	}
+    }
+    if (cmd != NULL)
+    {
+	if (extra_shell_arg != NULL)
+	    argv[argc++] = (char *)extra_shell_arg;
+	argv[argc++] = (char *)p_shcf;
+	argv[argc++] = (char *)cmd;
+    }
+    argv[argc] = NULL;
+
+# ifdef FEAT_GUI
+    /*
+     * For the GUI: Try using a pseudo-tty to get the stdin/stdout of the
+     * executed command into the Vim window.  Or use a pipe.
+     */
+    if (gui.in_use && show_shell_mess)
+    {
+	/*
+	 * Try to open a master pty.
+	 * If this works, open the slave pty.
+	 * If the slave can't be opened, close the master pty.
+	 */
+	if (p_guipty)
+	{
+	    pty_master_fd = OpenPTY(&tty_name);	    /* open pty */
+	    if (pty_master_fd >= 0 && ((pty_slave_fd =
+				    open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
+	    {
+		close(pty_master_fd);
+		pty_master_fd = -1;
+	    }
+	}
+	/*
+	 * If not opening a pty or it didn't work, try using pipes.
+	 */
+	if (pty_master_fd < 0)
+	{
+	    pipe_error = (pipe(fd_toshell) < 0);
+	    if (!pipe_error)			    /* pipe create OK */
+	    {
+		pipe_error = (pipe(fd_fromshell) < 0);
+		if (pipe_error)			    /* pipe create failed */
+		{
+		    close(fd_toshell[0]);
+		    close(fd_toshell[1]);
+		}
+	    }
+	    if (pipe_error)
+	    {
+		MSG_PUTS(_("\nCannot create pipes\n"));
+		out_flush();
+	    }
+	}
+    }
+
+    if (!pipe_error)			/* pty or pipe opened or not used */
+# endif
+
+    {
+# ifdef __BEOS__
+	beos_cleanup_read_thread();
+# endif
+	if ((pid = fork()) == -1)	/* maybe we should use vfork() */
+	{
+	    MSG_PUTS(_("\nCannot fork\n"));
+# ifdef FEAT_GUI
+	    if (gui.in_use && show_shell_mess)
+	    {
+		if (pty_master_fd >= 0)		/* close the pseudo tty */
+		{
+		    close(pty_master_fd);
+		    close(pty_slave_fd);
+		}
+		else				/* close the pipes */
+		{
+		    close(fd_toshell[0]);
+		    close(fd_toshell[1]);
+		    close(fd_fromshell[0]);
+		    close(fd_fromshell[1]);
+		}
+	    }
+# endif
+	}
+	else if (pid == 0)	/* child */
+	{
+	    reset_signals();		/* handle signals normally */
+
+	    if (!show_shell_mess || (options & SHELL_EXPAND))
+	    {
+		int fd;
+
+		/*
+		 * Don't want to show any message from the shell.  Can't just
+		 * close stdout and stderr though, because some systems will
+		 * break if you try to write to them after that, so we must
+		 * use dup() to replace them with something else -- webb
+		 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
+		 * waiting for input.
+		 */
+		fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
+		fclose(stdin);
+		fclose(stdout);
+		fclose(stderr);
+
+		/*
+		 * If any of these open()'s and dup()'s fail, we just continue
+		 * anyway.  It's not fatal, and on most systems it will make
+		 * no difference at all.  On a few it will cause the execvp()
+		 * to exit with a non-zero status even when the completion
+		 * could be done, which is nothing too serious.  If the open()
+		 * or dup() failed we'd just do the same thing ourselves
+		 * anyway -- webb
+		 */
+		if (fd >= 0)
+		{
+		    dup(fd); /* To replace stdin  (file descriptor 0) */
+		    dup(fd); /* To replace stdout (file descriptor 1) */
+		    dup(fd); /* To replace stderr (file descriptor 2) */
+
+		    /* Don't need this now that we've duplicated it */
+		    close(fd);
+		}
+	    }
+# ifdef FEAT_GUI
+	    else if (gui.in_use)
+	    {
+
+#  ifdef HAVE_SETSID
+		(void)setsid();
+#  endif
+		/* push stream discipline modules */
+		if (options & SHELL_COOKED)
+		    SetupSlavePTY(pty_slave_fd);
+#  ifdef TIOCSCTTY
+		/* try to become controlling tty (probably doesn't work,
+		 * unless run by root) */
+		ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
+#  endif
+		/* Simulate to have a dumb terminal (for now) */
+#  ifdef HAVE_SETENV
+		setenv("TERM", "dumb", 1);
+		sprintf((char *)envbuf, "%ld", Rows);
+		setenv("ROWS", (char *)envbuf, 1);
+		sprintf((char *)envbuf, "%ld", Rows);
+		setenv("LINES", (char *)envbuf, 1);
+		sprintf((char *)envbuf, "%ld", Columns);
+		setenv("COLUMNS", (char *)envbuf, 1);
+#  else
+		/*
+		 * Putenv does not copy the string, it has to remain valid.
+		 * Use a static array to avoid loosing allocated memory.
+		 */
+		putenv("TERM=dumb");
+		sprintf(envbuf_Rows, "ROWS=%ld", Rows);
+		putenv(envbuf_Rows);
+		sprintf(envbuf_Rows, "LINES=%ld", Rows);
+		putenv(envbuf_Rows);
+		sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
+		putenv(envbuf_Columns);
+#  endif
+
+		if (pty_master_fd >= 0)
+		{
+		    close(pty_master_fd);   /* close master side of pty */
+
+		    /* set up stdin/stdout/stderr for the child */
+		    close(0);
+		    dup(pty_slave_fd);
+		    close(1);
+		    dup(pty_slave_fd);
+		    close(2);
+		    dup(pty_slave_fd);
+
+		    close(pty_slave_fd);    /* has been dupped, close it now */
+		}
+		else
+		{
+		    /* set up stdin for the child */
+		    close(fd_toshell[1]);
+		    close(0);
+		    dup(fd_toshell[0]);
+		    close(fd_toshell[0]);
+
+		    /* set up stdout for the child */
+		    close(fd_fromshell[0]);
+		    close(1);
+		    dup(fd_fromshell[1]);
+		    close(fd_fromshell[1]);
+
+		    /* set up stderr for the child */
+		    close(2);
+		    dup(1);
+		}
+	    }
+# endif /* FEAT_GUI */
+	    /*
+	     * There is no type cast for the argv, because the type may be
+	     * different on different machines. This may cause a warning
+	     * message with strict compilers, don't worry about it.
+	     * Call _exit() instead of exit() to avoid closing the connection
+	     * to the X server (esp. with GTK, which uses atexit()).
+	     */
+	    execvp(argv[0], argv);
+	    _exit(EXEC_FAILED);	    /* exec failed, return failure code */
+	}
+	else			/* parent */
+	{
+	    /*
+	     * While child is running, ignore terminating signals.
+	     */
+	    catch_signals(SIG_IGN, SIG_ERR);
+
+# ifdef FEAT_GUI
+
+	    /*
+	     * For the GUI we redirect stdin, stdout and stderr to our window.
+	     */
+	    if (gui.in_use && show_shell_mess)
+	    {
+#  define BUFLEN 100		/* length for buffer, pseudo tty limit is 128 */
+		char_u	    buffer[BUFLEN + 1];
+#  ifdef FEAT_MBYTE
+		int	    buffer_off = 0;	/* valid bytes in buffer[] */
+#  endif
+		char_u	    ta_buf[BUFLEN + 1];	/* TypeAHead */
+		int	    ta_len = 0;		/* valid bytes in ta_buf[] */
+		int	    len;
+		int	    p_more_save;
+		int	    old_State;
+		int	    c;
+		int	    toshell_fd;
+		int	    fromshell_fd;
+
+		if (pty_master_fd >= 0)
+		{
+		    close(pty_slave_fd);	/* close slave side of pty */
+		    fromshell_fd = pty_master_fd;
+		    toshell_fd = dup(pty_master_fd);
+		}
+		else
+		{
+		    close(fd_toshell[0]);
+		    close(fd_fromshell[1]);
+		    toshell_fd = fd_toshell[1];
+		    fromshell_fd = fd_fromshell[0];
+		}
+
+		/*
+		 * Write to the child if there are typed characters.
+		 * Read from the child if there are characters available.
+		 *   Repeat the reading a few times if more characters are
+		 *   available. Need to check for typed keys now and then, but
+		 *   not too often (delays when no chars are available).
+		 * This loop is quit if no characters can be read from the pty
+		 * (WaitForChar detected special condition), or there are no
+		 * characters available and the child has exited.
+		 * Only check if the child has exited when there is no more
+		 * output. The child may exit before all the output has
+		 * been printed.
+		 *
+		 * Currently this busy loops!
+		 * This can probably dead-lock when the write blocks!
+		 */
+		p_more_save = p_more;
+		p_more = FALSE;
+		old_State = State;
+		State = EXTERNCMD;	/* don't redraw at window resize */
+
+		for (;;)
+		{
+		    /*
+		     * Check if keys have been typed, write them to the child
+		     * if there are any.  Don't do this if we are expanding
+		     * wild cards (would eat typeahead).  Don't get extra
+		     * characters when we already have one.
+		     */
+		    len = 0;
+		    if (!(options & SHELL_EXPAND)
+			    && (ta_len > 0
+				|| (len = ui_inchar(ta_buf, BUFLEN, 10L,
+								     0)) > 0))
+		    {
+			/*
+			 * For pipes:
+			 * Check for CTRL-C: send interrupt signal to child.
+			 * Check for CTRL-D: EOF, close pipe to child.
+			 */
+			if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
+			{
+#  ifdef SIGINT
+			    /*
+			     * Send SIGINT to the child's group or all
+			     * processes in our group.
+			     */
+			    if (ta_buf[ta_len] == Ctrl_C
+					       || ta_buf[ta_len] == intr_char)
+#   ifdef HAVE_SETSID
+				kill(-pid, SIGINT);
+#   else
+				kill(0, SIGINT);
+#   endif
+#  endif
+			    if (pty_master_fd < 0 && toshell_fd >= 0
+					       && ta_buf[ta_len] == Ctrl_D)
+			    {
+				close(toshell_fd);
+				toshell_fd = -1;
+			    }
+			}
+
+			/* replace K_BS by <BS> and K_DEL by <DEL> */
+			for (i = ta_len; i < ta_len + len; ++i)
+			{
+			    if (ta_buf[i] == CSI && len - i > 2)
+			    {
+				c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
+				if (c == K_DEL || c == K_KDEL || c == K_BS)
+				{
+				    mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
+						       (size_t)(len - i - 2));
+				    if (c == K_DEL || c == K_KDEL)
+					ta_buf[i] = DEL;
+				    else
+					ta_buf[i] = Ctrl_H;
+				    len -= 2;
+				}
+			    }
+			    else if (ta_buf[i] == '\r')
+				ta_buf[i] = '\n';
+#  ifdef FEAT_MBYTE
+			    if (has_mbyte)
+				i += (*mb_ptr2len_check)(ta_buf + i) - 1;
+#  endif
+			}
+
+			/*
+			 * For pipes: echo the typed characters.
+			 * For a pty this does not seem to work.
+			 */
+			if (pty_master_fd < 0)
+			{
+			    for (i = ta_len; i < ta_len + len; ++i)
+			    {
+				if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
+				    msg_putchar(ta_buf[i]);
+#  ifdef FEAT_MBYTE
+				else if (has_mbyte)
+				{
+				    int l = (*mb_ptr2len_check)(ta_buf + i);
+
+				    msg_outtrans_len(ta_buf + i, l);
+				    i += l - 1;
+				}
+#  endif
+				else
+				    msg_outtrans_len(ta_buf + i, 1);
+			    }
+			    windgoto(msg_row, msg_col);
+			    out_flush();
+			}
+
+			ta_len += len;
+
+			/*
+			 * Write the characters to the child, unless EOF has
+			 * been typed for pipes.  Write one character at a
+			 * time, to avoid loosing too much typeahead.
+			 */
+			if (toshell_fd >= 0)
+			{
+			    len = write(toshell_fd, (char *)ta_buf, (size_t)1);
+			    if (len > 0)
+			    {
+				ta_len -= len;
+				mch_memmove(ta_buf, ta_buf + len, ta_len);
+			    }
+			}
+		    }
+
+		    /*
+		     * Check if the child has any characters to be printed.
+		     * Read them and write them to our window.	Repeat this as
+		     * long as there is something to do, avoid the 10ms wait
+		     * for mch_inchar(), or sending typeahead characters to
+		     * the external process.
+		     * TODO: This should handle escape sequences, compatible
+		     * to some terminal (vt52?).
+		     */
+		    while (RealWaitForChar(fromshell_fd, 10L, NULL))
+		    {
+			len = read(fromshell_fd, (char *)buffer
+#  ifdef FEAT_MBYTE
+				+ buffer_off, (size_t)(BUFLEN - buffer_off)
+#  else
+				, (size_t)BUFLEN
+#  endif
+				);
+			if (len <= 0)		    /* end of file or error */
+			    goto finished;
+#  ifdef FEAT_MBYTE
+			len += buffer_off;
+			buffer[len] = NUL;
+			if (has_mbyte)
+			{
+			    int		l;
+
+			    /* Check if the last character in buffer[] is
+			     * incomplete, keep these bytes for the next
+			     * round. */
+			    for (p = buffer; p < buffer + len; p += l)
+			    {
+				if (enc_utf8)	/* exclude composing chars */
+				    l = utf_ptr2len_check(p);
+				else
+				    l = (*mb_ptr2len_check)(p);
+				if (l == 0)
+				    l = 1;  /* NUL byte? */
+				else if (MB_BYTE2LEN(*p) != l)
+				    break;
+			    }
+			    if (p == buffer)	/* no complete character */
+			    {
+				/* avoid getting stuck at an illegal byte */
+				if (len >= 12)
+				    ++p;
+				else
+				{
+				    buffer_off = len;
+				    continue;
+				}
+			    }
+			    c = *p;
+			    *p = NUL;
+			    msg_puts(buffer);
+			    if (p < buffer + len)
+			    {
+				*p = c;
+				buffer_off = (buffer + len) - p;
+				mch_memmove(buffer, p, buffer_off);
+				continue;
+			    }
+			    buffer_off = 0;
+			}
+			else
+#  endif /* FEAT_MBYTE */
+			{
+			    buffer[len] = NUL;
+			    msg_puts(buffer);
+			}
+
+			windgoto(msg_row, msg_col);
+			cursor_on();
+			out_flush();
+			if (got_int)
+			    break;
+		    }
+
+		    /*
+		     * Check if the child still exists, before checking for
+		     * typed characters (otherwise we would loose typeahead).
+		     */
+#  ifdef __NeXT__
+		    wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
+#  else
+		    wait_pid = waitpid(pid, &status, WNOHANG);
+#  endif
+		    if ((wait_pid == (pid_t)-1 && errno == ECHILD)
+			    || (wait_pid == pid && WIFEXITED(status)))
+		    {
+			wait_pid = pid;
+			break;
+		    }
+		    wait_pid = 0;
+		}
+finished:
+		p_more = p_more_save;
+
+#  ifndef MACOS_X_UNIX /* TODO: Is it needed for MACOS_X ? */
+		/*
+		 * Give all typeahead that wasn't used back to ui_inchar().
+		 */
+		if (ta_len)
+		    ui_inchar_undo(ta_buf, ta_len);
+#  endif
+		State = old_State;
+		if (toshell_fd >= 0)
+		    close(toshell_fd);
+		close(fromshell_fd);
+	    }
+# endif /* FEAT_GUI */
+
+	    /*
+	     * Wait until our child has exited.
+	     * Ignore wait() returning pids of other children and returning
+	     * because of some signal like SIGWINCH.
+	     * Don't wait if wait_pid was already set above, indicating the
+	     * child already exited.
+	     */
+	    while (wait_pid != pid)
+	    {
+#ifdef _THREAD_SAFE
+		/* Ugly hack: when compiled with Python threads are probably
+		 * used, in which case wait() sometimes hangs for no obvious
+		 * reason.  Use waitpid() instead and loop (like the GUI). */
+#  ifdef __NeXT__
+		wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
+#  else
+		wait_pid = waitpid(pid, &status, WNOHANG);
+#  endif
+		if (wait_pid == 0)
+		{
+		    /* Wait for 1/100 sec before trying again. */
+		    mch_delay(10L, TRUE);
+		    continue;
+		}
+#else
+		wait_pid = wait(&status);
+#endif
+		if (wait_pid <= 0
+# ifdef ECHILD
+			&& errno == ECHILD
+# endif
+		   )
+		    break;
+	    }
+
+	    /*
+	     * Set to raw mode right now, otherwise a CTRL-C after
+	     * catch_signals() will kill Vim.
+	     */
+	    if (tmode == TMODE_RAW)
+		settmode(TMODE_RAW);
+	    did_settmode = TRUE;
+	    set_signals();
+
+	    if (WIFEXITED(status))
+	    {
+		retval = WEXITSTATUS(status);
+		if (retval && !emsg_silent)
+		{
+		    if (retval == EXEC_FAILED)
+		    {
+			MSG_PUTS(_("\nCannot execute shell "));
+			msg_outtrans(p_sh);
+			msg_putchar('\n');
+		    }
+		    else if (!(options & SHELL_SILENT))
+		    {
+			MSG_PUTS(_("\nshell returned "));
+			msg_outnum((long)retval);
+			msg_putchar('\n');
+		    }
+		}
+	    }
+	    else
+		MSG_PUTS(_("\nCommand terminated\n"));
+	}
+    }
+    vim_free(argv);
+
+error:
+    if (!did_settmode)
+	if (tmode == TMODE_RAW)
+	    settmode(TMODE_RAW);	/* set to raw mode */
+# ifdef FEAT_TITLE
+    resettitle();
+# endif
+    vim_free(newcmd);
+
+    return retval;
+
+#endif /* USE_SYSTEM */
+}
+
+/*
+ * Check for CTRL-C typed by reading all available characters.
+ * In cooked mode we should get SIGINT, no need to check.
+ */
+    void
+mch_breakcheck()
+{
+    if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
+	fill_input_buf(FALSE);
+}
+
+/*
+ * Wait "msec" msec until a character is available from the keyboard or from
+ * inbuf[]. msec == -1 will block forever.
+ * When a GUI is being used, this will never get called -- webb
+ */
+    static int
+WaitForChar(msec)
+    long	msec;
+{
+#ifdef FEAT_MOUSE_GPM
+    int		gpm_process_wanted;
+#endif
+#ifdef FEAT_XCLIPBOARD
+    int		rest;
+#endif
+    int		avail;
+
+    if (input_available())	    /* something in inbuf[] */
+	return 1;
+
+#if defined(FEAT_MOUSE_DEC)
+    /* May need to query the mouse position. */
+    if (WantQueryMouse)
+    {
+	WantQueryMouse = 0;
+	mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
+    }
+#endif
+
+    /*
+     * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
+     * events.  This is a bit complicated, because they might both be defined.
+     */
+#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
+# ifdef FEAT_XCLIPBOARD
+    rest = 0;
+    if (do_xterm_trace())
+	rest = msec;
+# endif
+    do
+    {
+# ifdef FEAT_XCLIPBOARD
+	if (rest != 0)
+	{
+	    msec = XT_TRACE_DELAY;
+	    if (rest >= 0 && rest < XT_TRACE_DELAY)
+		msec = rest;
+	    if (rest >= 0)
+		rest -= msec;
+	}
+# endif
+# ifdef FEAT_MOUSE_GPM
+	gpm_process_wanted = 0;
+	avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
+# else
+	avail = RealWaitForChar(read_cmd_fd, msec, NULL);
+# endif
+	if (!avail)
+	{
+	    if (input_available())
+		return 1;
+# ifdef FEAT_XCLIPBOARD
+	    if (rest == 0 || !do_xterm_trace())
+# endif
+		break;
+	}
+    }
+    while (FALSE
+# ifdef FEAT_MOUSE_GPM
+	   || (gpm_process_wanted && mch_gpm_process() == 0)
+# endif
+# ifdef FEAT_XCLIPBOARD
+	   || (!avail && rest != 0)
+# endif
+	  );
+
+#else
+    avail = RealWaitForChar(read_cmd_fd, msec, NULL);
+#endif
+    return avail;
+}
+
+/*
+ * Wait "msec" msec until a character is available from file descriptor "fd".
+ * Time == -1 will block forever.
+ * When a GUI is being used, this will not be used for input -- webb
+ * Returns also, when a request from Sniff is waiting -- toni.
+ * Or when a Linux GPM mouse event is waiting.
+ */
+/* ARGSUSED */
+#if defined(__BEOS__)
+    int
+#else
+    static  int
+#endif
+RealWaitForChar(fd, msec, check_for_gpm)
+    int		fd;
+    long	msec;
+    int		*check_for_gpm;
+{
+    int		ret;
+#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP)
+    static int	busy = FALSE;
+
+    /* May retry getting characters after an event was handled. */
+# define MAY_LOOP
+
+# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+    /* Remember at what time we started, so that we know how much longer we
+     * should wait after being interrupted. */
+#  define USE_START_TV
+    struct timeval  start_tv;
+
+    if (msec > 0 && (
+#  ifdef FEAT_XCLIPBOARD
+	    xterm_Shell != (Widget)0
+#   ifdef USE_XSMP
+	    ||
+#   endif
+#  endif
+#  ifdef USE_XSMP
+	    xsmp_icefd != -1
+#  endif
+	    ))
+	gettimeofday(&start_tv, NULL);
+# endif
+
+    /* Handle being called recursively.  This may happen for the session
+     * manager stuff, it may save the file, which does a breakcheck. */
+    if (busy)
+	return 0;
+#endif
+
+#ifdef MAY_LOOP
+    while (1)
+#endif
+    {
+#ifdef MAY_LOOP
+	int		finished = TRUE; /* default is to 'loop' just once */
+#endif
+#ifndef HAVE_SELECT
+	struct pollfd   fds[5];
+	int		nfd;
+# ifdef FEAT_XCLIPBOARD
+	int		xterm_idx = -1;
+# endif
+# ifdef FEAT_MOUSE_GPM
+	int		gpm_idx = -1;
+# endif
+# ifdef USE_XSMP
+	int		xsmp_idx = -1;
+# endif
+
+	fds[0].fd = fd;
+	fds[0].events = POLLIN;
+	nfd = 1;
+
+# ifdef FEAT_SNIFF
+#  define SNIFF_IDX 1
+	if (want_sniff_request)
+	{
+	    fds[SNIFF_IDX].fd = fd_from_sniff;
+	    fds[SNIFF_IDX].events = POLLIN;
+	    nfd++;
+	}
+# endif
+# ifdef FEAT_XCLIPBOARD
+	if (xterm_Shell != (Widget)0)
+	{
+	    xterm_idx = nfd;
+	    fds[nfd].fd = ConnectionNumber(xterm_dpy);
+	    fds[nfd].events = POLLIN;
+	    nfd++;
+	}
+# endif
+# ifdef FEAT_MOUSE_GPM
+	if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
+	{
+	    gpm_idx = nfd;
+	    fds[nfd].fd = gpm_fd;
+	    fds[nfd].events = POLLIN;
+	    nfd++;
+	}
+# endif
+# ifdef USE_XSMP
+	if (xsmp_icefd != -1)
+	{
+	    xsmp_idx = nfd;
+	    fds[nfd].fd = xsmp_icefd;
+	    fds[nfd].events = POLLIN;
+	    nfd++;
+	}
+# endif
+
+	ret = poll(fds, nfd, (int)msec);
+
+# ifdef FEAT_SNIFF
+	if (ret < 0)
+	    sniff_disconnect(1);
+	else if (want_sniff_request)
+	{
+	    if (fds[SNIFF_IDX].revents & POLLHUP)
+		sniff_disconnect(1);
+	    if (fds[SNIFF_IDX].revents & POLLIN)
+		sniff_request_waiting = 1;
+	}
+# endif
+# ifdef FEAT_XCLIPBOARD
+	if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
+	{
+	    xterm_update();      /* Maybe we should hand out clipboard */
+	    if (--ret == 0 && !input_available())
+		/* Try again */
+		finished = FALSE;
+	}
+# endif
+# ifdef FEAT_MOUSE_GPM
+	if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
+	{
+	    *check_for_gpm = 1;
+	}
+# endif
+# ifdef USE_XSMP
+	if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
+	{
+	    if (fds[xsmp_idx].revents & POLLIN)
+	    {
+		busy = TRUE;
+		xsmp_handle_requests();
+		busy = FALSE;
+	    }
+	    else if (fds[xsmp_idx].revents & POLLHUP)
+	    {
+		if (p_verbose > 0)
+		    MSG(_("XSMP lost ICE connection"));
+		xsmp_close();
+	    }
+	    if (--ret == 0)
+		/* Try again */
+		finished = FALSE;
+	}
+# endif
+
+
+#else /* HAVE_SELECT */
+
+	struct timeval  tv;
+	fd_set		rfds, efds;
+	int		maxfd;
+
+# ifdef __EMX__
+	/* don't check for incoming chars if not in raw mode, because select()
+	 * always returns TRUE then (in some version of emx.dll) */
+	if (curr_tmode != TMODE_RAW)
+	    return 0;
+# endif
+
+	if (msec >= 0)
+	{
+	    tv.tv_sec = msec / 1000;
+	    tv.tv_usec = (msec % 1000) * (1000000/1000);
+	}
+
+	/*
+	 * Select on ready for reading and exceptional condition (end of file).
+	 */
+	FD_ZERO(&rfds); /* calls bzero() on a sun */
+	FD_ZERO(&efds);
+	FD_SET(fd, &rfds);
+# if !defined(__QNX__) && !defined(__CYGWIN32__)
+	/* For QNX select() always returns 1 if this is set.  Why? */
+	FD_SET(fd, &efds);
+# endif
+	maxfd = fd;
+
+# ifdef FEAT_SNIFF
+	if (want_sniff_request)
+	{
+	    FD_SET(fd_from_sniff, &rfds);
+	    FD_SET(fd_from_sniff, &efds);
+	    if (maxfd < fd_from_sniff)
+		maxfd = fd_from_sniff;
+	}
+# endif
+# ifdef FEAT_XCLIPBOARD
+	if (xterm_Shell != (Widget)0)
+	{
+	    FD_SET(ConnectionNumber(xterm_dpy), &rfds);
+	    if (maxfd < ConnectionNumber(xterm_dpy))
+		maxfd = ConnectionNumber(xterm_dpy);
+	}
+# endif
+# ifdef FEAT_MOUSE_GPM
+	if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
+	{
+	    FD_SET(gpm_fd, &rfds);
+	    FD_SET(gpm_fd, &efds);
+	    if (maxfd < gpm_fd)
+		maxfd = gpm_fd;
+	}
+# endif
+# ifdef USE_XSMP
+	if (xsmp_icefd != -1)
+	{
+	    FD_SET(xsmp_icefd, &rfds);
+	    FD_SET(xsmp_icefd, &efds);
+	    if (maxfd < xsmp_icefd)
+		maxfd = xsmp_icefd;
+	}
+# endif
+
+# ifdef OLD_VMS
+	/* Old VMS as v6.2 and older have broken select(). It waits more than
+	 * required. Should not be used */
+	ret = 0;
+# else
+	ret = select(maxfd + 1, &rfds, NULL, &efds, (msec >= 0) ? &tv : NULL);
+# endif
+
+# ifdef FEAT_SNIFF
+	if (ret < 0 )
+	    sniff_disconnect(1);
+	else if (ret > 0 && want_sniff_request)
+	{
+	    if (FD_ISSET(fd_from_sniff, &efds))
+		sniff_disconnect(1);
+	    if (FD_ISSET(fd_from_sniff, &rfds))
+		sniff_request_waiting = 1;
+	}
+# endif
+# ifdef FEAT_XCLIPBOARD
+	if (ret > 0 && xterm_Shell != (Widget)0
+		&& FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
+	{
+	    xterm_update();	      /* Maybe we should hand out clipboard */
+	    /* continue looping when we only got the X event and the input
+	     * buffer is empty */
+	    if (--ret == 0 && !input_available())
+	    {
+		/* Try again */
+		finished = FALSE;
+	    }
+	}
+# endif
+# ifdef FEAT_MOUSE_GPM
+	if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
+	{
+	    if (FD_ISSET(gpm_fd, &efds))
+		gpm_close();
+	    else if (FD_ISSET(gpm_fd, &rfds))
+		*check_for_gpm = 1;
+	}
+# endif
+# ifdef USE_XSMP
+	if (ret > 0 && xsmp_icefd != -1)
+	{
+	    if (FD_ISSET(xsmp_icefd, &efds))
+	    {
+		if (p_verbose > 0)
+		    MSG(_("XSMP lost ICE connection"));
+		xsmp_close();
+		if (--ret == 0)
+		    finished = FALSE;   /* keep going if event was only one */
+	    }
+	    else if (FD_ISSET(xsmp_icefd, &rfds))
+	    {
+		busy = TRUE;
+		xsmp_handle_requests();
+		busy = FALSE;
+		if (--ret == 0)
+		    finished = FALSE;   /* keep going if event was only one */
+	    }
+	}
+# endif
+
+#endif /* HAVE_SELECT */
+
+#ifdef MAY_LOOP
+	if (finished || msec == 0)
+	    break;
+
+	/* We're going to loop around again, find out for how long */
+	if (msec > 0)
+	{
+# ifdef USE_START_TV
+	    struct timeval  mtv;
+
+	    /* Compute remaining wait time. */
+	    gettimeofday(&mtv, NULL);
+	    msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
+				   + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
+# else
+	    /* Guess we got interrupted halfway. */
+	    msec = msec / 2;
+# endif
+	    if (msec <= 0)
+		break;	/* waited long enough */
+	}
+#endif
+    }
+
+    return (ret > 0);
+}
+
+#ifndef VMS
+
+#ifndef NO_EXPANDPATH
+    static int
+pstrcmp(a, b)
+    const void *a, *b;
+{
+    return (pathcmp(*(char **)a, *(char **)b));
+}
+
+/*
+ * Recursively expand one path component into all matching files and/or
+ * directories.
+ * "path" has backslashes before chars that are not to be expanded, starting
+ * at "path + wildoff".
+ * Return the number of matches found.
+ */
+    int
+mch_expandpath(gap, path, flags)
+    garray_T	*gap;
+    char_u	*path;
+    int		flags;		/* EW_* flags */
+{
+    return unix_expandpath(gap, path, 0, flags);
+}
+
+    static int
+unix_expandpath(gap, path, wildoff, flags)
+    garray_T	*gap;
+    char_u	*path;
+    int		wildoff;
+    int		flags;		/* EW_* flags */
+{
+    char_u	*buf;
+    char_u	*path_end;
+    char_u	*p, *s, *e;
+    int		start_len, c;
+    char_u	*pat;
+    DIR		*dirp;
+    regmatch_T	regmatch;
+    struct dirent *dp;
+    int		starts_with_dot;
+    int		matches;
+    int		len;
+
+    start_len = gap->ga_len;
+    buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
+    if (buf == NULL)
+	return 0;
+
+/*
+ * Find the first part in the path name that contains a wildcard.
+ * Copy it into buf, including the preceding characters.
+ */
+    p = buf;
+    s = buf;
+    e = NULL;
+    path_end = path;
+    while (*path_end != NUL)
+    {
+	/* May ignore a wildcard that has a backslash before it; it will
+	 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
+	if (path_end >= path + wildoff && rem_backslash(path_end))
+	    *p++ = *path_end++;
+	else if (*path_end == '/')
+	{
+	    if (e != NULL)
+		break;
+	    s = p + 1;
+	}
+	else if (path_end >= path + wildoff
+			 && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
+	    e = p;
+#ifdef FEAT_MBYTE
+	if (has_mbyte)
+	{
+	    len = (*mb_ptr2len_check)(path_end);
+	    STRNCPY(p, path_end, len);
+	    p += len;
+	    path_end += len;
+	}
+	else
+#endif
+	    *p++ = *path_end++;
+    }
+    e = p;
+    *e = NUL;
+
+    /* now we have one wildcard component between s and e */
+    /* Remove backslashes between "wildoff" and the start of the wildcard
+     * component. */
+    for (p = buf + wildoff; p < s; ++p)
+	if (rem_backslash(p))
+	{
+	    STRCPY(p, p + 1);
+	    --e;
+	    --s;
+	}
+
+    /* convert the file pattern to a regexp pattern */
+    starts_with_dot = (*s == '.');
+    pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+    if (pat == NULL)
+    {
+	vim_free(buf);
+	return 0;
+    }
+
+    /* compile the regexp into a program */
+#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
+    regmatch.rm_ic = TRUE;		/* Behave like Terminal.app */
+#else
+    regmatch.rm_ic = FALSE;		/* Don't ever ignore case */
+#endif
+    regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+    vim_free(pat);
+
+    if (regmatch.regprog == NULL)
+    {
+	vim_free(buf);
+	return 0;
+    }
+
+    /* open the directory for scanning */
+    c = *s;
+    *s = NUL;
+    dirp = opendir(*buf == NUL ? "." : (char *)buf);
+    *s = c;
+
+    /* Find all matching entries */
+    if (dirp != NULL)
+    {
+	for (;;)
+	{
+	    dp = readdir(dirp);
+	    if (dp == NULL)
+		break;
+	    if ((dp->d_name[0] != '.' || starts_with_dot)
+		    && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
+	    {
+		STRCPY(s, dp->d_name);
+		len = STRLEN(buf);
+		STRCPY(buf + len, path_end);
+		if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
+		{
+		    /* need to expand another component of the path */
+		    /* remove backslashes for the remaining components only */
+		    (void)unix_expandpath(gap, buf, len + 1, flags);
+		}
+		else
+		{
+		    /* no more wildcards, check if there is a match */
+		    /* remove backslashes for the remaining components only */
+		    if (*path_end != NUL)
+			backslash_halve(buf + len + 1);
+		    if (mch_getperm(buf) >= 0)	/* add existing file */
+			addfile(gap, buf, flags);
+		}
+	    }
+	}
+
+	closedir(dirp);
+    }
+
+    vim_free(buf);
+    vim_free(regmatch.regprog);
+
+    matches = gap->ga_len - start_len;
+    if (matches > 0)
+	qsort(((char_u **)gap->ga_data) + start_len, matches,
+						   sizeof(char_u *), pstrcmp);
+    return matches;
+}
+#endif
+
+/*
+ * mch_expand_wildcards() - this code does wild-card pattern matching using
+ * the shell
+ *
+ * return OK for success, FAIL for error (you may lose some memory) and put
+ * an error message in *file.
+ *
+ * num_pat is number of input patterns
+ * pat is array of pointers to input patterns
+ * num_file is pointer to number of matched file names
+ * file is pointer to array of pointers to matched file names
+ */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+/* ARGSUSED */
+    int
+mch_expand_wildcards(num_pat, pat, num_file, file, flags)
+    int		   num_pat;
+    char_u	 **pat;
+    int		  *num_file;
+    char_u	***file;
+    int		   flags;	/* EW_* flags */
+{
+    int		i;
+    size_t	len;
+    char_u	*p;
+    int		dir;
+#ifdef __EMX__
+# define EXPL_ALLOC_INC	16
+    char_u	**expl_files;
+    size_t	files_alloced, files_free;
+    char_u	*buf;
+    int		has_wildcard;
+
+    *num_file = 0;	/* default: no files found */
+    files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
+    files_free = EXPL_ALLOC_INC;    /* how much space is not used  */
+    *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
+    if (*file == NULL)
+	return FAIL;
+
+    for (; num_pat > 0; num_pat--, pat++)
+    {
+	expl_files = NULL;
+	if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
+	    /* expand environment var or home dir */
+	    buf = expand_env_save(*pat);
+	else
+	    buf = vim_strsave(*pat);
+	expl_files = NULL;
+	has_wildcard = mch_has_exp_wildcard(buf);  /* (still) wildcards in there? */
+	if (has_wildcard)   /* yes, so expand them */
+	    expl_files = (char_u **)_fnexplode(buf);
+
+	/*
+	 * return value of buf if no wildcards left,
+	 * OR if no match AND EW_NOTFOUND is set.
+	 */
+	if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
+		|| (expl_files == NULL && (flags & EW_NOTFOUND)))
+	{   /* simply save the current contents of *buf */
+	    expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
+	    if (expl_files != NULL)
+	    {
+		expl_files[0] = vim_strsave(buf);
+		expl_files[1] = NULL;
+	    }
+	}
+	vim_free(buf);
+
+	/*
+	 * Count number of names resulting from expansion,
+	 * At the same time add a backslash to the end of names that happen to
+	 * be directories, and replace slashes with backslashes.
+	 */
+	if (expl_files)
+	{
+	    for (i = 0; (p = expl_files[i]) != NULL; i++)
+	    {
+		dir = mch_isdir(p);
+		/* If we don't want dirs and this is one, skip it */
+		if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
+		    continue;
+
+		if (--files_free == 0)
+		{
+		    /* need more room in table of pointers */
+		    files_alloced += EXPL_ALLOC_INC;
+		    *file = (char_u **)vim_realloc(*file,
+					   sizeof(char_u **) * files_alloced);
+		    if (*file == NULL)
+		    {
+			EMSG(_(e_outofmem));
+			*num_file = 0;
+			return FAIL;
+		    }
+		    files_free = EXPL_ALLOC_INC;
+		}
+		slash_adjust(p);
+		if (dir)
+		{
+		    /* For a directory we add a '/', unless it's already
+		     * there. */
+		    len = STRLEN(p);
+		    if (((*file)[*num_file] = alloc(len + 2)) != NULL)
+		    {
+			STRCPY((*file)[*num_file], p);
+			if (!vim_ispathsep((*file)[*num_file][len - 1]))
+			{
+			    (*file)[*num_file][len] = psepc;
+			    (*file)[*num_file][len + 1] = 0;
+			}
+		    }
+		}
+		else
+		{
+		    (*file)[*num_file] = vim_strsave(p);
+		}
+
+		/*
+		 * Error message already given by either alloc or vim_strsave.
+		 * Should return FAIL, but returning OK works also.
+		 */
+		if ((*file)[*num_file] == NULL)
+		    break;
+		(*num_file)++;
+	    }
+	    _fnexplodefree((char **)expl_files);
+	}
+    }
+    return OK;
+
+#else /* __EMX__ */
+
+    int		j;
+    char_u	*tempname;
+    char_u	*command;
+    FILE	*fd;
+    char_u	*buffer;
+#define STYLE_ECHO  0	    /* use "echo" to expand */
+#define STYLE_GLOB  1	    /* use "glob" to expand, for csh */
+#define STYLE_PRINT 2	    /* use "print -N" to expand, for zsh */
+#define STYLE_BT    3	    /* `cmd` expansion, execute the pattern directly */
+    int		shell_style = STYLE_ECHO;
+    int		check_spaces;
+    static int	did_find_nul = FALSE;
+    int		ampersent = FALSE;
+
+    *num_file = 0;	/* default: no files found */
+    *file = NULL;
+
+    /*
+     * If there are no wildcards, just copy the names to allocated memory.
+     * Saves a lot of time, because we don't have to start a new shell.
+     */
+    if (!have_wildcard(num_pat, pat))
+	return save_patterns(num_pat, pat, num_file, file);
+
+    /*
+     * Don't allow the use of backticks in secure and restricted mode.
+     */
+    if (secure || restricted)
+	for (i = 0; i < num_pat; ++i)
+	    if (vim_strchr(pat[i], '`') != NULL
+		    && (check_restricted() || check_secure()))
+		return FAIL;
+
+    /*
+     * get a name for the temp file
+     */
+    if ((tempname = vim_tempname('o')) == NULL)
+    {
+	EMSG(_(e_notmp));
+	return FAIL;
+    }
+
+    /*
+     * Let the shell expand the patterns and write the result into the temp
+     * file.  if expanding `cmd` execute it directly.
+     * If we use csh, glob will work better than echo.
+     * If we use zsh, print -N will work better than glob.
+     */
+    if (num_pat == 1 && *pat[0] == '`'
+	    && (len = STRLEN(pat[0])) > 2
+	    && *(pat[0] + len - 1) == '`')
+	shell_style = STYLE_BT;
+    else if ((len = STRLEN(p_sh)) >= 3)
+    {
+	if (STRCMP(p_sh + len - 3, "csh") == 0)
+	    shell_style = STYLE_GLOB;
+	else if (STRCMP(p_sh + len - 3, "zsh") == 0)
+	    shell_style = STYLE_PRINT;
+    }
+
+    /* "unset nonomatch; print -N >" plus two is 29 */
+    len = STRLEN(tempname) + 29;
+    for (i = 0; i < num_pat; ++i)	/* count the length of the patterns */
+	len += STRLEN(pat[i]) + 3;	/* add space and two quotes */
+    command = alloc(len);
+    if (command == NULL)
+    {
+	/* out of memory */
+	vim_free(tempname);
+	return FAIL;
+    }
+
+    /*
+     * Build the shell command:
+     * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
+     *	 recognizes this).
+     * - Add the shell command to print the expanded names.
+     * - Add the temp file name.
+     * - Add the file name patterns.
+     */
+    if (shell_style == STYLE_BT)
+    {
+	STRCPY(command, pat[0] + 1);		/* exclude first backtick */
+	p = command + STRLEN(command) - 1;
+	*p = ' ';				/* remove last backtick */
+	while (p > command && vim_iswhite(*p))
+	    --p;
+	if (*p == '&')				/* remove trailing '&' */
+	{
+	    ampersent = TRUE;
+	    *p = ' ';
+	}
+	STRCAT(command, ">");
+    }
+    else
+    {
+	if (flags & EW_NOTFOUND)
+	    STRCPY(command, "set nonomatch; ");
+	else
+	    STRCPY(command, "unset nonomatch; ");
+	if (shell_style == STYLE_GLOB)
+	    STRCAT(command, "glob >");
+	else if (shell_style == STYLE_PRINT)
+	    STRCAT(command, "print -N >");
+	else
+	    STRCAT(command, "echo >");
+    }
+    STRCAT(command, tempname);
+    if (shell_style != STYLE_BT)
+	for (i = 0; i < num_pat; ++i)
+	{
+	    /* When using system() always add extra quotes, because the shell
+	     * is started twice.  Otherwise only put quotes around spaces and
+	     * single quotes. */
+#ifdef USE_SYSTEM
+	    STRCAT(command, " \"");
+	    STRCAT(command, pat[i]);
+	    STRCAT(command, "\"");
+#else
+	    p = command + STRLEN(command);
+	    *p++ = ' ';
+	    for (j = 0; pat[i][j] != NUL; )
+		if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
+		{
+		    *p++ = '"';
+		    while (pat[i][j] != NUL
+			    && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
+			*p++ = pat[i][j++];
+		    *p++ = '"';
+		}
+		else
+		    *p++ = pat[i][j++];
+	    *p = NUL;
+#endif
+	}
+    if (flags & EW_SILENT)
+	show_shell_mess = FALSE;
+    if (ampersent)
+	STRCAT(command, "&");		/* put the '&' back after the
+					   redirection */
+
+    /*
+     * Using zsh -G: If a pattern has no matches, it is just deleted from
+     * the argument list, otherwise zsh gives an error message and doesn't
+     * expand any other pattern.
+     */
+    if (shell_style == STYLE_PRINT)
+	extra_shell_arg = (char_u *)"-G";   /* Use zsh NULL_GLOB option */
+
+    /*
+     * If we use -f then shell variables set in .cshrc won't get expanded.
+     * vi can do it, so we will too, but it is only necessary if there is a "$"
+     * in one of the patterns, otherwise we can still use the fast option.
+     */
+    else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
+	extra_shell_arg = (char_u *)"-f";	/* Use csh fast option */
+
+    /*
+     * execute the shell command
+     */
+    i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
+
+    /* When running in the background, give it some time to create the temp
+     * file, but don't wait for it to finish. */
+    if (ampersent)
+	mch_delay(10L, TRUE);
+
+    extra_shell_arg = NULL;		/* cleanup */
+    show_shell_mess = TRUE;
+    vim_free(command);
+
+    if (i)				/* mch_call_shell() failed */
+    {
+	mch_remove(tempname);
+	vim_free(tempname);
+	/*
+	 * With interactive completion, the error message is not printed.
+	 * However with USE_SYSTEM, I don't know how to turn off error messages
+	 * from the shell, so screen may still get messed up -- webb.
+	 */
+#ifndef USE_SYSTEM
+	if (!(flags & EW_SILENT))
+#endif
+	{
+	    redraw_later_clear();	/* probably messed up screen */
+	    msg_putchar('\n');		/* clear bottom line quickly */
+	    cmdline_row = Rows - 1;	/* continue on last line */
+#ifdef USE_SYSTEM
+	    if (!(flags & EW_SILENT))
+#endif
+	    {
+		MSG(_(e_wildexpand));
+		msg_start();		/* don't overwrite this message */
+	    }
+	}
+	/* If a `cmd` expansion failed, don't list `cmd` as a match, even when
+	 * EW_NOTFOUND is given */
+	if (shell_style == STYLE_BT)
+	    return FAIL;
+	goto notfound;
+    }
+
+    /*
+     * read the names from the file into memory
+     */
+    fd = fopen((char *)tempname, READBIN);
+    if (fd == NULL)
+    {
+	/* Something went wrong, perhaps a file name with a special char. */
+	if (!(flags & EW_SILENT))
+	{
+	    MSG(_(e_wildexpand));
+	    msg_start();		/* don't overwrite this message */
+	}
+	vim_free(tempname);
+	goto notfound;
+    }
+    fseek(fd, 0L, SEEK_END);
+    len = ftell(fd);			/* get size of temp file */
+    fseek(fd, 0L, SEEK_SET);
+    buffer = alloc(len + 1);
+    if (buffer == NULL)
+    {
+	/* out of memory */
+	mch_remove(tempname);
+	vim_free(tempname);
+	fclose(fd);
+	return FAIL;
+    }
+    i = fread((char *)buffer, 1, len, fd);
+    fclose(fd);
+    mch_remove(tempname);
+    if (i != len)
+    {
+	/* unexpected read error */
+	EMSG2(_(e_notread), tempname);
+	vim_free(tempname);
+	vim_free(buffer);
+	return FAIL;
+    }
+    vim_free(tempname);
+
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+    /* Translate <CR><NL> into <NL>.  Caution, buffer may contain NUL. */
+    p = buffer;
+    for (i = 0; i < len; ++i)
+	if (!(buffer[i] == CAR && buffer[i + 1] == NL))
+	    *p++ = buffer[i];
+    len = p - buffer;
+# endif
+
+
+    /* file names are separated with Space */
+    if (shell_style == STYLE_ECHO)
+    {
+	buffer[len] = '\n';		/* make sure the buffer ends in NL */
+	p = buffer;
+	for (i = 0; *p != '\n'; ++i)	/* count number of entries */
+	{
+	    while (*p != ' ' && *p != '\n')
+		++p;
+	    p = skipwhite(p);		/* skip to next entry */
+	}
+    }
+    /* file names are separated with NL */
+    else if (shell_style == STYLE_BT)
+    {
+	buffer[len] = NUL;		/* make sure the buffer ends in NUL */
+	p = buffer;
+	for (i = 0; *p != NUL; ++i)	/* count number of entries */
+	{
+	    while (*p != '\n' && *p != NUL)
+		++p;
+	    if (*p != NUL)
+		++p;
+	    p = skipwhite(p);		/* skip leading white space */
+	}
+    }
+    /* file names are separated with NUL */
+    else
+    {
+	/*
+	 * Some versions of zsh use spaces instead of NULs to separate
+	 * results.  Only do this when there is no NUL before the end of the
+	 * buffer, otherwise we would never be able to use file names with
+	 * embedded spaces when zsh does use NULs.
+	 * When we found a NUL once, we know zsh is OK, set did_find_nul and
+	 * don't check for spaces again.
+	 */
+	check_spaces = FALSE;
+	if (shell_style == STYLE_PRINT && !did_find_nul)
+	{
+	    /* If there is a NUL, set did_find_nul, else set check_spaces */
+	    if (len && (int)STRLEN(buffer) < len - 1)
+		did_find_nul = TRUE;
+	    else
+		check_spaces = TRUE;
+	}
+
+	/*
+	 * Make sure the buffer ends with a NUL.  For STYLE_PRINT there
+	 * already is one, for STYLE_GLOB it needs to be added.
+	 */
+	if (len && buffer[len - 1] == NUL)
+	    --len;
+	else
+	    buffer[len] = NUL;
+	i = 0;
+	for (p = buffer; p < buffer + len; ++p)
+	    if (*p == NUL || (*p == ' ' && check_spaces))   /* count entry */
+	    {
+		++i;
+		*p = NUL;
+	    }
+	if (len)
+	    ++i;			/* count last entry */
+    }
+    if (i == 0)
+    {
+	/*
+	 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
+	 * /bin/sh will happily expand it to nothing rather than returning an
+	 * error; and hey, it's good to check anyway -- webb.
+	 */
+	vim_free(buffer);
+	goto notfound;
+    }
+    *num_file = i;
+    *file = (char_u **)alloc(sizeof(char_u *) * i);
+    if (*file == NULL)
+    {
+	/* out of memory */
+	vim_free(buffer);
+	return FAIL;
+    }
+
+    /*
+     * Isolate the individual file names.
+     */
+    p = buffer;
+    for (i = 0; i < *num_file; ++i)
+    {
+	(*file)[i] = p;
+	/* Space or NL separates */
+	if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
+	{
+	    while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
+		++p;
+	    if (p == buffer + len)		/* last entry */
+		*p = NUL;
+	    else
+	    {
+		*p++ = NUL;
+		p = skipwhite(p);		/* skip to next entry */
+	    }
+	}
+	else		/* NUL separates */
+	{
+	    while (*p && p < buffer + len)	/* skip entry */
+		++p;
+	    ++p;				/* skip NUL */
+	}
+    }
+
+    /*
+     * Move the file names to allocated memory.
+     */
+    for (j = 0, i = 0; i < *num_file; ++i)
+    {
+	/* Require the files to exist.	Helps when using /bin/sh */
+	if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
+	    continue;
+
+	/* check if this entry should be included */
+	dir = (mch_isdir((*file)[i]));
+	if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
+	    continue;
+
+	p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
+	if (p)
+	{
+	    STRCPY(p, (*file)[i]);
+	    if (dir)
+		STRCAT(p, "/");	    /* add '/' to a directory name */
+	    (*file)[j++] = p;
+	}
+    }
+    vim_free(buffer);
+    *num_file = j;
+
+    if (*num_file == 0)	    /* rejected all entries */
+    {
+	vim_free(*file);
+	*file = NULL;
+	goto notfound;
+    }
+
+    return OK;
+
+notfound:
+    if (flags & EW_NOTFOUND)
+	return save_patterns(num_pat, pat, num_file, file);
+    return FAIL;
+
+#endif /* __EMX__ */
+}
+
+#endif /* VMS */
+
+#ifndef __EMX__
+    static int
+save_patterns(num_pat, pat, num_file, file)
+    int		num_pat;
+    char_u	**pat;
+    int		*num_file;
+    char_u	***file;
+{
+    int		i;
+
+    *file = (char_u **)alloc(num_pat * sizeof(char_u *));
+    if (*file == NULL)
+	return FAIL;
+    for (i = 0; i < num_pat; i++)
+	(*file)[i] = vim_strsave(pat[i]);
+    *num_file = num_pat;
+    return OK;
+}
+#endif
+
+
+/*
+ * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
+ * expand.
+ */
+    int
+mch_has_exp_wildcard(p)
+    char_u  *p;
+{
+    for ( ; *p; ++p)
+    {
+#ifndef OS2
+	if (*p == '\\' && p[1] != NUL)
+	    ++p;
+	else
+#endif
+	    if (vim_strchr((char_u *)
+#ifdef VMS
+				    "*?%"
+#else
+# ifdef OS2
+				    "*?"
+# else
+				    "*?[{'"
+# endif
+#endif
+						, *p) != NULL)
+	    return TRUE;
+#ifdef FEAT_MBYTE
+	if (has_mbyte)
+	    p += (*mb_ptr2len_check)(p) - 1;
+#endif
+    }
+    return FALSE;
+}
+
+/*
+ * Return TRUE if the string "p" contains a wildcard.
+ * Don't recognize '~' at the end as a wildcard.
+ */
+    int
+mch_has_wildcard(p)
+    char_u  *p;
+{
+    for ( ; *p; ++p)
+    {
+#ifndef OS2
+	if (*p == '\\' && p[1] != NUL)
+	    ++p;
+	else
+#endif
+	    if (vim_strchr((char_u *)
+#ifdef VMS
+				    "*?%$"
+#else
+# ifdef OS2
+#  ifdef VIM_BACKTICK
+				    "*?$`"
+#  else
+				    "*?$"
+#  endif
+# else
+				    "*?[{`'$"
+# endif
+#endif
+						, *p) != NULL
+		|| (*p == '~' && p[1] != NUL))
+	    return TRUE;
+#ifdef FEAT_MBYTE
+	if (has_mbyte)
+	    p += (*mb_ptr2len_check)(p) - 1;
+#endif
+    }
+    return FALSE;
+}
+
+#ifndef __EMX__
+    static int
+have_wildcard(num, file)
+    int	    num;
+    char_u  **file;
+{
+    int	    i;
+
+    for (i = 0; i < num; i++)
+	if (mch_has_wildcard(file[i]))
+	    return 1;
+    return 0;
+}
+
+    static int
+have_dollars(num, file)
+    int	    num;
+    char_u  **file;
+{
+    int	    i;
+
+    for (i = 0; i < num; i++)
+	if (vim_strchr(file[i], '$') != NULL)
+	    return TRUE;
+    return FALSE;
+}
+#endif	/* ifndef __EMX__ */
+
+#ifndef HAVE_RENAME
+/*
+ * Scaled-down version of rename(), which is missing in Xenix.
+ * This version can only move regular files and will fail if the
+ * destination exists.
+ */
+    int
+mch_rename(src, dest)
+    const char *src, *dest;
+{
+    struct stat	    st;
+
+    if (stat(dest, &st) >= 0)	    /* fail if destination exists */
+	return -1;
+    if (link(src, dest) != 0)	    /* link file to new name */
+	return -1;
+    if (mch_remove(src) == 0)	    /* delete link to old name */
+	return 0;
+    return -1;
+}
+#endif /* !HAVE_RENAME */
+
+#ifdef FEAT_MOUSE_GPM
+/*
+ * Initializes connection with gpm (if it isn't already opened)
+ * Return 1 if succeeded (or connection already opened), 0 if failed
+ */
+    static int
+gpm_open()
+{
+    static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
+
+    if (!gpm_flag)
+    {
+	gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
+	gpm_connect.defaultMask = ~GPM_HARD;
+	/* Default handling for mouse move*/
+	gpm_connect.minMod = 0; /* Handle any modifier keys */
+	gpm_connect.maxMod = 0xffff;
+	if (Gpm_Open(&gpm_connect, 0) > 0)
+	{
+	    /* gpm library tries to handling TSTP causes
+	     * problems. Anyways, we close connection to Gpm whenever
+	     * we are going to suspend or starting an external process
+	     * so we should'nt  have problem with this
+	     */
+	    signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+	    return 1; /* succeed */
+	}
+	if (gpm_fd == -2)
+	    Gpm_Close(); /* We don't want to talk to xterm via gpm */
+	return 0;
+    }
+    return 1; /* already open */
+}
+
+/*
+ * Closes connection to gpm
+ * returns non-zero if connection succesfully closed
+ */
+    static void
+gpm_close()
+{
+    if (gpm_flag && gpm_fd >= 0) /* if Open */
+	Gpm_Close();
+}
+
+/* Reads gpm event and adds special keys to input buf. Returns length of
+ * generated key sequence.
+ * This function is made after gui_send_mouse_event
+ */
+    static int
+mch_gpm_process()
+{
+    int			button;
+    static Gpm_Event	gpm_event;
+    char_u		string[6];
+    int_u		vim_modifiers;
+    int			row,col;
+    unsigned char	buttons_mask;
+    unsigned char	gpm_modifiers;
+    static unsigned char old_buttons = 0;
+
+    Gpm_GetEvent(&gpm_event);
+
+#ifdef FEAT_GUI
+    /* Don't put events in the input queue now. */
+    if (hold_gui_events)
+	return 0;
+#endif
+
+    row = gpm_event.y - 1;
+    col = gpm_event.x - 1;
+
+    string[0] = ESC; /* Our termcode */
+    string[1] = 'M';
+    string[2] = 'G';
+    switch (GPM_BARE_EVENTS(gpm_event.type))
+    {
+	case GPM_DRAG:
+	    string[3] = MOUSE_DRAG;
+	    break;
+	case GPM_DOWN:
+	    buttons_mask = gpm_event.buttons & ~old_buttons;
+	    old_buttons = gpm_event.buttons;
+	    switch (buttons_mask)
+	    {
+		case GPM_B_LEFT:
+		    button = MOUSE_LEFT;
+		    break;
+		case GPM_B_MIDDLE:
+		    button = MOUSE_MIDDLE;
+		    break;
+		case GPM_B_RIGHT:
+		    button = MOUSE_RIGHT;
+		    break;
+		default:
+		    return 0;
+		    /*Don't know what to do. Can more than one button be
+		     * reported in one event? */
+	    }
+	    string[3] = (char_u)(button | 0x20);
+	    SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
+	    break;
+	case GPM_UP:
+	    string[3] = MOUSE_RELEASE;
+	    old_buttons &= ~gpm_event.buttons;
+	    break;
+	default:
+	    return 0;
+    }
+    /*This code is based on gui_x11_mouse_cb in gui_x11.c */
+    gpm_modifiers = gpm_event.modifiers;
+    vim_modifiers = 0x0;
+    /* I ignore capslock stats. Aren't we all just hate capslock mixing with
+     * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
+     * K_CAPSSHIFT is defined 8, so it probably isn't even reported
+     */
+    if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
+	vim_modifiers |= MOUSE_SHIFT;
+
+    if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
+	vim_modifiers |= MOUSE_CTRL;
+    if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
+	vim_modifiers |= MOUSE_ALT;
+    string[3] |= vim_modifiers;
+    string[4] = (char_u)(col + ' ' + 1);
+    string[5] = (char_u)(row + ' ' + 1);
+    add_to_input_buf(string, 6);
+    return 6;
+}
+#endif /* FEAT_MOUSE_GPM */
+
+#if defined(FEAT_LIBCALL) || defined(PROTO)
+typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
+typedef char_u * (*INTPROCSTR)__ARGS((int));
+typedef int (*STRPROCINT)__ARGS((char_u *));
+typedef int (*INTPROCINT)__ARGS((int));
+
+/*
+ * Call a DLL routine which takes either a string or int param
+ * and returns an allocated string.
+ */
+    int
+mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
+    char_u	*libname;
+    char_u	*funcname;
+    char_u	*argstring;	/* NULL when using a argint */
+    int		argint;
+    char_u	**string_result;/* NULL when using number_result */
+    int		*number_result;
+{
+# if defined(USE_DLOPEN)
+    void	*hinstLib;
+# else
+    shl_t	hinstLib;
+# endif
+    STRPROCSTR	ProcAdd;
+    INTPROCSTR	ProcAddI;
+    char_u	*retval_str = NULL;
+    int		retval_int = 0;
+    int		success = FALSE;
+
+    /* Get a handle to the DLL module. */
+# if defined(USE_DLOPEN)
+    hinstLib = dlopen((char *)libname, RTLD_LAZY
+#  ifdef RTLD_LOCAL
+	    | RTLD_LOCAL
+#  endif
+	    );
+# else
+    hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
+# endif
+
+    /* If the handle is valid, try to get the function address. */
+    if (hinstLib != NULL)
+    {
+# ifdef HAVE_SETJMP_H
+	/*
+	 * Catch a crash when calling the library function.  For example when
+	 * using a number where a string pointer is expected.
+	 */
+	mch_startjmp();
+	if (SETJMP(lc_jump_env) != 0)
+	{
+	    success = FALSE;
+	    mch_didjmp();
+	}
+	else
+# endif
+	{
+	    retval_str = NULL;
+	    retval_int = 0;
+
+	    if (argstring != NULL)
+	    {
+# if defined(USE_DLOPEN)
+		ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
+# else
+		if (shl_findsym(&hinstLib, (const char *)funcname,
+					TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
+		    ProcAdd = NULL;
+# endif
+		if ((success = (ProcAdd != NULL)))
+		{
+		    if (string_result == NULL)
+			retval_int = ((STRPROCINT)ProcAdd)(argstring);
+		    else
+			retval_str = (ProcAdd)(argstring);
+		}
+	    }
+	    else
+	    {
+# if defined(USE_DLOPEN)
+		ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
+# else
+		if (shl_findsym(&hinstLib, (const char *)funcname,
+				       TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
+		    ProcAddI = NULL;
+# endif
+		if ((success = (ProcAddI != NULL)))
+		{
+		    if (string_result == NULL)
+			retval_int = ((INTPROCINT)ProcAddI)(argint);
+		    else
+			retval_str = (ProcAddI)(argint);
+		}
+	    }
+
+	    /* Save the string before we free the library. */
+	    /* Assume that a "1" or "-1" result is an illegal pointer. */
+	    if (string_result == NULL)
+		*number_result = retval_int;
+	    else if (retval_str != NULL
+		    && retval_str != (char_u *)1
+		    && retval_str != (char_u *)-1)
+		*string_result = vim_strsave(retval_str);
+	}
+
+# ifdef HAVE_SETJMP_H
+	mch_endjmp();
+#  ifdef SIGHASARG
+	if (lc_signal != 0)
+	{
+	    int i;
+
+	    /* try to find the name of this signal */
+	    for (i = 0; signal_info[i].sig != -1; i++)
+		if (lc_signal == signal_info[i].sig)
+		    break;
+	    EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
+	}
+#  endif
+# endif
+
+	/* Free the DLL module. */
+# if defined(USE_DLOPEN)
+	(void)dlclose(hinstLib);
+# else
+	(void)shl_unload(hinstLib);
+# endif
+    }
+
+    if (!success)
+    {
+	EMSG2(_(e_libcall), funcname);
+	return FAIL;
+    }
+
+    return OK;
+}
+#endif
+
+#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
+static int	xterm_trace = -1;	/* default: disabled */
+static int	xterm_button;
+
+/*
+ * Setup a dummy window for X selections in a terminal.
+ */
+    void
+setup_term_clip()
+{
+    int		z = 0;
+    char	*strp = "";
+    Widget	AppShell;
+
+    if (!x_connect_to_server())
+	return;
+
+    open_app_context();
+    if (app_context != NULL && xterm_Shell == (Widget)0)
+    {
+	int (*oldhandler)();
+#if defined(HAVE_SETJMP_H)
+	int (*oldIOhandler)();
+#endif
+# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+	struct timeval  start_tv;
+
+	if (p_verbose > 0)
+	    gettimeofday(&start_tv, NULL);
+# endif
+
+	/* Ignore X errors while opening the display */
+	oldhandler = XSetErrorHandler(x_error_check);
+
+#if defined(HAVE_SETJMP_H)
+	/* Ignore X IO errors while opening the display */
+	oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
+	mch_startjmp();
+	if (SETJMP(lc_jump_env) != 0)
+	{
+	    mch_didjmp();
+	    xterm_dpy = NULL;
+	}
+	else
+#endif
+	{
+	    xterm_dpy = XtOpenDisplay(app_context, xterm_display,
+		    "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
+#if defined(HAVE_SETJMP_H)
+	    mch_endjmp();
+#endif
+	}
+
+#if defined(HAVE_SETJMP_H)
+	/* Now handle X IO errors normally. */
+	(void)XSetIOErrorHandler(oldIOhandler);
+#endif
+	/* Now handle X errors normally. */
+	(void)XSetErrorHandler(oldhandler);
+
+	if (xterm_dpy == NULL)
+	{
+	    if (p_verbose > 0)
+		MSG(_("Opening the X display failed"));
+	    return;
+	}
+
+	/* Catch terminating error of the X server connection. */
+	(void)XSetIOErrorHandler(x_IOerror_handler);
+
+# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+	if (p_verbose > 0)
+	    xopen_message(&start_tv);
+# endif
+
+	/* Create a Shell to make converters work. */
+	AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
+		applicationShellWidgetClass, xterm_dpy,
+		NULL);
+	if (AppShell == (Widget)0)
+	    return;
+	xterm_Shell = XtVaCreatePopupShell("VIM",
+		topLevelShellWidgetClass, AppShell,
+		XtNmappedWhenManaged, 0,
+		XtNwidth, 1,
+		XtNheight, 1,
+		NULL);
+	if (xterm_Shell == (Widget)0)
+	    return;
+
+	x11_setup_atoms(xterm_dpy);
+	if (x11_display == NULL)
+	    x11_display = xterm_dpy;
+
+	XtRealizeWidget(xterm_Shell);
+	XSync(xterm_dpy, False);
+	xterm_update();
+    }
+    if (xterm_Shell != (Widget)0)
+    {
+	clip_init(TRUE);
+	if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
+	    x11_window = (Window)atol(strp);
+	/* Check if $WINDOWID is valid. */
+	if (test_x11_window(xterm_dpy) == FAIL)
+	    x11_window = 0;
+	if (x11_window != 0)
+	    xterm_trace = 0;
+    }
+}
+
+    void
+start_xterm_trace(button)
+    int button;
+{
+    if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
+	return;
+    xterm_trace = 1;
+    xterm_button = button;
+    do_xterm_trace();
+}
+
+
+    void
+stop_xterm_trace()
+{
+    if (xterm_trace < 0)
+	return;
+    xterm_trace = 0;
+}
+
+/*
+ * Query the xterm pointer and generate mouse termcodes if necessary
+ * return TRUE if dragging is active, else FALSE
+ */
+    static int
+do_xterm_trace()
+{
+    Window		root, child;
+    int			root_x, root_y;
+    int			win_x, win_y;
+    int			row, col;
+    int_u		mask_return;
+    char_u		buf[50];
+    char_u		*strp;
+    long		got_hints;
+    static char_u	*mouse_code;
+    static char_u	mouse_name[2] = {KS_MOUSE, KE_FILLER};
+    static int		prev_row = 0, prev_col = 0;
+    static XSizeHints	xterm_hints;
+
+    if (xterm_trace <= 0)
+	return FALSE;
+
+    if (xterm_trace == 1)
+    {
+	/* Get the hints just before tracking starts.  The font size might
+	 * have changed recently */
+	XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
+	if (!(got_hints & PResizeInc)
+		|| xterm_hints.width_inc <= 1
+		|| xterm_hints.height_inc <= 1)
+	{
+	    xterm_trace = -1;  /* Not enough data -- disable tracing */
+	    return FALSE;
+	}
+
+	/* Rely on the same mouse code for the duration of this */
+	mouse_code = find_termcode(mouse_name);
+	prev_row = mouse_row;
+	prev_row = mouse_col;
+	xterm_trace = 2;
+
+	/* Find the offset of the chars, there might be a scrollbar on the
+	 * left of the window and/or a menu on the top (eterm etc.) */
+	XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
+		      &win_x, &win_y, &mask_return);
+	xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
+			      - (xterm_hints.height_inc / 2);
+	if (xterm_hints.y <= xterm_hints.height_inc / 2)
+	    xterm_hints.y = 2;
+	xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
+			      - (xterm_hints.width_inc / 2);
+	if (xterm_hints.x <= xterm_hints.width_inc / 2)
+	    xterm_hints.x = 2;
+	return TRUE;
+    }
+    if (mouse_code == NULL)
+    {
+	xterm_trace = 0;
+	return FALSE;
+    }
+
+    XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
+		  &win_x, &win_y, &mask_return);
+
+    row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
+    col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
+    if (row == prev_row && col == prev_col)
+	return TRUE;
+
+    STRCPY(buf, mouse_code);
+    strp = buf + STRLEN(buf);
+    *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
+    *strp++ = (char_u)(col + ' ' + 1);
+    *strp++ = (char_u)(row + ' ' + 1);
+    *strp = 0;
+    add_to_input_buf(buf, STRLEN(buf));
+
+    prev_row = row;
+    prev_col = col;
+    return TRUE;
+}
+
+# if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Destroy the display, window and app_context.  Required for GTK.
+ */
+    void
+clear_xterm_clip()
+{
+    if (xterm_Shell != (Widget)0)
+    {
+	XtDestroyWidget(xterm_Shell);
+	xterm_Shell = (Widget)0;
+    }
+    if (xterm_dpy != NULL)
+    {
+#if 0
+	/* Lesstif and Solaris crash here, lose some memory */
+	XtCloseDisplay(xterm_dpy);
+#endif
+	if (x11_display == xterm_dpy)
+	    x11_display = NULL;
+	xterm_dpy = NULL;
+    }
+#if 0
+    if (app_context != (XtAppContext)NULL)
+    {
+	/* Lesstif and Solaris crash here, lose some memory */
+	XtDestroyApplicationContext(app_context);
+	app_context = (XtAppContext)NULL;
+    }
+#endif
+}
+# endif
+
+/*
+ * Catch up with any queued X events.  This may put keyboard input into the
+ * input buffer, call resize call-backs, trigger timers etc.  If there is
+ * nothing in the X event queue (& no timers pending), then we return
+ * immediately.
+ */
+    static void
+xterm_update()
+{
+    XEvent event;
+
+    while (XtAppPending(app_context) && !vim_is_input_buf_full())
+    {
+	XtAppNextEvent(app_context, &event);
+#ifdef FEAT_CLIENTSERVER
+	{
+	    XPropertyEvent *e = (XPropertyEvent *)&event;
+
+	    if (e->type == PropertyNotify && e->window == commWindow
+		   && e->atom == commProperty && e->state == PropertyNewValue)
+		serverEventProc(xterm_dpy, &event);
+	}
+#endif
+	XtDispatchEvent(&event);
+    }
+}
+
+    int
+clip_xterm_own_selection(cbd)
+    VimClipboard *cbd;
+{
+    if (xterm_Shell != (Widget)0)
+	return clip_x11_own_selection(xterm_Shell, cbd);
+    return FAIL;
+}
+
+    void
+clip_xterm_lose_selection(cbd)
+    VimClipboard *cbd;
+{
+    if (xterm_Shell != (Widget)0)
+	clip_x11_lose_selection(xterm_Shell, cbd);
+}
+
+    void
+clip_xterm_request_selection(cbd)
+    VimClipboard *cbd;
+{
+    if (xterm_Shell != (Widget)0)
+	clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
+}
+
+    void
+clip_xterm_set_selection(cbd)
+    VimClipboard *cbd;
+{
+    clip_x11_set_selection(cbd);
+}
+#endif
+
+
+#if defined(USE_XSMP) || defined(PROTO)
+/*
+ * Code for X Session Management Protocol.
+ */
+static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
+static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
+static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
+static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer	client_data));
+static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
+
+
+# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
+static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
+
+/*
+ * This is our chance to ask the user if they want to save,
+ * or abort the logout
+ */
+/*ARGSUSED*/
+    static void
+xsmp_handle_interaction(smc_conn, client_data)
+    SmcConn	smc_conn;
+    SmPointer	client_data;
+{
+    cmdmod_T	save_cmdmod;
+    int		cancel_shutdown = False;
+
+    save_cmdmod = cmdmod;
+    cmdmod.confirm = TRUE;
+    if (check_changed_any(FALSE))
+	/* Mustn't logout */
+	cancel_shutdown = True;
+    cmdmod = save_cmdmod;
+    setcursor();		/* position cursor */
+    out_flush();
+
+    /* Done interaction */
+    SmcInteractDone(smc_conn, cancel_shutdown);
+
+    /* Finish off
+     * Only end save-yourself here if we're not cancelling shutdown;
+     * we'll get a cancelled callback later in which we'll end it.
+     * Hopefully get around glitchy SMs (like GNOME-1)
+     */
+    if (!cancel_shutdown)
+    {
+	xsmp.save_yourself = False;
+	SmcSaveYourselfDone(smc_conn, True);
+    }
+}
+# endif
+
+/*
+ * Callback that starts save-yourself.
+ */
+/*ARGSUSED*/
+    static void
+xsmp_handle_save_yourself(smc_conn, client_data, save_type,
+					       shutdown, interact_style, fast)
+    SmcConn	smc_conn;
+    SmPointer	client_data;
+    int		save_type;
+    Bool	shutdown;
+    int		interact_style;
+    Bool	fast;
+{
+    /* Handle already being in saveyourself */
+    if (xsmp.save_yourself)
+	SmcSaveYourselfDone(smc_conn, True);
+    xsmp.save_yourself = True;
+    xsmp.shutdown = shutdown;
+
+    /* First up, preserve all files */
+    out_flush();
+    ml_sync_all(FALSE, FALSE);	/* preserve all swap files */
+
+    if (p_verbose > 0)
+	MSG(_("XSMP handling save-yourself request"));
+
+# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
+    /* Now see if we can ask about unsaved files */
+    if (shutdown && !fast && gui.in_use)
+	/* Need to interact with user, but need SM's permission */
+	SmcInteractRequest(smc_conn, SmDialogError,
+					xsmp_handle_interaction, client_data);
+    else
+# endif
+    {
+	/* Can stop the cycle here */
+	SmcSaveYourselfDone(smc_conn, True);
+	xsmp.save_yourself = False;
+    }
+}
+
+
+/*
+ * Callback to warn us of imminent death.
+ */
+/*ARGSUSED*/
+    static void
+xsmp_die(smc_conn, client_data)
+    SmcConn	smc_conn;
+    SmPointer	client_data;
+{
+    xsmp_close();
+
+    /* quit quickly leaving swapfiles for modified buffers behind */
+    getout_preserve_modified(0);
+}
+
+
+/*
+ * Callback to tell us that save-yourself has completed.
+ */
+/*ARGSUSED*/
+    static void
+xsmp_save_complete(smc_conn, client_data)
+    SmcConn	smc_conn;
+    SmPointer	client_data;
+{
+    xsmp.save_yourself = False;
+}
+
+
+/*
+ * Callback to tell us that an instigated shutdown was cancelled
+ * (maybe even by us)
+ */
+/*ARGSUSED*/
+    static void
+xsmp_shutdown_cancelled(smc_conn, client_data)
+    SmcConn	smc_conn;
+    SmPointer	client_data;
+{
+    if (xsmp.save_yourself)
+	SmcSaveYourselfDone(smc_conn, True);
+    xsmp.save_yourself = False;
+    xsmp.shutdown = False;
+}
+
+
+/*
+ * Callback to tell us that a new ICE connection has been established.
+ */
+/*ARGSUSED*/
+    static void
+xsmp_ice_connection(iceConn, clientData, opening, watchData)
+    IceConn	iceConn;
+    IcePointer	clientData;
+    Bool	opening;
+    IcePointer	*watchData;
+{
+    /* Intercept creation of ICE connection fd */
+    if (opening)
+    {
+	xsmp_icefd = IceConnectionNumber(iceConn);
+	IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
+    }
+}
+
+
+/* Handle any ICE processing that's required; return FAIL if SM lost */
+    int
+xsmp_handle_requests()
+{
+    Bool rep;
+
+    if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
+						 == IceProcessMessagesIOError)
+    {
+	/* Lost ICE */
+	if (p_verbose > 0)
+	    MSG(_("XSMP lost ICE connection"));
+	xsmp_close();
+	return FAIL;
+    }
+    else
+	return OK;
+}
+
+static int dummy;
+
+/* Set up X Session Management Protocol */
+    void
+xsmp_init(void)
+{
+    char		errorstring[80];
+    char		*clientid;
+    SmcCallbacks	smcallbacks;
+#if 0
+    SmPropValue		smname;
+    SmProp		smnameprop;
+    SmProp		*smprops[1];
+#endif
+
+    if (p_verbose > 0)
+	MSG(_("XSMP opening connection"));
+
+    xsmp.save_yourself = xsmp.shutdown = False;
+
+    /* Set up SM callbacks - must have all, even if they're not used */
+    smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
+    smcallbacks.save_yourself.client_data = NULL;
+    smcallbacks.die.callback = xsmp_die;
+    smcallbacks.die.client_data = NULL;
+    smcallbacks.save_complete.callback = xsmp_save_complete;
+    smcallbacks.save_complete.client_data = NULL;
+    smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
+    smcallbacks.shutdown_cancelled.client_data = NULL;
+
+    /* Set up a watch on ICE connection creations.  The "dummy" argument is
+     * apparently required for FreeBSD (we get a BUS error when using NULL). */
+    if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
+    {
+	if (p_verbose > 0)
+	    MSG(_("XSMP ICE connection watch failed"));
+	return;
+    }
+
+    /* Create an SM connection */
+    xsmp.smcconn = SmcOpenConnection(
+	    NULL,
+	    NULL,
+	    SmProtoMajor,
+	    SmProtoMinor,
+	    SmcSaveYourselfProcMask | SmcDieProcMask
+		     | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
+	    &smcallbacks,
+	    NULL,
+	    &clientid,
+	    sizeof(errorstring),
+	    errorstring);
+    if (xsmp.smcconn == NULL)
+    {
+	char errorreport[132];
+	sprintf(errorreport, _("XSMP SmcOpenConnection failed: %s"),
+		errorstring);
+	if (p_verbose > 0)
+	    MSG(errorreport);
+	return;
+    }
+    xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
+
+#if 0
+    /* ID ourselves */
+    smname.value = "vim";
+    smname.length = 3;
+    smnameprop.name = "SmProgram";
+    smnameprop.type = "SmARRAY8";
+    smnameprop.num_vals = 1;
+    smnameprop.vals = &smname;
+
+    smprops[0] = &smnameprop;
+    SmcSetProperties(xsmp.smcconn, 1, smprops);
+#endif
+}
+
+
+/* Shut down XSMP comms. */
+    void
+xsmp_close()
+{
+    if (xsmp_icefd != -1)
+    {
+	SmcCloseConnection(xsmp.smcconn, 0, NULL);
+	xsmp_icefd = -1;
+    }
+}
+#endif /* USE_XSMP */
+
+
+#ifdef EBCDIC
+/* Translate character to its CTRL- value */
+char CtrlTable[] =
+{
+/* 00 - 5E */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* ^ */ 0x1E,
+/* - */ 0x1F,
+/* 61 - 6C */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* _ */ 0x1F,
+/* 6E - 80 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* a */ 0x01,
+/* b */ 0x02,
+/* c */ 0x03,
+/* d */ 0x37,
+/* e */ 0x2D,
+/* f */ 0x2E,
+/* g */ 0x2F,
+/* h */ 0x16,
+/* i */ 0x05,
+/* 8A - 90 */
+	0, 0, 0, 0, 0, 0, 0,
+/* j */ 0x15,
+/* k */ 0x0B,
+/* l */ 0x0C,
+/* m */ 0x0D,
+/* n */ 0x0E,
+/* o */ 0x0F,
+/* p */ 0x10,
+/* q */ 0x11,
+/* r */ 0x12,
+/* 9A - A1 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+/* s */ 0x13,
+/* t */ 0x3C,
+/* u */ 0x3D,
+/* v */ 0x32,
+/* w */ 0x26,
+/* x */ 0x18,
+/* y */ 0x19,
+/* z */ 0x3F,
+/* AA - AC */
+	0, 0, 0,
+/* [ */ 0x27,
+/* AE - BC */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* ] */ 0x1D,
+/* BE - C0 */ 0, 0, 0,
+/* A */ 0x01,
+/* B */ 0x02,
+/* C */ 0x03,
+/* D */ 0x37,
+/* E */ 0x2D,
+/* F */ 0x2E,
+/* G */ 0x2F,
+/* H */ 0x16,
+/* I */ 0x05,
+/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
+/* J */ 0x15,
+/* K */ 0x0B,
+/* L */ 0x0C,
+/* M */ 0x0D,
+/* N */ 0x0E,
+/* O */ 0x0F,
+/* P */ 0x10,
+/* Q */ 0x11,
+/* R */ 0x12,
+/* DA - DF */ 0, 0, 0, 0, 0, 0,
+/* \ */ 0x1C,
+/* E1 */ 0,
+/* S */ 0x13,
+/* T */ 0x3C,
+/* U */ 0x3D,
+/* V */ 0x32,
+/* W */ 0x26,
+/* X */ 0x18,
+/* Y */ 0x19,
+/* Z */ 0x3F,
+/* EA - FF*/ 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+char MetaCharTable[]=
+{/*   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
+      0,  0,  0,  0,'\\', 0,'F',  0,'W','M','N',  0,  0,  0,  0,  0,
+      0,  0,  0,  0,']',  0,  0,'G',  0,  0,'R','O',  0,  0,  0,  0,
+    '@','A','B','C','D','E',  0,  0,'H','I','J','K','L',  0,  0,  0,
+    'P','Q',  0,'S','T','U','V',  0,'X','Y','Z','[',  0,  0,'^',  0
+};
+
+
+/* TODO: Use characters NOT numbers!!! */
+char CtrlCharTable[]=
+{/*   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
+    124,193,194,195,  0,201,  0,  0,  0,  0,  0,210,211,212,213,214,
+    215,216,217,226,  0,209,200,  0,231,232,  0,  0,224,189, 95,109,
+      0,  0,  0,  0,  0,  0,230,173,  0,  0,  0,  0,  0,197,198,199,
+      0,  0,229,  0,  0,  0,  0,196,  0,  0,  0,  0,227,228,  0,233,
+};
+
+
+#endif