blob: a39caffe4b161c4688e4cd26f49ac2aaaac4ea52 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
15 * Also for BeOS and Atari MiNT.
16 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
21/*
22 * Some systems have a prototype for select() that has (int *) instead of
23 * (fd_set *), which is wrong. This define removes that prototype. We define
24 * our own prototype below.
25 * Don't use it for the Mac, it causes a warning for precompiled headers.
26 * TODO: use a configure check for precompiled headers?
27 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000028#if !defined(__APPLE__) && !defined(__TANDEM)
Bram Moolenaar071d4272004-06-13 20:20:40 +000029# define select select_declared_wrong
30#endif
31
32#include "vim.h"
33
Bram Moolenaar325b7a22004-07-05 15:58:32 +000034#ifdef FEAT_MZSCHEME
35# include "if_mzsch.h"
36#endif
37
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#include "os_unixx.h" /* unix includes for os_unix.c only */
39
40#ifdef USE_XSMP
41# include <X11/SM/SMlib.h>
42#endif
43
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000044#ifdef HAVE_SELINUX
45# include <selinux/selinux.h>
46static int selinux_enabled = -1;
47#endif
48
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020049#ifdef HAVE_SMACK
50# include <attr/xattr.h>
51# include <linux/xattr.h>
52# ifndef SMACK_LABEL_LEN
53# define SMACK_LABEL_LEN 1024
54# endif
55#endif
56
Bram Moolenaar071d4272004-06-13 20:20:40 +000057/*
58 * Use this prototype for select, some include files have a wrong prototype
59 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000060#ifndef __TANDEM
61# undef select
62# ifdef __BEOS__
63# define select beos_select
64# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#endif
66
Bram Moolenaara2442432007-04-26 14:26:37 +000067#ifdef __CYGWIN__
68# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000069# include <cygwin/version.h>
70# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
71 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010072# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
73# define WIN32_LEAN_AND_MEAN
74# include <windows.h>
75# include "winclip.pro"
76# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000077# endif
78#endif
79
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#if defined(HAVE_SELECT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010081extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
Bram Moolenaar071d4272004-06-13 20:20:40 +000082#endif
83
84#ifdef FEAT_MOUSE_GPM
85# include <gpm.h>
86/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
87 * I just copied relevant defines here. A cleaner solution would be to put gpm
88 * code into separate file and include there linux/keyboard.h
89 */
90/* #include <linux/keyboard.h> */
91# define KG_SHIFT 0
92# define KG_CTRL 2
93# define KG_ALT 3
94# define KG_ALTGR 1
95# define KG_SHIFTL 4
96# define KG_SHIFTR 5
97# define KG_CTRLL 6
98# define KG_CTRLR 7
99# define KG_CAPSSHIFT 8
100
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100101static void gpm_close(void);
102static int gpm_open(void);
103static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104#endif
105
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000106#ifdef FEAT_SYSMOUSE
107# include <sys/consio.h>
108# include <sys/fbio.h>
109
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100110static int sysmouse_open(void);
111static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +0100112static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000113#endif
114
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115/*
116 * end of autoconf section. To be extended...
117 */
118
119/* Are the following #ifdefs still required? And why? Is that for X11? */
120
121#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
122# ifdef SIGWINCH
123# undef SIGWINCH
124# endif
125# ifdef TIOCGWINSZ
126# undef TIOCGWINSZ
127# endif
128#endif
129
130#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
131# define SIGWINCH SIGWINDOW
132#endif
133
134#ifdef FEAT_X11
135# include <X11/Xlib.h>
136# include <X11/Xutil.h>
137# include <X11/Xatom.h>
138# ifdef FEAT_XCLIPBOARD
139# include <X11/Intrinsic.h>
140# include <X11/Shell.h>
141# include <X11/StringDefs.h>
142static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void clip_update(void);
144static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145# endif
146
147# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
148Window x11_window = 0;
149# endif
150Display *x11_display = NULL;
151
152# ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100153static int get_x11_windis(void);
154static void set_x11_title(char_u *);
155static void set_x11_icon(char_u *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156# endif
157#endif
158
159#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100160static int get_x11_title(int);
161static int get_x11_icon(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162
163static char_u *oldtitle = NULL;
164static int did_set_title = FALSE;
165static char_u *oldicon = NULL;
166static int did_set_icon = FALSE;
167#endif
168
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100169static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaar205b8862011-09-07 15:04:31 +0200171#ifdef HAVE_UNION_WAIT
172typedef union wait waitstatus;
173#else
174typedef int waitstatus;
175#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100176static pid_t wait4pid(pid_t, waitstatus *);
Bram Moolenaar205b8862011-09-07 15:04:31 +0200177
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200178static int WaitForChar(long msec, int *interrupted, int ignore_input);
179static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100180#if defined(__BEOS__) || defined(VMS)
Bram Moolenaarcda77642016-06-04 13:32:35 +0200181int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200183static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184#endif
185
186#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100187static int do_xterm_trace(void);
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000188# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189#endif
190
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100191static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192
193#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100194static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195#endif
196#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100197static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198#endif
199#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100200static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#endif
202#if defined(SIGALRM) && defined(FEAT_X11) \
203 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
204# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100205static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000206/* volatile because it is used in signal handler sig_alarm(). */
207static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100209static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100211static void catch_int_signal(void);
212static void set_signals(void);
213static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200214#ifdef HAVE_SIGPROCMASK
215# define SIGSET_DECL(set) sigset_t set;
216# define BLOCK_SIGNALS(set) block_signals(set)
217# define UNBLOCK_SIGNALS(set) unblock_signals(set)
218#else
219# define SIGSET_DECL(set)
220# define BLOCK_SIGNALS(set) do { /**/ } while (0)
221# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
222#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100223static int have_wildcard(int, char_u **);
224static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100226static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227
228#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000229# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230#endif
231
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000232/* volatile because it is used in signal handler sig_winch(). */
233static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234static char_u *extra_shell_arg = NULL;
235static int show_shell_mess = TRUE;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000236/* volatile because it is used in signal handler deathtrap(). */
237static volatile int deadly_signal = 0; /* The signal we caught */
238/* volatile because it is used in signal handler deathtrap(). */
239static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100241#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
242static int dont_check_job_ended = 0;
243#endif
244
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
246
247#ifdef USE_XSMP
248typedef struct
249{
250 SmcConn smcconn; /* The SM connection ID */
251 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200252 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 Bool save_yourself; /* If we're in the middle of a save_yourself */
254 Bool shutdown; /* If we're in shutdown mode */
255} xsmp_config_T;
256
257static xsmp_config_T xsmp;
258#endif
259
260#ifdef SYS_SIGLIST_DECLARED
261/*
262 * I have seen
263 * extern char *_sys_siglist[NSIG];
264 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
265 * that describe the signals. That is nearly what we want here. But
266 * autoconf does only check for sys_siglist (without the underscore), I
267 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100268 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000269 */
270#endif
271
272static struct signalinfo
273{
274 int sig; /* Signal number, eg. SIGSEGV etc */
275 char *name; /* Signal name (not char_u!). */
276 char deadly; /* Catch as a deadly signal? */
277} signal_info[] =
278{
279#ifdef SIGHUP
280 {SIGHUP, "HUP", TRUE},
281#endif
282#ifdef SIGQUIT
283 {SIGQUIT, "QUIT", TRUE},
284#endif
285#ifdef SIGILL
286 {SIGILL, "ILL", TRUE},
287#endif
288#ifdef SIGTRAP
289 {SIGTRAP, "TRAP", TRUE},
290#endif
291#ifdef SIGABRT
292 {SIGABRT, "ABRT", TRUE},
293#endif
294#ifdef SIGEMT
295 {SIGEMT, "EMT", TRUE},
296#endif
297#ifdef SIGFPE
298 {SIGFPE, "FPE", TRUE},
299#endif
300#ifdef SIGBUS
301 {SIGBUS, "BUS", TRUE},
302#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100303#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
304 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 {SIGSEGV, "SEGV", TRUE},
306#endif
307#ifdef SIGSYS
308 {SIGSYS, "SYS", TRUE},
309#endif
310#ifdef SIGALRM
311 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
312#endif
313#ifdef SIGTERM
314 {SIGTERM, "TERM", TRUE},
315#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100316#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317 {SIGVTALRM, "VTALRM", TRUE},
318#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000319#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
320 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
321 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 {SIGPROF, "PROF", TRUE},
323#endif
324#ifdef SIGXCPU
325 {SIGXCPU, "XCPU", TRUE},
326#endif
327#ifdef SIGXFSZ
328 {SIGXFSZ, "XFSZ", TRUE},
329#endif
330#ifdef SIGUSR1
331 {SIGUSR1, "USR1", TRUE},
332#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000333#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
334 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000335 {SIGUSR2, "USR2", TRUE},
336#endif
337#ifdef SIGINT
338 {SIGINT, "INT", FALSE},
339#endif
340#ifdef SIGWINCH
341 {SIGWINCH, "WINCH", FALSE},
342#endif
343#ifdef SIGTSTP
344 {SIGTSTP, "TSTP", FALSE},
345#endif
346#ifdef SIGPIPE
347 {SIGPIPE, "PIPE", FALSE},
348#endif
349 {-1, "Unknown!", FALSE}
350};
351
Bram Moolenaar25724922009-07-14 15:38:41 +0000352 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100353mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000354{
355 if (p_verbose >= 5)
356 {
357 verbose_enter();
358 smsg((char_u *)"chdir(%s)", path);
359 verbose_leave();
360 }
361# ifdef VMS
362 return chdir(vms_fixfilename(path));
363# else
364 return chdir(path);
365# endif
366}
367
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200368/* Why is NeXT excluded here (and not in os_unixx.h)? */
369#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
370# define NEW_TTY_SYSTEM
371#endif
372
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000373/*
374 * Write s[len] to the screen.
375 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100377mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000378{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000379 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 if (p_wd) /* Unix is too fast, slow down a bit more */
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100381 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382}
383
384/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000385 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 * Get a characters from the keyboard.
387 * Return the number of characters that are available.
388 * If wtime == 0 do not wait for characters.
389 * If wtime == n wait a short time for characters.
390 * If wtime == -1 wait forever for characters.
391 */
392 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100393mch_inchar(
394 char_u *buf,
395 int maxlen,
396 long wtime, /* don't use "time", MIPS cannot handle it */
397 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398{
399 int len;
Bram Moolenaarcda77642016-06-04 13:32:35 +0200400 int interrupted = FALSE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200401 int did_start_blocking = FALSE;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200402 long wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200403 long elapsed_time = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100404#ifdef ELAPSED_FUNC
405 ELAPSED_TYPE start_tv;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200406
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100407 ELAPSED_INIT(start_tv);
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200408#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200410 /* repeat until we got a character or waited long enough */
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200411 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200413 /* Check if window changed size while we were busy, perhaps the ":set
414 * columns=99" command was used. */
415 while (do_resize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200417
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200418#ifdef MESSAGE_QUEUE
419 parse_queued_messages();
Bram Moolenaard85f2712017-07-28 21:51:57 +0200420 /* If input was put directly in typeahead buffer bail out here. */
421 if (typebuf_changed(tb_change_cnt))
422 return 0;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200423#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200424 if (wtime < 0 && did_start_blocking)
425 /* blocking and already waited for p_ut */
426 wait_time = -1;
427 else
428 {
429 if (wtime >= 0)
430 wait_time = wtime;
431 else
432 /* going to block after p_ut */
433 wait_time = p_ut;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100434#ifdef ELAPSED_FUNC
435 elapsed_time = ELAPSED_FUNC(start_tv);
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200436#endif
437 wait_time -= elapsed_time;
438 if (wait_time < 0)
439 {
440 if (wtime >= 0)
441 /* no character available within "wtime" */
442 return 0;
443
444 if (wtime < 0)
445 {
446 /* no character available within 'updatetime' */
447 did_start_blocking = TRUE;
448#ifdef FEAT_AUTOCMD
449 if (trigger_cursorhold() && maxlen >= 3
450 && !typebuf_changed(tb_change_cnt))
451 {
452 buf[0] = K_SPECIAL;
453 buf[1] = KS_EXTRA;
454 buf[2] = (int)KE_CURSORHOLD;
455 return 3;
456 }
457#endif
458 /*
459 * If there is no character available within 'updatetime'
460 * seconds flush all the swap files to disk.
461 * Also done when interrupted by SIGWINCH.
462 */
463 before_blocking();
464 continue;
465 }
466 }
467 }
468
469#ifdef FEAT_JOB_CHANNEL
470 /* Checking if a job ended requires polling. Do this every 100 msec. */
471 if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
472 wait_time = 100L;
Bram Moolenaar8a8199e2016-11-26 15:13:33 +0100473 /* If there is readahead then parse_queued_messages() timed out and we
474 * should call it again soon. */
475 if ((wait_time < 0 || wait_time > 100L) && channel_any_readahead())
476 wait_time = 10L;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200477#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100478#ifdef FEAT_BEVAL
479 if (p_beval && wait_time > 100L)
480 /* The 'balloonexpr' may indirectly invoke a callback while waiting
481 * for a character, need to check often. */
482 wait_time = 100L;
483#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200484
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200486 * We want to be interrupted by the winch signal
487 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 */
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200489 if (WaitForChar(wait_time, &interrupted, FALSE))
Bram Moolenaar67c53842010-05-22 18:28:27 +0200490 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200491 /* If input was put directly in typeahead buffer bail out here. */
492 if (typebuf_changed(tb_change_cnt))
493 return 0;
494
495 /*
496 * For some terminals we only get one character at a time.
497 * We want the get all available characters, so we could keep on
498 * trying until none is available
499 * For some other terminals this is quite slow, that's why we don't
500 * do it.
501 */
502 len = read_from_input_buf(buf, (long)maxlen);
503 if (len > 0)
504 return len;
505 continue;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200508 /* no character available */
509#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
510 /* estimate the elapsed time */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +0100511 elapsed_time += wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200512#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200514 if (do_resize /* interrupted by SIGWINCH signal */
515#ifdef FEAT_CLIENTSERVER
516 || server_waiting()
517#endif
518#ifdef MESSAGE_QUEUE
519 || interrupted
520#endif
521 || wait_time > 0
Bram Moolenaar1572e302017-03-25 20:16:28 +0100522 || (wtime < 0 && !did_start_blocking))
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200523 continue;
524
525 /* no character available or interrupted */
526 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200528 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529}
530
531 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100532handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533{
534 do_resize = FALSE;
535 shell_resized();
536}
537
538/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200539 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 */
541 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100542mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200544 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545}
546
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200547#if defined(FEAT_TERMINAL) || defined(PROTO)
548/*
549 * Check for any pending input or messages.
550 */
551 int
552mch_check_messages(void)
553{
554 return WaitForChar(0L, NULL, TRUE);
555}
556#endif
557
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
559# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000560# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561# endif
562# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
563# include <sys/sysctl.h>
564# endif
565# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
566# include <sys/sysinfo.h>
567# endif
568
569/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000570 * Return total amount of memory available in Kbyte.
571 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100574mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000577 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200579# ifdef HAVE_SYSCTL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580 int mib[2], physmem;
581 size_t len;
582
583 /* BSD way of getting the amount of RAM available. */
584 mib[0] = CTL_HW;
585 mib[1] = HW_USERMEM;
586 len = sizeof(physmem);
587 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
588 mem = (long_u)physmem;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200589# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200591# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 if (mem == 0)
593 {
594 struct sysinfo sinfo;
595
596 /* Linux way of getting amount of RAM available */
597 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000598 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200599# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar914572a2007-05-01 11:37:47 +0000600 /* avoid overflow as much as possible */
601 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
602 {
603 sinfo.mem_unit = sinfo.mem_unit >> 1;
604 --shiftright;
605 }
606 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200607# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200609# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000610 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200612# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200614# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 if (mem == 0)
616 {
617 long pagesize, pagecount;
618
619 /* Solaris way of getting amount of RAM available */
620 pagesize = sysconf(_SC_PAGESIZE);
621 pagecount = sysconf(_SC_PHYS_PAGES);
622 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000623 {
624 /* avoid overflow as much as possible */
625 while (shiftright > 0 && (pagesize & 1) == 0)
626 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000627 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000628 --shiftright;
629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000631 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200633# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634
635 /* Return the minimum of the physical memory and the user limit, because
636 * using more than the user limit may cause Vim to be terminated. */
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200637# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 {
639 struct rlimit rlp;
640
641 if (getrlimit(RLIMIT_DATA, &rlp) == 0
642 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200643# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200645# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000646 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000648 {
649 mem = (long_u)rlp.rlim_cur;
650 shiftright = 10;
651 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200653# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654
655 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000656 return mem >> shiftright;
657 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658}
659#endif
660
661 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100662mch_delay(long msec, int ignoreinput)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663{
664 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000665#ifdef FEAT_MZSCHEME
666 long total = msec; /* remember original value */
667#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668
669 if (ignoreinput)
670 {
671 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000672 * here. But we don't want QUIT to kill us (CTRL-\ used in a
673 * shell may produce SIGQUIT). */
674 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 old_tmode = curr_tmode;
676 if (curr_tmode == TMODE_RAW)
677 settmode(TMODE_SLEEP);
678
679 /*
680 * Everybody sleeps in a different way...
681 * Prefer nanosleep(), some versions of usleep() can only sleep up to
682 * one second.
683 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000684#ifdef FEAT_MZSCHEME
685 do
686 {
687 /* if total is large enough, wait by portions in p_mzq */
688 if (total > p_mzq)
689 msec = p_mzq;
690 else
691 msec = total;
692 total -= msec;
693#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694#ifdef HAVE_NANOSLEEP
695 {
696 struct timespec ts;
697
698 ts.tv_sec = msec / 1000;
699 ts.tv_nsec = (msec % 1000) * 1000000;
700 (void)nanosleep(&ts, NULL);
701 }
702#else
703# ifdef HAVE_USLEEP
704 while (msec >= 1000)
705 {
706 usleep((unsigned int)(999 * 1000));
707 msec -= 999;
708 }
709 usleep((unsigned int)(msec * 1000));
710# else
711# ifndef HAVE_SELECT
712 poll(NULL, 0, (int)msec);
713# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714 {
715 struct timeval tv;
716
717 tv.tv_sec = msec / 1000;
718 tv.tv_usec = (msec % 1000) * 1000;
719 /*
720 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
721 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
722 */
723 select(0, NULL, NULL, NULL, &tv);
724 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725# endif /* HAVE_SELECT */
726# endif /* HAVE_NANOSLEEP */
727#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000728#ifdef FEAT_MZSCHEME
729 }
730 while (total > 0);
731#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000734 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 }
736 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200737 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738}
739
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000740#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
742# define HAVE_CHECK_STACK_GROWTH
743/*
744 * Support for checking for an almost-out-of-stack-space situation.
745 */
746
747/*
748 * Return a pointer to an item on the stack. Used to find out if the stack
749 * grows up or down.
750 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100751static void check_stack_growth(char *p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752static int stack_grows_downwards;
753
754/*
755 * Find out if the stack grows upwards or downwards.
756 * "p" points to a variable on the stack of the caller.
757 */
758 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100759check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760{
761 int i;
762
763 stack_grows_downwards = (p > (char *)&i);
764}
765#endif
766
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000767#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768static char *stack_limit = NULL;
769
770#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
771# include <pthread.h>
772# include <pthread_np.h>
773#endif
774
775/*
776 * Find out until how var the stack can grow without getting into trouble.
777 * Called when starting up and when switching to the signal stack in
778 * deathtrap().
779 */
780 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100781get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782{
783 struct rlimit rlp;
784 int i;
785 long lim;
786
787 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
788 * limit doesn't fit in a long (rlim_cur might be "long long"). */
789 if (getrlimit(RLIMIT_STACK, &rlp) == 0
790 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
791# ifdef RLIM_INFINITY
792 && rlp.rlim_cur != RLIM_INFINITY
793# endif
794 )
795 {
796 lim = (long)rlp.rlim_cur;
797#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
798 {
799 pthread_attr_t attr;
800 size_t size;
801
802 /* On FreeBSD the initial thread always has a fixed stack size, no
803 * matter what the limits are set to. Normally it's 1 Mbyte. */
804 pthread_attr_init(&attr);
805 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
806 {
807 pthread_attr_getstacksize(&attr, &size);
808 if (lim > (long)size)
809 lim = (long)size;
810 }
811 pthread_attr_destroy(&attr);
812 }
813#endif
814 if (stack_grows_downwards)
815 {
816 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
817 if (stack_limit >= (char *)&i)
818 /* overflow, set to 1/16 of current stack position */
819 stack_limit = (char *)((long)&i / 16L);
820 }
821 else
822 {
823 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
824 if (stack_limit <= (char *)&i)
825 stack_limit = NULL; /* overflow */
826 }
827 }
828}
829
830/*
831 * Return FAIL when running out of stack space.
832 * "p" must point to any variable local to the caller that's on the stack.
833 */
834 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100835mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836{
837 if (stack_limit != NULL)
838 {
839 if (stack_grows_downwards)
840 {
841 if (p < stack_limit)
842 return FAIL;
843 }
844 else if (p > stack_limit)
845 return FAIL;
846 }
847 return OK;
848}
849#endif
850
851#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
852/*
853 * Support for using the signal stack.
854 * This helps when we run out of stack space, which causes a SIGSEGV. The
855 * signal handler then must run on another stack, since the normal stack is
856 * completely full.
857 */
858
859#ifndef SIGSTKSZ
860# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
861#endif
862
863# ifdef HAVE_SIGALTSTACK
864static stack_t sigstk; /* for sigaltstack() */
865# else
866static struct sigstack sigstk; /* for sigstack() */
867# endif
868
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100869static void init_signal_stack(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870static char *signal_stack;
871
872 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100873init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874{
875 if (signal_stack != NULL)
876 {
877# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878# ifdef HAVE_SS_BASE
879 sigstk.ss_base = signal_stack;
880# else
881 sigstk.ss_sp = signal_stack;
882# endif
883 sigstk.ss_size = SIGSTKSZ;
884 sigstk.ss_flags = 0;
885 (void)sigaltstack(&sigstk, NULL);
886# else
887 sigstk.ss_sp = signal_stack;
888 if (stack_grows_downwards)
889 sigstk.ss_sp += SIGSTKSZ - 1;
890 sigstk.ss_onstack = 0;
891 (void)sigstack(&sigstk, NULL);
892# endif
893 }
894}
895#endif
896
897/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000898 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899 * will barf when the second argument to signal() is ``wrong''.
900 * Let me try it with a few tricky defines from my own osdef.h (jw).
901 */
902#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 static RETSIGTYPE
904sig_winch SIGDEFARG(sigarg)
905{
906 /* this is not required on all systems, but it doesn't hurt anybody */
907 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
908 do_resize = TRUE;
909 SIGRETURN;
910}
911#endif
912
913#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000914 static RETSIGTYPE
915catch_sigint SIGDEFARG(sigarg)
916{
917 /* this is not required on all systems, but it doesn't hurt anybody */
918 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
919 got_int = TRUE;
920 SIGRETURN;
921}
922#endif
923
924#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925 static RETSIGTYPE
926catch_sigpwr SIGDEFARG(sigarg)
927{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000928 /* this is not required on all systems, but it doesn't hurt anybody */
929 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 /*
931 * I'm not sure we get the SIGPWR signal when the system is really going
932 * down or when the batteries are almost empty. Just preserve the swap
933 * files and don't exit, that can't do any harm.
934 */
935 ml_sync_all(FALSE, FALSE);
936 SIGRETURN;
937}
938#endif
939
940#ifdef SET_SIG_ALARM
941/*
942 * signal function for alarm().
943 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 static RETSIGTYPE
945sig_alarm SIGDEFARG(sigarg)
946{
947 /* doesn't do anything, just to break a system call */
948 sig_alarm_called = TRUE;
949 SIGRETURN;
950}
951#endif
952
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000953#if (defined(HAVE_SETJMP_H) \
954 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
955 || defined(FEAT_LIBCALL))) \
956 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000957/*
958 * A simplistic version of setjmp() that only allows one level of using.
959 * Don't call twice before calling mch_endjmp()!.
960 * Usage:
961 * mch_startjmp();
962 * if (SETJMP(lc_jump_env) != 0)
963 * {
964 * mch_didjmp();
965 * EMSG("crash!");
966 * }
967 * else
968 * {
969 * do_the_work;
970 * mch_endjmp();
971 * }
972 * Note: Can't move SETJMP() here, because a function calling setjmp() must
973 * not return before the saved environment is used.
974 * Returns OK for normal return, FAIL when the protected code caused a
975 * problem and LONGJMP() was used.
976 */
977 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100978mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979{
980#ifdef SIGHASARG
981 lc_signal = 0;
982#endif
983 lc_active = TRUE;
984}
985
986 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100987mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988{
989 lc_active = FALSE;
990}
991
992 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100993mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000994{
995# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
996 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
997 * otherwise catching the signal only works once. */
998 init_signal_stack();
999# endif
1000}
1001#endif
1002
1003/*
1004 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001005 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001007 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1008 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 */
1010 static RETSIGTYPE
1011deathtrap SIGDEFARG(sigarg)
1012{
1013 static int entered = 0; /* count the number of times we got here.
1014 Note: when memory has been corrupted
1015 this may get an arbitrary value! */
1016#ifdef SIGHASARG
1017 int i;
1018#endif
1019
1020#if defined(HAVE_SETJMP_H)
1021 /*
1022 * Catch a crash in protected code.
1023 * Restores the environment saved in lc_jump_env, which looks like
1024 * SETJMP() returns 1.
1025 */
1026 if (lc_active)
1027 {
1028# if defined(SIGHASARG)
1029 lc_signal = sigarg;
1030# endif
1031 lc_active = FALSE; /* don't jump again */
1032 LONGJMP(lc_jump_env, 1);
1033 /* NOTREACHED */
1034 }
1035#endif
1036
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001037#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001038# ifdef SIGQUIT
1039 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
1040 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1041 * pressing CTRL-\, but we don't want Vim to exit then. */
1042 if (in_mch_delay && sigarg == SIGQUIT)
1043 SIGRETURN;
1044# endif
1045
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001046 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1047 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1048 * free(). Calling free() again may then cause a crash. */
1049 if (entered == 0
1050 && (0
1051# ifdef SIGHUP
1052 || sigarg == SIGHUP
1053# endif
1054# ifdef SIGQUIT
1055 || sigarg == SIGQUIT
1056# endif
1057# ifdef SIGTERM
1058 || sigarg == SIGTERM
1059# endif
1060# ifdef SIGPWR
1061 || sigarg == SIGPWR
1062# endif
1063# ifdef SIGUSR1
1064 || sigarg == SIGUSR1
1065# endif
1066# ifdef SIGUSR2
1067 || sigarg == SIGUSR2
1068# endif
1069 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001070 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001071 SIGRETURN;
1072#endif
1073
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 /* Remember how often we have been called. */
1075 ++entered;
1076
Bram Moolenaare429e702016-06-10 19:49:14 +02001077#ifdef FEAT_AUTOCMD
1078 /* Executing autocommands is likely to use more stack space than we have
1079 * available in the signal stack. */
1080 block_autocmds();
1081#endif
1082
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083#ifdef FEAT_EVAL
1084 /* Set the v:dying variable. */
1085 set_vim_var_nr(VV_DYING, (long)entered);
1086#endif
1087
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001088#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 /* Since we are now using the signal stack, need to reset the stack
1090 * limit. Otherwise using a regexp will fail. */
1091 get_stack_limit();
1092#endif
1093
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001094#if 0
1095 /* This is for opening gdb the moment Vim crashes.
1096 * You need to manually adjust the file name and Vim executable name.
1097 * Suggested by SungHyun Nam. */
1098 {
1099# define VI_GDB_FILE "/tmp/vimgdb"
1100# define VIM_NAME "/usr/bin/vim"
1101 FILE *fp = fopen(VI_GDB_FILE, "w");
1102 if (fp)
1103 {
1104 fprintf(fp,
1105 "file %s\n"
1106 "attach %d\n"
1107 "set height 1000\n"
1108 "bt full\n"
1109 , VIM_NAME, getpid());
1110 fclose(fp);
1111 system("xterm -e gdb -x "VI_GDB_FILE);
1112 unlink(VI_GDB_FILE);
1113 }
1114 }
1115#endif
1116
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117#ifdef SIGHASARG
1118 /* try to find the name of this signal */
1119 for (i = 0; signal_info[i].sig != -1; i++)
1120 if (sigarg == signal_info[i].sig)
1121 break;
1122 deadly_signal = sigarg;
1123#endif
1124
1125 full_screen = FALSE; /* don't write message to the GUI, it might be
1126 * part of the problem... */
1127 /*
1128 * If something goes wrong after entering here, we may get here again.
1129 * When this happens, give a message and try to exit nicely (resetting the
1130 * terminal mode, etc.)
1131 * When this happens twice, just exit, don't even try to give a message,
1132 * stack may be corrupt or something weird.
1133 * When this still happens again (or memory was corrupted in such a way
1134 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1135 */
1136 if (entered >= 3)
1137 {
1138 reset_signals(); /* don't catch any signals anymore */
1139 may_core_dump();
1140 if (entered >= 4)
1141 _exit(8);
1142 exit(7);
1143 }
1144 if (entered == 2)
1145 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001146 /* No translation, it may call malloc(). */
1147 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148 out_flush();
1149 getout(1);
1150 }
1151
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001152 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001154 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 signal_info[i].name);
1156#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001157 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001159
1160 /* Preserve files and exit. This sets the really_exiting flag to prevent
1161 * calling free(). */
1162 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163
Bram Moolenaare429e702016-06-10 19:49:14 +02001164 /* NOTREACHED */
1165
Bram Moolenaar009b2592004-10-24 19:18:58 +00001166#ifdef NBDEBUG
1167 reset_signals();
1168 may_core_dump();
1169 abort();
1170#endif
1171
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 SIGRETURN;
1173}
1174
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001175#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176/*
1177 * On Solaris with multi-threading, suspending might not work immediately.
1178 * Catch the SIGCONT signal, which will be used as an indication whether the
1179 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001180 *
1181 * On Linux, signal is not always handled immediately either.
1182 * See https://bugs.launchpad.net/bugs/291373
1183 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001184 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001186static volatile int sigcont_received;
Bram Moolenaard99df422016-01-29 23:20:40 +01001187static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188
1189/*
1190 * signal handler for SIGCONT
1191 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 static RETSIGTYPE
1193sigcont_handler SIGDEFARG(sigarg)
1194{
1195 sigcont_received = TRUE;
1196 SIGRETURN;
1197}
1198#endif
1199
Bram Moolenaar62b42182010-09-21 22:09:37 +02001200# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001201static void loose_clipboard(void);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001202# ifdef USE_SYSTEM
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001203static void save_clipboard(void);
1204static void restore_clipboard(void);
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001205
1206static void *clip_star_save = NULL;
1207static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001208# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001209
1210/*
1211 * Called when Vim is going to sleep or execute a shell command.
1212 * We can't respond to requests for the X selections. Lose them, otherwise
1213 * other applications will hang. But first copy the text to cut buffer 0.
1214 */
1215 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001216loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001217{
1218 if (clip_star.owned || clip_plus.owned)
1219 {
1220 x11_export_final_selection();
1221 if (clip_star.owned)
1222 clip_lose_selection(&clip_star);
1223 if (clip_plus.owned)
1224 clip_lose_selection(&clip_plus);
1225 if (x11_display != NULL)
1226 XFlush(x11_display);
1227 }
1228}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001229
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001230# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001231/*
1232 * Save clipboard text to restore later.
1233 */
1234 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001235save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001236{
1237 if (clip_star.owned)
1238 clip_star_save = get_register('*', TRUE);
1239 if (clip_plus.owned)
1240 clip_plus_save = get_register('+', TRUE);
1241}
1242
1243/*
1244 * Restore clipboard text if no one own the X selection.
1245 */
1246 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001247restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001248{
1249 if (clip_star_save != NULL)
1250 {
1251 if (!clip_gen_owner_exists(&clip_star))
1252 put_register('*', clip_star_save);
1253 else
1254 free_register(clip_star_save);
1255 clip_star_save = NULL;
1256 }
1257 if (clip_plus_save != NULL)
1258 {
1259 if (!clip_gen_owner_exists(&clip_plus))
1260 put_register('+', clip_plus_save);
1261 else
1262 free_register(clip_plus_save);
1263 clip_plus_save = NULL;
1264 }
1265}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001266# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001267#endif
1268
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269/*
1270 * If the machine has job control, use it to suspend the program,
1271 * otherwise fake it by starting a new shell.
1272 */
1273 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001274mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275{
1276 /* BeOS does have SIGTSTP, but it doesn't work. */
1277#if defined(SIGTSTP) && !defined(__BEOS__)
1278 out_flush(); /* needed to make cursor visible on some systems */
1279 settmode(TMODE_COOK);
1280 out_flush(); /* needed to disable mouse on some systems */
1281
1282# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001283 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284# endif
1285
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001286# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287 sigcont_received = FALSE;
1288# endif
1289 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001290# if defined(_REENTRANT) && defined(SIGCONT)
1291 /*
1292 * Wait for the SIGCONT signal to be handled. It generally happens
1293 * immediately, but somehow not all the time. Do not call pause()
1294 * because there would be race condition which would hang Vim if
1295 * signal happened in between the test of sigcont_received and the
1296 * call to pause(). If signal is not yet received, call sleep(0)
1297 * to just yield CPU. Signal should then be received. If somehow
1298 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1299 * further if signal is not received after 1+2+3+4 ms (not expected
1300 * to happen).
1301 */
1302 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001303 long wait_time;
1304 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001305 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001306 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001307 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308# endif
1309
1310# ifdef FEAT_TITLE
1311 /*
1312 * Set oldtitle to NULL, so the current title is obtained again.
1313 */
1314 vim_free(oldtitle);
1315 oldtitle = NULL;
1316# endif
1317 settmode(TMODE_RAW);
1318 need_check_timestamps = TRUE;
1319 did_check_timestamps = FALSE;
1320#else
1321 suspend_shell();
1322#endif
1323}
1324
1325 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001326mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327{
1328 Columns = 80;
1329 Rows = 24;
1330
1331 out_flush();
1332 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001333
Bram Moolenaar56718732006-03-15 22:53:57 +00001334#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001335 mac_conv_init();
1336#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001337#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1338 win_clip_init();
1339#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340}
1341
1342 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001343set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344{
1345#if defined(SIGWINCH)
1346 /*
1347 * WINDOW CHANGE signal is handled with sig_winch().
1348 */
1349 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1350#endif
1351
1352 /*
1353 * We want the STOP signal to work, to make mch_suspend() work.
1354 * For "rvim" the STOP signal is ignored.
1355 */
1356#ifdef SIGTSTP
1357 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1358#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001359#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001360 signal(SIGCONT, sigcont_handler);
1361#endif
1362
1363 /*
1364 * We want to ignore breaking of PIPEs.
1365 */
1366#ifdef SIGPIPE
1367 signal(SIGPIPE, SIG_IGN);
1368#endif
1369
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001371 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372#endif
1373
1374 /*
1375 * Ignore alarm signals (Perl's alarm() generates it).
1376 */
1377#ifdef SIGALRM
1378 signal(SIGALRM, SIG_IGN);
1379#endif
1380
1381 /*
1382 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1383 * work will be lost.
1384 */
1385#ifdef SIGPWR
1386 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1387#endif
1388
1389 /*
1390 * Arrange for other signals to gracefully shutdown Vim.
1391 */
1392 catch_signals(deathtrap, SIG_ERR);
1393
1394#if defined(FEAT_GUI) && defined(SIGHUP)
1395 /*
1396 * When the GUI is running, ignore the hangup signal.
1397 */
1398 if (gui.in_use)
1399 signal(SIGHUP, SIG_IGN);
1400#endif
1401}
1402
Bram Moolenaardf177f62005-02-22 08:39:57 +00001403#if defined(SIGINT) || defined(PROTO)
1404/*
1405 * Catch CTRL-C (only works while in Cooked mode).
1406 */
1407 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001408catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001409{
1410 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1411}
1412#endif
1413
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001415reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416{
1417 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001418#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 /* SIGCONT isn't in the list, because its default action is ignore */
1420 signal(SIGCONT, SIG_DFL);
1421#endif
1422}
1423
1424 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001425catch_signals(
1426 RETSIGTYPE (*func_deadly)(),
1427 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001428{
1429 int i;
1430
1431 for (i = 0; signal_info[i].sig != -1; i++)
1432 if (signal_info[i].deadly)
1433 {
1434#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1435 struct sigaction sa;
1436
1437 /* Setup to use the alternate stack for the signal function. */
1438 sa.sa_handler = func_deadly;
1439 sigemptyset(&sa.sa_mask);
1440# if defined(__linux__) && defined(_REENTRANT)
1441 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1442 * thread handling in combination with using the alternate stack:
1443 * pthread library functions try to use the stack pointer to
1444 * identify the current thread, causing a SEGV signal, which
1445 * recursively calls deathtrap() and hangs. */
1446 sa.sa_flags = 0;
1447# else
1448 sa.sa_flags = SA_ONSTACK;
1449# endif
1450 sigaction(signal_info[i].sig, &sa, NULL);
1451#else
1452# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1453 struct sigvec sv;
1454
1455 /* Setup to use the alternate stack for the signal function. */
1456 sv.sv_handler = func_deadly;
1457 sv.sv_mask = 0;
1458 sv.sv_flags = SV_ONSTACK;
1459 sigvec(signal_info[i].sig, &sv, NULL);
1460# else
1461 signal(signal_info[i].sig, func_deadly);
1462# endif
1463#endif
1464 }
1465 else if (func_other != SIG_ERR)
1466 signal(signal_info[i].sig, func_other);
1467}
1468
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001469#ifdef HAVE_SIGPROCMASK
1470 static void
1471block_signals(sigset_t *set)
1472{
1473 sigset_t newset;
1474 int i;
1475
1476 sigemptyset(&newset);
1477
1478 for (i = 0; signal_info[i].sig != -1; i++)
1479 sigaddset(&newset, signal_info[i].sig);
1480
1481# if defined(_REENTRANT) && defined(SIGCONT)
1482 /* SIGCONT isn't in the list, because its default action is ignore */
1483 sigaddset(&newset, SIGCONT);
1484# endif
1485
1486 sigprocmask(SIG_BLOCK, &newset, set);
1487}
1488
1489 static void
1490unblock_signals(sigset_t *set)
1491{
1492 sigprocmask(SIG_SETMASK, set, NULL);
1493}
1494#endif
1495
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001497 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001498 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1499 * return TRUE
1500 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1501 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001502 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001503 * Returns TRUE when Vim should exit.
1504 */
1505 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001506vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001507{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001508 static int got_signal = 0;
1509 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001510
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001511 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001512 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001513 case SIGNAL_BLOCK: blocked = TRUE;
1514 break;
1515
1516 case SIGNAL_UNBLOCK: blocked = FALSE;
1517 if (got_signal != 0)
1518 {
1519 kill(getpid(), got_signal);
1520 got_signal = 0;
1521 }
1522 break;
1523
1524 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001525 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001526 got_signal = sig;
1527#ifdef SIGPWR
1528 if (sig != SIGPWR)
1529#endif
1530 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001531 break;
1532 }
1533 return FALSE;
1534}
1535
1536/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537 * Check_win checks whether we have an interactive stdout.
1538 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001540mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542 if (isatty(1))
1543 return OK;
1544 return FAIL;
1545}
1546
1547/*
1548 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1549 */
1550 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001551mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552{
1553 if (isatty(read_cmd_fd))
1554 return TRUE;
1555 return FALSE;
1556}
1557
1558#ifdef FEAT_X11
1559
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001560# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563/*
1564 * Give a message about the elapsed time for opening the X window.
1565 */
1566 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001567xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568{
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001569 smsg((char_u *)_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570}
1571# endif
1572#endif
1573
1574#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1575/*
1576 * A few functions shared by X11 title and clipboard code.
1577 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001578static int x_error_handler(Display *dpy, XErrorEvent *error_event);
1579static int x_error_check(Display *dpy, XErrorEvent *error_event);
1580static int x_connect_to_server(void);
1581static int test_x11_window(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582
1583static int got_x_error = FALSE;
1584
1585/*
1586 * X Error handler, otherwise X just exits! (very rude) -- webb
1587 */
1588 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001589x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001591 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592 STRCAT(IObuff, _("\nVim: Got X error\n"));
1593
1594 /* We cannot print a message and continue, because no X calls are allowed
1595 * here (causes my system to hang). Silently continuing might be an
1596 * alternative... */
1597 preserve_exit(); /* preserve files and exit */
1598
1599 return 0; /* NOTREACHED */
1600}
1601
1602/*
1603 * Another X Error handler, just used to check for errors.
1604 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001606x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607{
1608 got_x_error = TRUE;
1609 return 0;
1610}
1611
1612#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1613# if defined(HAVE_SETJMP_H)
1614/*
1615 * An X IO Error handler, used to catch error while opening the display.
1616 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001617static int x_IOerror_check(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001620x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621{
1622 /* This function should not return, it causes exit(). Longjump instead. */
1623 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001624# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001625 return 0; /* avoid the compiler complains about missing return value */
1626# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627}
1628# endif
1629
1630/*
1631 * An X IO Error handler, used to catch terminal errors.
1632 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001633static int x_IOerror_handler(Display *dpy);
1634static void may_restore_clipboard(void);
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001635static int xterm_dpy_was_reset = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001638x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639{
1640 xterm_dpy = NULL;
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001641 xterm_dpy_was_reset = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001642 x11_window = 0;
1643 x11_display = NULL;
1644 xterm_Shell = (Widget)0;
1645
1646 /* This function should not return, it causes exit(). Longjump instead. */
1647 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001648# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001649 return 0; /* avoid the compiler complains about missing return value */
1650# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001652
1653/*
1654 * If the X11 connection was lost try to restore it.
1655 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001656 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001657 */
1658 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001659may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001660{
1661 if (xterm_dpy_was_reset)
1662 {
1663 xterm_dpy_was_reset = FALSE;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001664
1665# ifndef LESSTIF_VERSION
1666 /* This has been reported to avoid Vim getting stuck. */
1667 if (app_context != (XtAppContext)NULL)
1668 {
1669 XtDestroyApplicationContext(app_context);
1670 app_context = (XtAppContext)NULL;
1671 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
1672 }
1673# endif
1674
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001675 setup_term_clip();
1676 get_x11_title(FALSE);
1677 }
1678}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679#endif
1680
1681/*
1682 * Return TRUE when connection to the X server is desired.
1683 */
1684 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001685x_connect_to_server(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687#if defined(FEAT_CLIENTSERVER)
1688 if (x_force_connect)
1689 return TRUE;
1690#endif
1691 if (x_no_connect)
1692 return FALSE;
1693
1694 /* Check for a match with "exclude:" from 'clipboard'. */
1695 if (clip_exclude_prog != NULL)
1696 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01001697 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698 return FALSE;
1699 }
1700 return TRUE;
1701}
1702
1703/*
1704 * Test if "dpy" and x11_window are valid by getting the window title.
1705 * I don't actually want it yet, so there may be a simpler call to use, but
1706 * this will cause the error handler x_error_check() to be called if anything
1707 * is wrong, such as the window pointer being invalid (as can happen when the
1708 * user changes his DISPLAY, but not his WINDOWID) -- webb
1709 */
1710 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001711test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712{
1713 int (*old_handler)();
1714 XTextProperty text_prop;
1715
1716 old_handler = XSetErrorHandler(x_error_check);
1717 got_x_error = FALSE;
1718 if (XGetWMName(dpy, x11_window, &text_prop))
1719 XFree((void *)text_prop.value);
1720 XSync(dpy, False);
1721 (void)XSetErrorHandler(old_handler);
1722
1723 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001724 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725
1726 return (got_x_error ? FAIL : OK);
1727}
1728#endif
1729
1730#ifdef FEAT_TITLE
1731
1732#ifdef FEAT_X11
1733
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001734static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735
1736/*
1737 * try to get x11 window and display
1738 *
1739 * return FAIL for failure, OK otherwise
1740 */
1741 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001742get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743{
1744 char *winid;
1745 static int result = -1;
1746#define XD_NONE 0 /* x11_display not set here */
1747#define XD_HERE 1 /* x11_display opened here */
1748#define XD_GUI 2 /* x11_display used from gui.dpy */
1749#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1750 static int x11_display_from = XD_NONE;
1751 static int did_set_error_handler = FALSE;
1752
1753 if (!did_set_error_handler)
1754 {
1755 /* X just exits if it finds an error otherwise! */
1756 (void)XSetErrorHandler(x_error_handler);
1757 did_set_error_handler = TRUE;
1758 }
1759
Bram Moolenaar9372a112005-12-06 19:59:18 +00001760#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 if (gui.in_use)
1762 {
1763 /*
1764 * If the X11 display was opened here before, for the window where Vim
1765 * was started, close that one now to avoid a memory leak.
1766 */
1767 if (x11_display_from == XD_HERE && x11_display != NULL)
1768 {
1769 XCloseDisplay(x11_display);
1770 x11_display_from = XD_NONE;
1771 }
1772 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1773 {
1774 x11_display_from = XD_GUI;
1775 return OK;
1776 }
1777 x11_display = NULL;
1778 return FAIL;
1779 }
1780 else if (x11_display_from == XD_GUI)
1781 {
1782 /* GUI must have stopped somehow, clear x11_display */
1783 x11_window = 0;
1784 x11_display = NULL;
1785 x11_display_from = XD_NONE;
1786 }
1787#endif
1788
1789 /* When started with the "-X" argument, don't try connecting. */
1790 if (!x_connect_to_server())
1791 return FAIL;
1792
1793 /*
1794 * If WINDOWID not set, should try another method to find out
1795 * what the current window number is. The only code I know for
1796 * this is very complicated.
1797 * We assume that zero is invalid for WINDOWID.
1798 */
1799 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1800 x11_window = (Window)atol(winid);
1801
1802#ifdef FEAT_XCLIPBOARD
1803 if (xterm_dpy != NULL && x11_window != 0)
1804 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001805 /* We may have checked it already, but Gnome terminal can move us to
1806 * another window, so we need to check every time. */
1807 if (x11_display_from != XD_XTERM)
1808 {
1809 /*
1810 * If the X11 display was opened here before, for the window where
1811 * Vim was started, close that one now to avoid a memory leak.
1812 */
1813 if (x11_display_from == XD_HERE && x11_display != NULL)
1814 XCloseDisplay(x11_display);
1815 x11_display = xterm_dpy;
1816 x11_display_from = XD_XTERM;
1817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 if (test_x11_window(x11_display) == FAIL)
1819 {
1820 /* probably bad $WINDOWID */
1821 x11_window = 0;
1822 x11_display = NULL;
1823 x11_display_from = XD_NONE;
1824 return FAIL;
1825 }
1826 return OK;
1827 }
1828#endif
1829
1830 if (x11_window == 0 || x11_display == NULL)
1831 result = -1;
1832
1833 if (result != -1) /* Have already been here and set this */
1834 return result; /* Don't do all these X calls again */
1835
1836 if (x11_window != 0 && x11_display == NULL)
1837 {
1838#ifdef SET_SIG_ALARM
1839 RETSIGTYPE (*sig_save)();
1840#endif
1841#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1842 struct timeval start_tv;
1843
1844 if (p_verbose > 0)
1845 gettimeofday(&start_tv, NULL);
1846#endif
1847
1848#ifdef SET_SIG_ALARM
1849 /*
1850 * Opening the Display may hang if the DISPLAY setting is wrong, or
1851 * the network connection is bad. Set an alarm timer to get out.
1852 */
1853 sig_alarm_called = FALSE;
1854 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1855 (RETSIGTYPE (*)())sig_alarm);
1856 alarm(2);
1857#endif
1858 x11_display = XOpenDisplay(NULL);
1859
1860#ifdef SET_SIG_ALARM
1861 alarm(0);
1862 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1863 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001864 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865#endif
1866 if (x11_display != NULL)
1867 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001868# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001870 {
1871 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001872 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001873 verbose_leave();
1874 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875# endif
1876 if (test_x11_window(x11_display) == FAIL)
1877 {
1878 /* Maybe window id is bad */
1879 x11_window = 0;
1880 XCloseDisplay(x11_display);
1881 x11_display = NULL;
1882 }
1883 else
1884 x11_display_from = XD_HERE;
1885 }
1886 }
1887 if (x11_window == 0 || x11_display == NULL)
1888 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001889
1890# ifdef FEAT_EVAL
1891 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1892# endif
1893
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 return (result = OK);
1895}
1896
1897/*
1898 * Determine original x11 Window Title
1899 */
1900 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001901get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001903 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904}
1905
1906/*
1907 * Determine original x11 Window icon
1908 */
1909 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001910get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911{
1912 int retval = FALSE;
1913
1914 retval = get_x11_thing(FALSE, test_only);
1915
1916 /* could not get old icon, use terminal name */
1917 if (oldicon == NULL && !test_only)
1918 {
1919 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001920 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001922 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 }
1924
1925 return retval;
1926}
1927
1928 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001929get_x11_thing(
1930 int get_title, /* get title string */
1931 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932{
1933 XTextProperty text_prop;
1934 int retval = FALSE;
1935 Status status;
1936
1937 if (get_x11_windis() == OK)
1938 {
1939 /* Get window/icon name if any */
1940 if (get_title)
1941 status = XGetWMName(x11_display, x11_window, &text_prop);
1942 else
1943 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1944
1945 /*
1946 * If terminal is xterm, then x11_window may be a child window of the
1947 * outer xterm window that actually contains the window/icon name, so
1948 * keep traversing up the tree until a window with a title/icon is
1949 * found.
1950 */
1951 /* Previously this was only done for xterm and alikes. I don't see a
1952 * reason why it would fail for other terminal emulators.
1953 * if (term_is_xterm) */
1954 {
1955 Window root;
1956 Window parent;
1957 Window win = x11_window;
1958 Window *children;
1959 unsigned int num_children;
1960
1961 while (!status || text_prop.value == NULL)
1962 {
1963 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1964 &num_children))
1965 break;
1966 if (children)
1967 XFree((void *)children);
1968 if (parent == root || parent == 0)
1969 break;
1970
1971 win = parent;
1972 if (get_title)
1973 status = XGetWMName(x11_display, win, &text_prop);
1974 else
1975 status = XGetWMIconName(x11_display, win, &text_prop);
1976 }
1977 }
1978 if (status && text_prop.value != NULL)
1979 {
1980 retval = TRUE;
1981 if (!test_only)
1982 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001983#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1984 if (text_prop.encoding == XA_STRING
1985# ifdef FEAT_MBYTE
1986 && !has_mbyte
1987# endif
1988 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 {
1990#endif
1991 if (get_title)
1992 oldtitle = vim_strsave((char_u *)text_prop.value);
1993 else
1994 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001995#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001996 }
1997 else
1998 {
1999 char **cl;
2000 Status transform_status;
2001 int n = 0;
2002
2003 transform_status = XmbTextPropertyToTextList(x11_display,
2004 &text_prop,
2005 &cl, &n);
2006 if (transform_status >= Success && n > 0 && cl[0])
2007 {
2008 if (get_title)
2009 oldtitle = vim_strsave((char_u *) cl[0]);
2010 else
2011 oldicon = vim_strsave((char_u *) cl[0]);
2012 XFreeStringList(cl);
2013 }
2014 else
2015 {
2016 if (get_title)
2017 oldtitle = vim_strsave((char_u *)text_prop.value);
2018 else
2019 oldicon = vim_strsave((char_u *)text_prop.value);
2020 }
2021 }
2022#endif
2023 }
2024 XFree((void *)text_prop.value);
2025 }
2026 }
2027 return retval;
2028}
2029
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002030/* Xutf8 functions are not avaialble on older systems. Note that on some
2031 * systems X_HAVE_UTF8_STRING may be defined in a header file but
2032 * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2033 * that and defines HAVE_XUTF8SETWMPROPERTIES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002035# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036# define USE_UTF8_STRING
2037# endif
2038#endif
2039
2040/*
2041 * Set x11 Window Title
2042 *
2043 * get_x11_windis() must be called before this and have returned OK
2044 */
2045 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002046set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047{
2048 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2049 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2050 * supported everywhere and STRING doesn't work for multi-byte titles.
2051 */
2052#ifdef USE_UTF8_STRING
2053 if (enc_utf8)
2054 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2055 NULL, NULL, 0, NULL, NULL, NULL);
2056 else
2057#endif
2058 {
2059#if XtSpecificationRelease >= 4
2060# ifdef FEAT_XFONTSET
2061 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2062 NULL, NULL, 0, NULL, NULL, NULL);
2063# else
2064 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002065 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066
2067 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002068 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069 XSetWMProperties(x11_display, x11_window, &text_prop,
2070 NULL, NULL, 0, NULL, NULL, NULL);
2071# endif
2072#else
2073 XStoreName(x11_display, x11_window, (char *)title);
2074#endif
2075 }
2076 XFlush(x11_display);
2077}
2078
2079/*
2080 * Set x11 Window icon
2081 *
2082 * get_x11_windis() must be called before this and have returned OK
2083 */
2084 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002085set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086{
2087 /* See above for comments about using X*SetWMProperties(). */
2088#ifdef USE_UTF8_STRING
2089 if (enc_utf8)
2090 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2091 NULL, 0, NULL, NULL, NULL);
2092 else
2093#endif
2094 {
2095#if XtSpecificationRelease >= 4
2096# ifdef FEAT_XFONTSET
2097 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2098 NULL, 0, NULL, NULL, NULL);
2099# else
2100 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002101 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002103 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2105 NULL, 0, NULL, NULL, NULL);
2106# endif
2107#else
2108 XSetIconName(x11_display, x11_window, (char *)icon);
2109#endif
2110 }
2111 XFlush(x11_display);
2112}
2113
2114#else /* FEAT_X11 */
2115
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002117get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118{
2119 return FALSE;
2120}
2121
2122 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002123get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124{
2125 if (!test_only)
2126 {
2127 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002128 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002130 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 }
2132 return FALSE;
2133}
2134
2135#endif /* FEAT_X11 */
2136
2137 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002138mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139{
2140 return get_x11_title(TRUE);
2141}
2142
2143 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002144mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145{
2146 return get_x11_icon(TRUE);
2147}
2148
2149/*
2150 * Set the window title and icon.
2151 */
2152 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002153mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154{
2155 int type = 0;
2156 static int recursive = 0;
2157
2158 if (T_NAME == NULL) /* no terminal name (yet) */
2159 return;
2160 if (title == NULL && icon == NULL) /* nothing to do */
2161 return;
2162
2163 /* When one of the X11 functions causes a deadly signal, we get here again
2164 * recursively. Avoid hanging then (something is probably locked). */
2165 if (recursive)
2166 return;
2167 ++recursive;
2168
2169 /*
2170 * if the window ID and the display is known, we may use X11 calls
2171 */
2172#ifdef FEAT_X11
2173 if (get_x11_windis() == OK)
2174 type = 1;
2175#else
2176# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2177 if (gui.in_use)
2178 type = 1;
2179# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180#endif
2181
2182 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002183 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 * than x11 calls, because the x11 calls don't always work
2185 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002186 if ((type || *T_TS != NUL) && title != NULL)
2187 {
2188 if (oldtitle == NULL
2189#ifdef FEAT_GUI
2190 && !gui.in_use
2191#endif
2192 ) /* first call but not in GUI, save title */
2193 (void)get_x11_title(FALSE);
2194
2195 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2196 term_settitle(title);
2197#ifdef FEAT_X11
2198 else
2199# ifdef FEAT_GUI_GTK
2200 if (!gui.in_use) /* don't do this if GTK+ is running */
2201# endif
2202 set_x11_title(title); /* x11 */
2203#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002204#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2206 else
2207 gui_mch_settitle(title, icon);
2208#endif
2209 did_set_title = TRUE;
2210 }
2211
2212 if ((type || *T_CIS != NUL) && icon != NULL)
2213 {
2214 if (oldicon == NULL
2215#ifdef FEAT_GUI
2216 && !gui.in_use
2217#endif
2218 ) /* first call, save icon */
2219 get_x11_icon(FALSE);
2220
2221 if (*T_CIS != NUL)
2222 {
2223 out_str(T_CIS); /* set icon start */
2224 out_str_nf(icon);
2225 out_str(T_CIE); /* set icon end */
2226 out_flush();
2227 }
2228#ifdef FEAT_X11
2229 else
2230# ifdef FEAT_GUI_GTK
2231 if (!gui.in_use) /* don't do this if GTK+ is running */
2232# endif
2233 set_x11_icon(icon); /* x11 */
2234#endif
2235 did_set_icon = TRUE;
2236 }
2237 --recursive;
2238}
2239
2240/*
2241 * Restore the window/icon title.
2242 * "which" is one of:
2243 * 1 only restore title
2244 * 2 only restore icon
2245 * 3 restore title and icon
2246 */
2247 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002248mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249{
2250 /* only restore the title or icon when it has been set */
2251 mch_settitle(((which & 1) && did_set_title) ?
2252 (oldtitle ? oldtitle : p_titleold) : NULL,
2253 ((which & 2) && did_set_icon) ? oldicon : NULL);
2254}
2255
2256#endif /* FEAT_TITLE */
2257
2258/*
2259 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002260 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 */
2262 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002263vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264{
2265 if (name == NULL)
2266 return FALSE;
2267 return (STRNICMP(name, "xterm", 5) == 0
2268 || STRNICMP(name, "nxterm", 6) == 0
2269 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002270 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002272 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 || STRCMP(name, "builtin_xterm") == 0);
2274}
2275
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002276#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2277/*
2278 * Return TRUE if "name" appears to be that of a terminal
2279 * known to support the xterm-style mouse protocol.
2280 * Relies on term_is_xterm having been set to its correct value.
2281 */
2282 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002283use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002284{
2285 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002286 && (term_is_xterm
2287 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002288 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002289 || STRICMP(name, "st") == 0
2290 || STRNICMP(name, "st-", 3) == 0
2291 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002292}
2293#endif
2294
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2296/*
2297 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2298 * Return 1 for "xterm".
2299 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002300 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002301 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302 */
2303 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002304use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002306 if (ttym_flags == TTYM_SGR)
2307 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002308 if (ttym_flags == TTYM_URXVT)
2309 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 if (ttym_flags == TTYM_XTERM2)
2311 return 2;
2312 if (ttym_flags == TTYM_XTERM)
2313 return 1;
2314 return 0;
2315}
2316#endif
2317
2318 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002319vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320{
2321 if (name == NULL)
2322 return FALSE;
2323 return (STRNICMP(name, "iris-ansi", 9) == 0
2324 || STRCMP(name, "builtin_iris-ansi") == 0);
2325}
2326
2327 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002328vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329{
2330 if (name == NULL)
2331 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002332 /* catch VT100 - VT5xx */
2333 return ((STRNICMP(name, "vt", 2) == 0
2334 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 || STRCMP(name, "builtin_vt320") == 0);
2336}
2337
2338/*
2339 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2340 * This should include all windowed terminal emulators.
2341 */
2342 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002343vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344{
2345 if (name == NULL)
2346 return FALSE;
2347 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2348 return TRUE;
2349 return ( STRNICMP(name, "hpterm", 6) == 0
2350 || STRNICMP(name, "sun-cmd", 7) == 0
2351 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002352 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 || STRNICMP(name, "dtterm", 6) == 0);
2354}
2355
2356/*
2357 * Insert user name in s[len].
2358 * Return OK if a name found.
2359 */
2360 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002361mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362{
2363#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002364 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 return OK;
2366#else
2367 return mch_get_uname(getuid(), s, len);
2368#endif
2369}
2370
2371/*
2372 * Insert user name for "uid" in s[len].
2373 * Return OK if a name found.
2374 */
2375 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002376mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377{
2378#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2379 struct passwd *pw;
2380
2381 if ((pw = getpwuid(uid)) != NULL
2382 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2383 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002384 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 return OK;
2386 }
2387#endif
2388 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2389 return FAIL; /* a number is not a name */
2390}
2391
2392/*
2393 * Insert host name is s[len].
2394 */
2395
2396#ifdef HAVE_SYS_UTSNAME_H
2397 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002398mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399{
2400 struct utsname vutsname;
2401
2402 if (uname(&vutsname) < 0)
2403 *s = NUL;
2404 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002405 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406}
2407#else /* HAVE_SYS_UTSNAME_H */
2408
2409# ifdef HAVE_SYS_SYSTEMINFO_H
2410# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2411# endif
2412
2413 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002414mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415{
2416# ifdef VAXC
2417 vaxc$gethostname((char *)s, len);
2418# else
2419 gethostname((char *)s, len);
2420# endif
2421 s[len - 1] = NUL; /* make sure it's terminated */
2422}
2423#endif /* HAVE_SYS_UTSNAME_H */
2424
2425/*
2426 * return process ID
2427 */
2428 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002429mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430{
2431 return (long)getpid();
2432}
2433
2434#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01002435static char *strerror(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436
2437 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002438strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439{
2440 extern int sys_nerr;
2441 extern char *sys_errlist[];
2442 static char er[20];
2443
2444 if (err > 0 && err < sys_nerr)
2445 return (sys_errlist[err]);
2446 sprintf(er, "Error %d", err);
2447 return er;
2448}
2449#endif
2450
2451/*
2452 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2453 * Return OK for success, FAIL for failure.
2454 */
2455 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002456mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457{
2458#if defined(USE_GETCWD)
2459 if (getcwd((char *)buf, len) == NULL)
2460 {
2461 STRCPY(buf, strerror(errno));
2462 return FAIL;
2463 }
2464 return OK;
2465#else
2466 return (getwd((char *)buf) != NULL ? OK : FAIL);
2467#endif
2468}
2469
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002471 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472 *
2473 * return FAIL for failure, OK for success
2474 */
2475 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002476mch_FullName(
2477 char_u *fname,
2478 char_u *buf,
2479 int len,
2480 int force) /* also expand when already absolute path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481{
2482 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002483#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484 int fd = -1;
2485 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002486#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 char_u olddir[MAXPATHL];
2488 char_u *p;
2489 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002490#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002491 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2492 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002493#endif
2494
Bram Moolenaar38323e42007-03-06 19:22:53 +00002495#ifdef VMS
2496 fname = vms_fixfilename(fname);
2497#endif
2498
Bram Moolenaara2442432007-04-26 14:26:37 +00002499#ifdef __CYGWIN__
2500 /*
2501 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2502 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002503# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar06b07342015-12-31 22:26:28 +01002504 /* Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2505 * a forward slash. */
2506 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2507 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002508# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002509 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002510# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002511 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002512#endif
2513
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002514 /* Expand it if forced or not an absolute path.
2515 * Do not do it for "/file", the result is always "/". */
2516 if ((force || !mch_isFullName(fname))
2517 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 {
2519 /*
2520 * If the file name has a path, change to that directory for a moment,
2521 * and then do the getwd() (and get back to where we were).
2522 * This will get the correct path name with "../" things.
2523 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002524 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002526#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 /*
2528 * Use fchdir() if possible, it's said to be faster and more
2529 * reliable. But on SunOS 4 it might not work. Check this by
2530 * doing a fchdir() right now.
2531 */
2532 if (!dont_fchdir)
2533 {
2534 fd = open(".", O_RDONLY | O_EXTRA, 0);
2535 if (fd >= 0 && fchdir(fd) < 0)
2536 {
2537 close(fd);
2538 fd = -1;
2539 dont_fchdir = TRUE; /* don't try again */
2540 }
2541 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002542#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543
2544 /* Only change directory when we are sure we can return to where
2545 * we are now. After doing "su" chdir(".") might not work. */
2546 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002547#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002549#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 (mch_dirname(olddir, MAXPATHL) == FAIL
2551 || mch_chdir((char *)olddir) != 0))
2552 {
2553 p = NULL; /* can't get current dir: don't chdir */
2554 retval = FAIL;
2555 }
2556 else
2557 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 /* The directory is copied into buf[], to be able to remove
2559 * the file name without changing it (could be a string in
2560 * read-only memory) */
2561 if (p - fname >= len)
2562 retval = FAIL;
2563 else
2564 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002565 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 if (mch_chdir((char *)buf))
2567 retval = FAIL;
2568 else
2569 fname = p + 1;
2570 *buf = NUL;
2571 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 }
2573 }
2574 if (mch_dirname(buf, len) == FAIL)
2575 {
2576 retval = FAIL;
2577 *buf = NUL;
2578 }
2579 if (p != NULL)
2580 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002581#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 if (fd >= 0)
2583 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002584 if (p_verbose >= 5)
2585 {
2586 verbose_enter();
2587 MSG("fchdir() to previous dir");
2588 verbose_leave();
2589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 l = fchdir(fd);
2591 close(fd);
2592 }
2593 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002594#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595 l = mch_chdir((char *)olddir);
2596 if (l != 0)
2597 EMSG(_(e_prev_dir));
2598 }
2599
2600 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002601 if (l >= len - 1)
2602 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002603#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002604 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002606 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002607#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002609
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002611 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 return FAIL;
2613
2614 /* Do not append ".", "/dir/." is equal to "/dir". */
2615 if (STRCMP(fname, ".") != 0)
2616 STRCAT(buf, fname);
2617
2618 return OK;
2619}
2620
2621/*
2622 * Return TRUE if "fname" does not depend on the current directory.
2623 */
2624 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002625mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002627#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 return ( fname[0] == '/' || fname[0] == '.' ||
2629 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2630 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2631 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002632#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634#endif
2635}
2636
Bram Moolenaar24552be2005-12-10 20:17:30 +00002637#if defined(USE_FNAME_CASE) || defined(PROTO)
2638/*
2639 * Set the case of the file name, if it already exists. This will cause the
2640 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002641 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002642 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002643 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002644fname_case(
2645 char_u *name,
2646 int len UNUSED) /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002647{
2648 struct stat st;
2649 char_u *slash, *tail;
2650 DIR *dirp;
2651 struct dirent *dp;
2652
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002653 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002654 {
2655 /* Open the directory where the file is located. */
2656 slash = vim_strrchr(name, '/');
2657 if (slash == NULL)
2658 {
2659 dirp = opendir(".");
2660 tail = name;
2661 }
2662 else
2663 {
2664 *slash = NUL;
2665 dirp = opendir((char *)name);
2666 *slash = '/';
2667 tail = slash + 1;
2668 }
2669
2670 if (dirp != NULL)
2671 {
2672 while ((dp = readdir(dirp)) != NULL)
2673 {
2674 /* Only accept names that differ in case and are the same byte
2675 * length. TODO: accept different length name. */
2676 if (STRICMP(tail, dp->d_name) == 0
2677 && STRLEN(tail) == STRLEN(dp->d_name))
2678 {
2679 char_u newname[MAXPATHL + 1];
2680 struct stat st2;
2681
2682 /* Verify the inode is equal. */
2683 vim_strncpy(newname, name, MAXPATHL);
2684 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2685 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002686 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002687 && st.st_ino == st2.st_ino
2688 && st.st_dev == st2.st_dev)
2689 {
2690 STRCPY(tail, dp->d_name);
2691 break;
2692 }
2693 }
2694 }
2695
2696 closedir(dirp);
2697 }
2698 }
2699}
2700#endif
2701
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702/*
2703 * Get file permissions for 'name'.
2704 * Returns -1 when it doesn't exist.
2705 */
2706 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002707mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708{
2709 struct stat statb;
2710
2711 /* Keep the #ifdef outside of stat(), it may be a macro. */
2712#ifdef VMS
2713 if (stat((char *)vms_fixfilename(name), &statb))
2714#else
2715 if (stat((char *)name, &statb))
2716#endif
2717 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002718#ifdef __INTERIX
2719 /* The top bit makes the value negative, which means the file doesn't
2720 * exist. Remove the bit, we don't use it. */
2721 return statb.st_mode & ~S_ADDACE;
2722#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002724#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725}
2726
2727/*
2728 * set file permission for 'name' to 'perm'
2729 *
2730 * return FAIL for failure, OK otherwise
2731 */
2732 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002733mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734{
2735 return (chmod((char *)
2736#ifdef VMS
2737 vms_fixfilename(name),
2738#else
2739 name,
2740#endif
2741 (mode_t)perm) == 0 ? OK : FAIL);
2742}
2743
2744#if defined(HAVE_ACL) || defined(PROTO)
2745# ifdef HAVE_SYS_ACL_H
2746# include <sys/acl.h>
2747# endif
2748# ifdef HAVE_SYS_ACCESS_H
2749# include <sys/access.h>
2750# endif
2751
2752# ifdef HAVE_SOLARIS_ACL
2753typedef struct vim_acl_solaris_T {
2754 int acl_cnt;
2755 aclent_t *acl_entry;
2756} vim_acl_solaris_T;
2757# endif
2758
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002759#if defined(HAVE_SELINUX) || defined(PROTO)
2760/*
2761 * Copy security info from "from_file" to "to_file".
2762 */
2763 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002764mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002765{
2766 if (from_file == NULL)
2767 return;
2768
2769 if (selinux_enabled == -1)
2770 selinux_enabled = is_selinux_enabled();
2771
2772 if (selinux_enabled > 0)
2773 {
2774 security_context_t from_context = NULL;
2775 security_context_t to_context = NULL;
2776
2777 if (getfilecon((char *)from_file, &from_context) < 0)
2778 {
2779 /* If the filesystem doesn't support extended attributes,
2780 the original had no special security context and the
2781 target cannot have one either. */
2782 if (errno == EOPNOTSUPP)
2783 return;
2784
2785 MSG_PUTS(_("\nCould not get security context for "));
2786 msg_outtrans(from_file);
2787 msg_putchar('\n');
2788 return;
2789 }
2790 if (getfilecon((char *)to_file, &to_context) < 0)
2791 {
2792 MSG_PUTS(_("\nCould not get security context for "));
2793 msg_outtrans(to_file);
2794 msg_putchar('\n');
2795 freecon (from_context);
2796 return ;
2797 }
2798 if (strcmp(from_context, to_context) != 0)
2799 {
2800 if (setfilecon((char *)to_file, from_context) < 0)
2801 {
2802 MSG_PUTS(_("\nCould not set security context for "));
2803 msg_outtrans(to_file);
2804 msg_putchar('\n');
2805 }
2806 }
2807 freecon(to_context);
2808 freecon(from_context);
2809 }
2810}
2811#endif /* HAVE_SELINUX */
2812
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002813#if defined(HAVE_SMACK) && !defined(PROTO)
2814/*
2815 * Copy security info from "from_file" to "to_file".
2816 */
2817 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002818mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002819{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002820 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002821 {
2822 XATTR_NAME_SMACK,
2823 XATTR_NAME_SMACKEXEC,
2824 XATTR_NAME_SMACKMMAP
2825 };
2826
2827 char buffer[SMACK_LABEL_LEN];
2828 const char *name;
2829 int index;
2830 int ret;
2831 ssize_t size;
2832
2833 if (from_file == NULL)
2834 return;
2835
2836 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2837 / sizeof(smack_copied_attributes)[0]) ; index++)
2838 {
2839 /* get the name of the attribute to copy */
2840 name = smack_copied_attributes[index];
2841
2842 /* get the value of the attribute in buffer */
2843 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2844 if (size >= 0)
2845 {
2846 /* copy the attribute value of buffer */
2847 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2848 if (ret < 0)
2849 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002850 vim_snprintf((char *)IObuff, IOSIZE,
2851 _("Could not set security context %s for %s"),
2852 name, to_file);
2853 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002854 msg_putchar('\n');
2855 }
2856 }
2857 else
2858 {
2859 /* what reason of not having the attribute value? */
2860 switch (errno)
2861 {
2862 case ENOTSUP:
2863 /* extended attributes aren't supported or enabled */
2864 /* should a message be echoed? not sure... */
2865 return; /* leave because it isn't usefull to continue */
2866
2867 case ERANGE:
2868 default:
2869 /* no enough size OR unexpected error */
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002870 vim_snprintf((char *)IObuff, IOSIZE,
2871 _("Could not get security context %s for %s. Removing it!"),
2872 name, from_file);
2873 msg_puts(IObuff);
2874 msg_putchar('\n');
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002875 /* FALLTHROUGH to remove the attribute */
2876
2877 case ENODATA:
2878 /* no attribute of this name */
2879 ret = removexattr((char*)to_file, name);
Bram Moolenaar57a728d2014-04-02 23:09:26 +02002880 /* Silently ignore errors, apparently this happens when
2881 * smack is not actually being used. */
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002882 break;
2883 }
2884 }
2885 }
2886}
2887#endif /* HAVE_SMACK */
2888
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889/*
2890 * Return a pointer to the ACL of file "fname" in allocated memory.
2891 * Return NULL if the ACL is not available for whatever reason.
2892 */
2893 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002894mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895{
2896 vim_acl_T ret = NULL;
2897#ifdef HAVE_POSIX_ACL
2898 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2899#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002900#ifdef HAVE_SOLARIS_ZFS_ACL
2901 acl_t *aclent;
2902
2903 if (acl_get((char *)fname, 0, &aclent) < 0)
2904 return NULL;
2905 ret = (vim_acl_T)aclent;
2906#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907#ifdef HAVE_SOLARIS_ACL
2908 vim_acl_solaris_T *aclent;
2909
2910 aclent = malloc(sizeof(vim_acl_solaris_T));
2911 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2912 {
2913 free(aclent);
2914 return NULL;
2915 }
2916 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2917 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2918 {
2919 free(aclent->acl_entry);
2920 free(aclent);
2921 return NULL;
2922 }
2923 ret = (vim_acl_T)aclent;
2924#else
2925#if defined(HAVE_AIX_ACL)
2926 int aclsize;
2927 struct acl *aclent;
2928
2929 aclsize = sizeof(struct acl);
2930 aclent = malloc(aclsize);
2931 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2932 {
2933 if (errno == ENOSPC)
2934 {
2935 aclsize = aclent->acl_len;
2936 aclent = realloc(aclent, aclsize);
2937 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2938 {
2939 free(aclent);
2940 return NULL;
2941 }
2942 }
2943 else
2944 {
2945 free(aclent);
2946 return NULL;
2947 }
2948 }
2949 ret = (vim_acl_T)aclent;
2950#endif /* HAVE_AIX_ACL */
2951#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002952#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953#endif /* HAVE_POSIX_ACL */
2954 return ret;
2955}
2956
2957/*
2958 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2959 */
2960 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002961mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962{
2963 if (aclent == NULL)
2964 return;
2965#ifdef HAVE_POSIX_ACL
2966 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2967#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002968#ifdef HAVE_SOLARIS_ZFS_ACL
2969 acl_set((char *)fname, (acl_t *)aclent);
2970#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971#ifdef HAVE_SOLARIS_ACL
2972 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2973 ((vim_acl_solaris_T *)aclent)->acl_entry);
2974#else
2975#ifdef HAVE_AIX_ACL
2976 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2977#endif /* HAVE_AIX_ACL */
2978#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002979#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980#endif /* HAVE_POSIX_ACL */
2981}
2982
2983 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002984mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985{
2986 if (aclent == NULL)
2987 return;
2988#ifdef HAVE_POSIX_ACL
2989 acl_free((acl_t)aclent);
2990#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002991#ifdef HAVE_SOLARIS_ZFS_ACL
2992 acl_free((acl_t *)aclent);
2993#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994#ifdef HAVE_SOLARIS_ACL
2995 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2996 free(aclent);
2997#else
2998#ifdef HAVE_AIX_ACL
2999 free(aclent);
3000#endif /* HAVE_AIX_ACL */
3001#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003002#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003#endif /* HAVE_POSIX_ACL */
3004}
3005#endif
3006
3007/*
3008 * Set hidden flag for "name".
3009 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003011mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012{
3013 /* can't hide a file */
3014}
3015
3016/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003017 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 * return FALSE if "name" is not a directory
3019 * return FALSE for error
3020 */
3021 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003022mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023{
3024 struct stat statb;
3025
3026 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3027 return FALSE;
3028 if (stat((char *)name, &statb))
3029 return FALSE;
3030#ifdef _POSIX_SOURCE
3031 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
3032#else
3033 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
3034#endif
3035}
3036
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003037/*
3038 * return TRUE if "name" is a directory, NOT a symlink to a directory
3039 * return FALSE if "name" is not a directory
3040 * return FALSE for error
3041 */
3042 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003043mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003044{
3045 struct stat statb;
3046
3047 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3048 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003049 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003050 return FALSE;
3051#ifdef _POSIX_SOURCE
3052 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
3053#else
3054 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
3055#endif
3056}
3057
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003058static int executable_file(char_u *name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
3060/*
3061 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3062 */
3063 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003064executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065{
3066 struct stat st;
3067
3068 if (stat((char *)name, &st))
3069 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003070#ifdef VMS
3071 /* Like on Unix system file can have executable rights but not necessarily
3072 * be an executable, but on Unix is not a default for an ordianry file to
3073 * have an executable flag - on VMS it is in most cases.
3074 * Therefore, this check does not have any sense - let keep us to the
3075 * conventions instead:
3076 * *.COM and *.EXE files are the executables - the rest are not. This is
3077 * not ideal but better then it was.
3078 */
3079 int vms_executable = 0;
3080 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3081 {
3082 if (strstr(vms_tolower((char*)name),".exe") != NULL
3083 || strstr(vms_tolower((char*)name),".com")!= NULL)
3084 vms_executable = 1;
3085 }
3086 return vms_executable;
3087#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003089#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090}
3091
3092/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003093 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003094 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 * Return -1 if unknown.
3096 */
3097 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003098mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099{
3100 char_u *buf;
3101 char_u *p, *e;
3102 int retval;
3103
Bram Moolenaarb5971142015-03-21 17:32:19 +01003104 /* When "use_path" is false and if it's an absolute or relative path don't
3105 * need to use $PATH. */
3106 if (!use_path || mch_isFullName(name) || (name[0] == '.'
3107 && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003108 {
Bram Moolenaarb5971142015-03-21 17:32:19 +01003109 /* There must be a path separator, files in the current directory
3110 * can't be executed. */
3111 if (gettail(name) != name && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003112 {
3113 if (path != NULL)
3114 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003115 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003116 *path = FullName_save(name, TRUE);
3117 else
3118 *path = vim_strsave(name);
3119 }
3120 return TRUE;
3121 }
3122 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003123 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124
3125 p = (char_u *)getenv("PATH");
3126 if (p == NULL || *p == NUL)
3127 return -1;
3128 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3129 if (buf == NULL)
3130 return -1;
3131
3132 /*
3133 * Walk through all entries in $PATH to check if "name" exists there and
3134 * is an executable file.
3135 */
3136 for (;;)
3137 {
3138 e = (char_u *)strchr((char *)p, ':');
3139 if (e == NULL)
3140 e = p + STRLEN(p);
3141 if (e - p <= 1) /* empty entry means current dir */
3142 STRCPY(buf, "./");
3143 else
3144 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003145 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 add_pathsep(buf);
3147 }
3148 STRCAT(buf, name);
3149 retval = executable_file(buf);
3150 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003151 {
3152 if (path != NULL)
3153 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003154 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003155 *path = FullName_save(buf, TRUE);
3156 else
3157 *path = vim_strsave(buf);
3158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003160 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161
3162 if (*e != ':')
3163 break;
3164 p = e + 1;
3165 }
3166
3167 vim_free(buf);
3168 return retval;
3169}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170
3171/*
3172 * Check what "name" is:
3173 * NODE_NORMAL: file or directory (or doesn't exist)
3174 * NODE_WRITABLE: writable device, socket, fifo, etc.
3175 * NODE_OTHER: non-writable things
3176 */
3177 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003178mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179{
3180 struct stat st;
3181
3182 if (stat((char *)name, &st))
3183 return NODE_NORMAL;
3184 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3185 return NODE_NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3187 return NODE_OTHER;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188 /* Everything else is writable? */
3189 return NODE_WRITABLE;
3190}
3191
3192 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003193mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194{
3195#ifdef HAVE_CHECK_STACK_GROWTH
3196 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 check_stack_growth((char *)&i);
3199
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003200# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201 get_stack_limit();
3202# endif
3203
3204#endif
3205
3206 /*
3207 * Setup an alternative stack for signals. Helps to catch signals when
3208 * running out of stack space.
3209 * Use of sigaltstack() is preferred, it's more portable.
3210 * Ignore any errors.
3211 */
3212#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003213 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 init_signal_stack();
3215#endif
3216}
3217
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003218#if defined(EXITFREE) || defined(PROTO)
3219 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003220mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003221{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003222# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3223 if (clip_star.owned)
3224 clip_lose_selection(&clip_star);
3225 if (clip_plus.owned)
3226 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003227# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003228# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003229 if (xterm_Shell != (Widget)0)
3230 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003231# ifndef LESSTIF_VERSION
3232 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003233 if (xterm_dpy != NULL)
3234 XtCloseDisplay(xterm_dpy);
3235 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003236 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003237 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003238# ifdef FEAT_X11
3239 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3240# endif
3241 }
3242# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003243# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003244# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003245 if (x11_display != NULL
3246# ifdef FEAT_XCLIPBOARD
3247 && x11_display != xterm_dpy
3248# endif
3249 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003250 XCloseDisplay(x11_display);
3251# endif
3252# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3253 vim_free(signal_stack);
3254 signal_stack = NULL;
3255# endif
3256# ifdef FEAT_TITLE
3257 vim_free(oldtitle);
3258 vim_free(oldicon);
3259# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003260}
3261#endif
3262
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003263static void exit_scroll(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264
3265/*
3266 * Output a newline when exiting.
3267 * Make sure the newline goes to the same stream as the text.
3268 */
3269 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003270exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003272 if (silent_mode)
3273 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274 if (newline_on_exit || msg_didout)
3275 {
3276 if (msg_use_printf())
3277 {
3278 if (info_message)
3279 mch_msg("\n");
3280 else
3281 mch_errmsg("\r\n");
3282 }
3283 else
3284 out_char('\n');
3285 }
3286 else
3287 {
3288 restore_cterm_colors(); /* get original colors back */
3289 msg_clr_eos_force(); /* clear the rest of the display */
3290 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3291 }
3292}
3293
3294 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003295mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296{
3297 exiting = TRUE;
3298
3299#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3300 x11_export_final_selection();
3301#endif
3302
3303#ifdef FEAT_GUI
3304 if (!gui.in_use)
3305#endif
3306 {
3307 settmode(TMODE_COOK);
3308#ifdef FEAT_TITLE
3309 mch_restore_title(3); /* restore xterm title and icon name */
3310#endif
3311 /*
3312 * When t_ti is not empty but it doesn't cause swapping terminal
3313 * pages, need to output a newline when msg_didout is set. But when
3314 * t_ti does swap pages it should not go to the shell page. Do this
3315 * before stoptermcap().
3316 */
3317 if (swapping_screen() && !newline_on_exit)
3318 exit_scroll();
3319
3320 /* Stop termcap: May need to check for T_CRV response, which
3321 * requires RAW mode. */
3322 stoptermcap();
3323
3324 /*
3325 * A newline is only required after a message in the alternate screen.
3326 * This is set to TRUE by wait_return().
3327 */
3328 if (!swapping_screen() || newline_on_exit)
3329 exit_scroll();
3330
3331 /* Cursor may have been switched off without calling starttermcap()
3332 * when doing "vim -u vimrc" and vimrc contains ":q". */
3333 if (full_screen)
3334 cursor_on();
3335 }
3336 out_flush();
3337 ml_close_all(TRUE); /* remove all memfiles */
3338 may_core_dump();
3339#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 gui_exit(r);
3342#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003343
Bram Moolenaar56718732006-03-15 22:53:57 +00003344#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003345 mac_conv_cleanup();
3346#endif
3347
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348#ifdef __QNX__
3349 /* A core dump won't be created if the signal handler
3350 * doesn't return, so we can't call exit() */
3351 if (deadly_signal != 0)
3352 return;
3353#endif
3354
Bram Moolenaar009b2592004-10-24 19:18:58 +00003355#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003356 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003357#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003358
3359#ifdef EXITFREE
3360 free_all_mem();
3361#endif
3362
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 exit(r);
3364}
3365
3366 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003367may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368{
3369 if (deadly_signal != 0)
3370 {
3371 signal(deadly_signal, SIG_DFL);
3372 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3373 }
3374}
3375
3376#ifndef VMS
3377
3378 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003379mch_settmode(int tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380{
3381 static int first = TRUE;
3382
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003383#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384# ifdef HAVE_TERMIOS_H
3385 static struct termios told;
3386 struct termios tnew;
3387# else
3388 static struct termio told;
3389 struct termio tnew;
3390# endif
3391
3392 if (first)
3393 {
3394 first = FALSE;
3395# if defined(HAVE_TERMIOS_H)
3396 tcgetattr(read_cmd_fd, &told);
3397# else
3398 ioctl(read_cmd_fd, TCGETA, &told);
3399# endif
3400 }
3401
3402 tnew = told;
3403 if (tmode == TMODE_RAW)
3404 {
3405 /*
3406 * ~ICRNL enables typing ^V^M
3407 */
3408 tnew.c_iflag &= ~ICRNL;
3409 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3410# if defined(IEXTEN) && !defined(__MINT__)
3411 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3412 /* but it breaks function keys on MINT */
3413# endif
3414 );
3415# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3416 tnew.c_oflag &= ~ONLCR;
3417# endif
3418 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3419 tnew.c_cc[VTIME] = 0; /* don't wait */
3420 }
3421 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003422 {
3423 /* Also reset ICANON here, otherwise on Solaris select() won't see
3424 * typeahead characters. */
3425 tnew.c_lflag &= ~(ICANON | ECHO);
3426 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3427 tnew.c_cc[VTIME] = 0; /* don't wait */
3428 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429
3430# if defined(HAVE_TERMIOS_H)
3431 {
3432 int n = 10;
3433
3434 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3435 * few times. */
3436 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3437 && errno == EINTR && n > 0)
3438 --n;
3439 }
3440# else
3441 ioctl(read_cmd_fd, TCSETA, &tnew);
3442# endif
3443
3444#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 /*
3446 * for "old" tty systems
3447 */
3448# ifndef TIOCSETN
3449# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3450# endif
3451 static struct sgttyb ttybold;
3452 struct sgttyb ttybnew;
3453
3454 if (first)
3455 {
3456 first = FALSE;
3457 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3458 }
3459
3460 ttybnew = ttybold;
3461 if (tmode == TMODE_RAW)
3462 {
3463 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3464 ttybnew.sg_flags |= RAW;
3465 }
3466 else if (tmode == TMODE_SLEEP)
3467 ttybnew.sg_flags &= ~(ECHO);
3468 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3469#endif
3470 curr_tmode = tmode;
3471}
3472
3473/*
3474 * Try to get the code for "t_kb" from the stty setting
3475 *
3476 * Even if termcap claims a backspace key, the user's setting *should*
3477 * prevail. stty knows more about reality than termcap does, and if
3478 * somebody's usual erase key is DEL (which, for most BSD users, it will
3479 * be), they're going to get really annoyed if their erase key starts
3480 * doing forward deletes for no reason. (Eric Fischer)
3481 */
3482 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003483get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003485 ttyinfo_T info;
3486 char_u buf[2];
3487 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003489 if (get_tty_info(read_cmd_fd, &info) == OK)
3490 {
3491 intr_char = info.interrupt;
3492 buf[0] = info.backspace;
3493 buf[1] = NUL;
3494 add_termcode((char_u *)"kb", buf, FALSE);
3495
3496 /* If <BS> and <DEL> are now the same, redefine <DEL>. */
3497 p = find_termcode((char_u *)"kD");
3498 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3499 do_fixdel(NULL);
3500 }
3501}
3502
3503/*
3504 * Obtain the characters that Backspace and Enter produce on "fd".
3505 * Returns OK or FAIL.
3506 */
3507 int
3508get_tty_info(int fd, ttyinfo_T *info)
3509{
3510#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511# ifdef HAVE_TERMIOS_H
3512 struct termios keys;
3513# else
3514 struct termio keys;
3515# endif
3516
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003517 if (
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518# if defined(HAVE_TERMIOS_H)
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003519 tcgetattr(fd, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520# else
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003521 ioctl(fd, TCGETA, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522# endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003523 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003525 info->backspace = keys.c_cc[VERASE];
3526 info->interrupt = keys.c_cc[VINTR];
3527 if (keys.c_iflag & ICRNL)
3528 info->enter = NL;
3529 else
3530 info->enter = CAR;
3531 if (keys.c_oflag & ONLCR)
3532 info->nl_does_cr = TRUE;
3533 else
3534 info->nl_does_cr = FALSE;
3535 return OK;
3536 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537#else
3538 /* for "old" tty systems */
3539 struct sgttyb keys;
3540
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003541 if (ioctl(fd, TIOCGETP, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003543 info->backspace = keys.sg_erase;
3544 info->interrupt = keys.sg_kill;
3545 info->enter = CAR;
3546 info->nl_does_cr = TRUE;
3547 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003550 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551}
3552
3553#endif /* VMS */
3554
3555#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3556/*
3557 * Set mouse clicks on or off.
3558 */
3559 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003560mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561{
3562 static int ison = FALSE;
3563 int xterm_mouse_vers;
3564
3565 if (on == ison) /* return quickly if nothing to do */
3566 return;
3567
3568 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003569
3570# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003571 if (ttym_flags == TTYM_URXVT)
3572 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003573 out_str_nf((char_u *)
3574 (on
3575 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3576 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3577 ison = on;
3578 }
3579# endif
3580
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003581# ifdef FEAT_MOUSE_SGR
3582 if (ttym_flags == TTYM_SGR)
3583 {
3584 out_str_nf((char_u *)
3585 (on
3586 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3587 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3588 ison = on;
3589 }
3590# endif
3591
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 if (xterm_mouse_vers > 0)
3593 {
3594 if (on) /* enable mouse events, use mouse tracking if available */
3595 out_str_nf((char_u *)
3596 (xterm_mouse_vers > 1
3597 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3598 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3599 else /* disable mouse events, could probably always send the same */
3600 out_str_nf((char_u *)
3601 (xterm_mouse_vers > 1
3602 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3603 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3604 ison = on;
3605 }
3606
3607# ifdef FEAT_MOUSE_DEC
3608 else if (ttym_flags == TTYM_DEC)
3609 {
3610 if (on) /* enable mouse events */
3611 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3612 else /* disable mouse events */
3613 out_str_nf((char_u *)"\033['z");
3614 ison = on;
3615 }
3616# endif
3617
3618# ifdef FEAT_MOUSE_GPM
3619 else
3620 {
3621 if (on)
3622 {
3623 if (gpm_open())
3624 ison = TRUE;
3625 }
3626 else
3627 {
3628 gpm_close();
3629 ison = FALSE;
3630 }
3631 }
3632# endif
3633
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003634# ifdef FEAT_SYSMOUSE
3635 else
3636 {
3637 if (on)
3638 {
3639 if (sysmouse_open() == OK)
3640 ison = TRUE;
3641 }
3642 else
3643 {
3644 sysmouse_close();
3645 ison = FALSE;
3646 }
3647 }
3648# endif
3649
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650# ifdef FEAT_MOUSE_JSB
3651 else
3652 {
3653 if (on)
3654 {
3655 /* D - Enable Mouse up/down messages
3656 * L - Enable Left Button Reporting
3657 * M - Enable Middle Button Reporting
3658 * R - Enable Right Button Reporting
3659 * K - Enable SHIFT and CTRL key Reporting
3660 * + - Enable Advanced messaging of mouse moves and up/down messages
3661 * Q - Quiet No Ack
3662 * # - Numeric value of mouse pointer required
3663 * 0 = Multiview 2000 cursor, used as standard
3664 * 1 = Windows Arrow
3665 * 2 = Windows I Beam
3666 * 3 = Windows Hour Glass
3667 * 4 = Windows Cross Hair
3668 * 5 = Windows UP Arrow
3669 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003670# ifdef JSBTERM_MOUSE_NONADVANCED
3671 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3673 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003674# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3676 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003677# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 ison = TRUE;
3679 }
3680 else
3681 {
3682 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3683 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3684 ison = FALSE;
3685 }
3686 }
3687# endif
3688# ifdef FEAT_MOUSE_PTERM
3689 else
3690 {
3691 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3692 if (on)
3693 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3694 else
3695 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3696 ison = on;
3697 }
3698# endif
3699}
3700
3701/*
3702 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3703 */
3704 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003705check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706{
3707# ifdef FEAT_MOUSE_XTERM
3708 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003709# ifdef FEAT_MOUSE_URXVT
3710 && use_xterm_mouse() != 3
3711# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712# ifdef FEAT_GUI
3713 && !gui.in_use
3714# endif
3715 )
3716 {
3717 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003718 ? IF_EB("\233M", CSI_STR "M")
3719 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 if (*p_mouse != NUL)
3721 {
3722 /* force mouse off and maybe on to send possibly new mouse
3723 * activation sequence to the xterm, with(out) drag tracing. */
3724 mch_setmouse(FALSE);
3725 setmouse();
3726 }
3727 }
3728 else
3729 del_mouse_termcode(KS_MOUSE);
3730# endif
3731
3732# ifdef FEAT_MOUSE_GPM
3733 if (!use_xterm_mouse()
3734# ifdef FEAT_GUI
3735 && !gui.in_use
3736# endif
3737 )
3738 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3739# endif
3740
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003741# ifdef FEAT_SYSMOUSE
3742 if (!use_xterm_mouse()
3743# ifdef FEAT_GUI
3744 && !gui.in_use
3745# endif
3746 )
3747 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3748# endif
3749
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750# ifdef FEAT_MOUSE_JSB
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003751 /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752 if (!use_xterm_mouse()
3753# ifdef FEAT_GUI
3754 && !gui.in_use
3755# endif
3756 )
3757 set_mouse_termcode(KS_JSBTERM_MOUSE,
3758 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3759 else
3760 del_mouse_termcode(KS_JSBTERM_MOUSE);
3761# endif
3762
3763# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003764 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 * define it in the GUI or when using an xterm. */
3766 if (!use_xterm_mouse()
3767# ifdef FEAT_GUI
3768 && !gui.in_use
3769# endif
3770 )
3771 set_mouse_termcode(KS_NETTERM_MOUSE,
3772 (char_u *)IF_EB("\033}", ESC_STR "}"));
3773 else
3774 del_mouse_termcode(KS_NETTERM_MOUSE);
3775# endif
3776
3777# ifdef FEAT_MOUSE_DEC
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003778 /* Conflicts with xterm mouse: "\033[" and "\033[M" */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003779 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780# ifdef FEAT_GUI
3781 && !gui.in_use
3782# endif
3783 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003784 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3785 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786 else
3787 del_mouse_termcode(KS_DEC_MOUSE);
3788# endif
3789# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003790 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003791 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792# ifdef FEAT_GUI
3793 && !gui.in_use
3794# endif
3795 )
3796 set_mouse_termcode(KS_PTERM_MOUSE,
3797 (char_u *) IF_EB("\033[", ESC_STR "["));
3798 else
3799 del_mouse_termcode(KS_PTERM_MOUSE);
3800# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003801# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003802 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003803# ifdef FEAT_GUI
3804 && !gui.in_use
3805# endif
3806 )
3807 {
3808 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003809 ? IF_EB("\233*M", CSI_STR "*M")
3810 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003811
3812 if (*p_mouse != NUL)
3813 {
3814 mch_setmouse(FALSE);
3815 setmouse();
3816 }
3817 }
3818 else
3819 del_mouse_termcode(KS_URXVT_MOUSE);
3820# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003821# ifdef FEAT_MOUSE_SGR
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003822 if (use_xterm_mouse() == 4
3823# ifdef FEAT_GUI
3824 && !gui.in_use
3825# endif
3826 )
3827 {
3828 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003829 ? IF_EB("\233<*M", CSI_STR "<*M")
3830 : IF_EB("\033[<*M", ESC_STR "[<*M")));
3831
3832 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
3833 ? IF_EB("\233<*m", CSI_STR "<*m")
3834 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003835
3836 if (*p_mouse != NUL)
3837 {
3838 mch_setmouse(FALSE);
3839 setmouse();
3840 }
3841 }
3842 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02003843 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003844 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02003845 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
3846 }
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003847# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848}
3849#endif
3850
3851/*
3852 * set screen mode, always fails.
3853 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003855mch_screenmode(char_u *arg UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856{
3857 EMSG(_(e_screenmode));
3858 return FAIL;
3859}
3860
3861#ifndef VMS
3862
3863/*
3864 * Try to get the current window size:
3865 * 1. with an ioctl(), most accurate method
3866 * 2. from the environment variables LINES and COLUMNS
3867 * 3. from the termcap
3868 * 4. keep using the old values
3869 * Return OK when size could be determined, FAIL otherwise.
3870 */
3871 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003872mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873{
3874 long rows = 0;
3875 long columns = 0;
3876 char_u *p;
3877
3878 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879 * 1. try using an ioctl. It is the most accurate method.
3880 *
3881 * Try using TIOCGWINSZ first, some systems that have it also define
3882 * TIOCGSIZE but don't have a struct ttysize.
3883 */
3884# ifdef TIOCGWINSZ
3885 {
3886 struct winsize ws;
3887 int fd = 1;
3888
3889 /* When stdout is not a tty, use stdin for the ioctl(). */
3890 if (!isatty(fd) && isatty(read_cmd_fd))
3891 fd = read_cmd_fd;
3892 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3893 {
3894 columns = ws.ws_col;
3895 rows = ws.ws_row;
3896 }
3897 }
3898# else /* TIOCGWINSZ */
3899# ifdef TIOCGSIZE
3900 {
3901 struct ttysize ts;
3902 int fd = 1;
3903
3904 /* When stdout is not a tty, use stdin for the ioctl(). */
3905 if (!isatty(fd) && isatty(read_cmd_fd))
3906 fd = read_cmd_fd;
3907 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3908 {
3909 columns = ts.ts_cols;
3910 rows = ts.ts_lines;
3911 }
3912 }
3913# endif /* TIOCGSIZE */
3914# endif /* TIOCGWINSZ */
3915
3916 /*
3917 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003918 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3919 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003921 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922 {
3923 if ((p = (char_u *)getenv("LINES")))
3924 rows = atoi((char *)p);
3925 if ((p = (char_u *)getenv("COLUMNS")))
3926 columns = atoi((char *)p);
3927 }
3928
3929#ifdef HAVE_TGETENT
3930 /*
3931 * 3. try reading "co" and "li" entries from termcap
3932 */
3933 if (columns == 0 || rows == 0)
3934 getlinecol(&columns, &rows);
3935#endif
3936
3937 /*
3938 * 4. If everything fails, use the old values
3939 */
3940 if (columns <= 0 || rows <= 0)
3941 return FAIL;
3942
3943 Rows = rows;
3944 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02003945 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946 return OK;
3947}
3948
Bram Moolenaarb13501f2017-07-22 22:32:56 +02003949#if defined(FEAT_TERMINAL) || defined(PROTO)
3950/*
3951 * Report the windows size "rows" and "cols" to tty "fd".
3952 */
3953 int
3954mch_report_winsize(int fd, int rows, int cols)
3955{
3956# ifdef TIOCSWINSZ
3957 struct winsize ws;
3958
3959 ws.ws_col = cols;
3960 ws.ws_row = rows;
3961 ws.ws_xpixel = cols * 5;
3962 ws.ws_ypixel = rows * 10;
3963 if (ioctl(fd, TIOCSWINSZ, &ws) == 0)
3964 {
3965 ch_log(NULL, "ioctl(TIOCSWINSZ) success");
3966 return OK;
3967 }
3968 ch_log(NULL, "ioctl(TIOCSWINSZ) failed");
3969# else
3970# ifdef TIOCSSIZE
3971 struct ttysize ts;
3972
3973 ts.ts_cols = cols;
3974 ts.ts_lines = rows;
3975 if (ioctl(fd, TIOCSSIZE, &ws) == 0)
3976 {
3977 ch_log(NULL, "ioctl(TIOCSSIZE) success");
3978 return OK;
3979 }
3980 ch_log(NULL, "ioctl(TIOCSSIZE) failed");
3981# endif
3982# endif
3983 return FAIL;
3984}
3985#endif
3986
Bram Moolenaar071d4272004-06-13 20:20:40 +00003987/*
3988 * Try to set the window size to Rows and Columns.
3989 */
3990 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003991mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992{
3993 if (*T_CWS)
3994 {
3995 /*
3996 * NOTE: if you get an error here that term_set_winsize() is
3997 * undefined, check the output of configure. It could probably not
3998 * find a ncurses, termcap or termlib library.
3999 */
4000 term_set_winsize((int)Rows, (int)Columns);
4001 out_flush();
4002 screen_start(); /* don't know where cursor is now */
4003 }
4004}
4005
4006#endif /* VMS */
4007
4008/*
4009 * Rows and/or Columns has changed.
4010 */
4011 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004012mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013{
4014 /* Nothing to do. */
4015}
4016
Bram Moolenaar205b8862011-09-07 15:04:31 +02004017/*
4018 * Wait for process "child" to end.
4019 * Return "child" if it exited properly, <= 0 on error.
4020 */
4021 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004022wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004023{
4024 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004025 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004026
4027 while (wait_pid != child)
4028 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004029 /* When compiled with Python threads are probably used, in which case
4030 * wait() sometimes hangs for no obvious reason. Use waitpid()
4031 * instead and loop (like the GUI). Also needed for other interfaces,
4032 * they might call system(). */
4033# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004034 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004035# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004036 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004037# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004038 if (wait_pid == 0)
4039 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004040 /* Wait for 1 to 10 msec before trying again. */
4041 mch_delay(delay_msec, TRUE);
4042 if (++delay_msec > 10)
4043 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004044 continue;
4045 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004046 if (wait_pid <= 0
4047# ifdef ECHILD
4048 && errno == ECHILD
4049# endif
4050 )
4051 break;
4052 }
4053 return wait_pid;
4054}
4055
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004056#if defined(FEAT_JOB_CHANNEL) || !defined(USE_SYSTEM) || defined(PROTO)
Bram Moolenaar72801402016-02-09 11:37:50 +01004057/*
4058 * Parse "cmd" and put the white-separated parts in "argv".
4059 * "argv" is an allocated array with "argc" entries.
4060 * Returns FAIL when out of memory.
4061 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01004062 int
4063mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
4064{
4065 int i;
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004066 char_u *p, *d;
Bram Moolenaar835dc632016-02-07 14:27:38 +01004067 int inquote;
4068
4069 /*
4070 * Do this loop twice:
4071 * 1: find number of arguments
4072 * 2: separate them and build argv[]
4073 */
4074 for (i = 0; i < 2; ++i)
4075 {
Bram Moolenaar6231cb82016-04-26 19:42:42 +02004076 p = skipwhite(cmd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01004077 inquote = FALSE;
4078 *argc = 0;
4079 for (;;)
4080 {
4081 if (i == 1)
4082 (*argv)[*argc] = (char *)p;
4083 ++*argc;
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004084 d = p;
Bram Moolenaar835dc632016-02-07 14:27:38 +01004085 while (*p != NUL && (inquote || (*p != ' ' && *p != TAB)))
4086 {
Bram Moolenaar9d654a82017-09-03 19:52:17 +02004087 if (p[0] == '"')
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004088 /* quotes surrounding an argument and are dropped */
Bram Moolenaar835dc632016-02-07 14:27:38 +01004089 inquote = !inquote;
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004090 else
Bram Moolenaar9d654a82017-09-03 19:52:17 +02004091 {
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004092 if (p[0] == '\\' && p[1] != NUL)
4093 {
4094 /* First pass: skip over "\ " and "\"".
4095 * Second pass: Remove the backslash. */
Bram Moolenaar9d654a82017-09-03 19:52:17 +02004096 ++p;
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004097 }
4098 if (i == 1)
4099 *d++ = *p;
Bram Moolenaar9d654a82017-09-03 19:52:17 +02004100 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01004101 ++p;
4102 }
4103 if (*p == NUL)
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004104 {
4105 if (i == 1)
4106 *d++ = NUL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01004107 break;
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004108 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01004109 if (i == 1)
Bram Moolenaard78f03f2017-10-06 01:07:41 +02004110 *d++ = NUL;
4111 p = skipwhite(p + 1);
Bram Moolenaar835dc632016-02-07 14:27:38 +01004112 }
4113 if (*argv == NULL)
4114 {
4115 if (use_shcf)
4116 {
4117 /* Account for possible multiple args in p_shcf. */
4118 p = p_shcf;
4119 for (;;)
4120 {
4121 p = skiptowhite(p);
4122 if (*p == NUL)
4123 break;
4124 ++*argc;
4125 p = skipwhite(p);
4126 }
4127 }
4128
4129 *argv = (char **)alloc((unsigned)((*argc + 4) * sizeof(char *)));
4130 if (*argv == NULL) /* out of memory */
4131 return FAIL;
4132 }
4133 }
4134 return OK;
4135}
4136#endif
4137
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004138#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004139/*
4140 * Set the environment for a child process.
4141 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004142 static void
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004143set_child_environment(long rows, long columns, char *term)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004144{
4145# ifdef HAVE_SETENV
4146 char envbuf[50];
4147# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004148 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004149 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004150 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004151 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004152 static char envbuf_Colors[20];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004153# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004154 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004155# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004156# endif
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004157 long colors =
4158# ifdef FEAT_GUI
4159 gui.in_use ? 256*256*256 :
4160# endif
4161 t_colors;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004162
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004163# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004164 setenv("TERM", term, 1);
4165 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004166 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004167 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004168 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004169 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004170 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004171 sprintf((char *)envbuf, "%ld", colors);
4172 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004173# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004174 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004175# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004176# else
4177 /*
4178 * Putenv does not copy the string, it has to remain valid.
4179 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004180 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004181 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004182 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4183 putenv(envbuf_Term);
4184 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004185 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004186 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4187 putenv(envbuf_Lines);
4188 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4189 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004190 putenv(envbuf_Columns);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004191 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors);
4192 putenv(envbuf_Colors);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004193# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004194 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4195 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4196 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004197# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004198# endif
4199}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004200
4201 static void
4202set_default_child_environment(void)
4203{
4204 set_child_environment(Rows, Columns, "dumb");
4205}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004206#endif
4207
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004208#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004209/*
4210 * Open a PTY, with FD for the master and slave side.
4211 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
4212 * When successful both file descriptors are stored.
4213 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004214 static void
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004215open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004216{
4217 char *tty_name;
4218
4219 *pty_master_fd = OpenPTY(&tty_name); /* open pty */
4220 if (*pty_master_fd >= 0)
4221 {
4222 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4223 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4224 * adding O_NOCTTY always works when defined. */
4225#ifdef O_NOCTTY
4226 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4227#else
4228 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4229#endif
4230 if (*pty_slave_fd < 0)
4231 {
4232 close(*pty_master_fd);
4233 *pty_master_fd = -1;
4234 }
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004235 else if (namep != NULL)
4236 *namep = vim_strsave((char_u *)tty_name);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004237 }
4238}
4239#endif
4240
Bram Moolenaarfae42832017-08-01 22:24:26 +02004241/*
4242 * Send SIGINT to a child process if "c" is an interrupt character.
4243 */
4244 void
4245may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4246{
4247# ifdef SIGINT
4248 if (c == Ctrl_C || c == intr_char)
4249 {
4250# ifdef HAVE_SETSID
4251 kill(-pid, SIGINT);
4252# else
4253 kill(0, SIGINT);
4254# endif
4255 if (wpid > 0)
4256 kill(wpid, SIGINT);
4257 }
4258# endif
4259}
4260
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004262mch_call_shell(
4263 char_u *cmd,
4264 int options) /* SHELL_*, see vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265{
4266#ifdef VMS
4267 char *ifn = NULL;
4268 char *ofn = NULL;
4269#endif
4270 int tmode = cur_tmode;
4271#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
Bram Moolenaarb2b050a2016-07-16 21:52:46 +02004272 char_u *newcmd; /* only needed for unix */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004273 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274
4275 out_flush();
4276
4277 if (options & SHELL_COOKED)
4278 settmode(TMODE_COOK); /* set to normal mode */
4279
Bram Moolenaar62b42182010-09-21 22:09:37 +02004280# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004281 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004282 loose_clipboard();
4283# endif
4284
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 if (cmd == NULL)
4286 x = system((char *)p_sh);
4287 else
4288 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004289# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 if (ofn = strchr((char *)cmd, '>'))
4291 *ofn++ = '\0';
4292 if (ifn = strchr((char *)cmd, '<'))
4293 {
4294 char *p;
4295
4296 *ifn++ = '\0';
4297 p = strchr(ifn,' '); /* chop off any trailing spaces */
4298 if (p)
4299 *p = '\0';
4300 }
4301 if (ofn)
4302 x = vms_sys((char *)cmd, ofn, ifn);
4303 else
4304 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004305# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306 newcmd = lalloc(STRLEN(p_sh)
4307 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
4308 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
4309 if (newcmd == NULL)
4310 x = 0;
4311 else
4312 {
4313 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4314 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4315 (char *)p_shcf,
4316 (char *)cmd);
4317 x = system((char *)newcmd);
4318 vim_free(newcmd);
4319 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004320# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 }
4322# ifdef VMS
4323 x = vms_sys_status(x);
4324# endif
4325 if (emsg_silent)
4326 ;
4327 else if (x == 127)
4328 MSG_PUTS(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329 else if (x && !(options & SHELL_SILENT))
4330 {
4331 MSG_PUTS(_("\nshell returned "));
4332 msg_outnum((long)x);
4333 msg_putchar('\n');
4334 }
4335
4336 if (tmode == TMODE_RAW)
4337 settmode(TMODE_RAW); /* set to raw mode */
4338# ifdef FEAT_TITLE
4339 resettitle();
4340# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004341# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4342 restore_clipboard();
4343# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344 return x;
4345
4346#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
4347
Bram Moolenaardf177f62005-02-22 08:39:57 +00004348# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4349 127, some shells use that already */
Bram Moolenaarb109bb42017-08-21 21:07:29 +02004350# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351
Bram Moolenaar835dc632016-02-07 14:27:38 +01004352 char_u *newcmd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004354 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355 pid_t wait_pid = 0;
4356# ifdef HAVE_UNION_WAIT
4357 union wait status;
4358# else
4359 int status = -1;
4360# endif
4361 int retval = -1;
4362 char **argv = NULL;
4363 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004364 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 int i;
4366 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004368# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004370# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004371 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 int fd_fromshell[2];
4373 int pipe_error = FALSE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004374 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375
Bram Moolenaar62b42182010-09-21 22:09:37 +02004376 newcmd = vim_strsave(p_sh);
4377 if (newcmd == NULL) /* out of memory */
4378 goto error;
4379
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380 out_flush();
4381 if (options & SHELL_COOKED)
4382 settmode(TMODE_COOK); /* set to normal mode */
4383
Bram Moolenaar835dc632016-02-07 14:27:38 +01004384 if (mch_parse_cmd(newcmd, TRUE, &argv, &argc) == FAIL)
4385 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004386
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387 if (cmd != NULL)
4388 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004389 char_u *s;
4390
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 if (extra_shell_arg != NULL)
4392 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004393
4394 /* Break 'shellcmdflag' into white separated parts. This doesn't
4395 * handle quoted strings, they are very unlikely to appear. */
4396 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4397 if (p_shcf_copy == NULL) /* out of memory */
4398 goto error;
4399 s = p_shcf_copy;
4400 p = p_shcf;
4401 while (*p != NUL)
4402 {
4403 argv[argc++] = (char *)s;
4404 while (*p && *p != ' ' && *p != TAB)
4405 *s++ = *p++;
4406 *s++ = NUL;
4407 p = skipwhite(p);
4408 }
4409
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 argv[argc++] = (char *)cmd;
4411 }
4412 argv[argc] = NULL;
4413
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004415 * For the GUI, when writing the output into the buffer and when reading
4416 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4417 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004419 if ((options & (SHELL_READ|SHELL_WRITE))
4420# ifdef FEAT_GUI
4421 || (gui.in_use && show_shell_mess)
4422# endif
4423 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004425# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 /*
4427 * Try to open a master pty.
4428 * If this works, open the slave pty.
4429 * If the slave can't be opened, close the master pty.
4430 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004431 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004432 open_pty(&pty_master_fd, &pty_slave_fd, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 /*
4434 * If not opening a pty or it didn't work, try using pipes.
4435 */
4436 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004437# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438 {
4439 pipe_error = (pipe(fd_toshell) < 0);
4440 if (!pipe_error) /* pipe create OK */
4441 {
4442 pipe_error = (pipe(fd_fromshell) < 0);
4443 if (pipe_error) /* pipe create failed */
4444 {
4445 close(fd_toshell[0]);
4446 close(fd_toshell[1]);
4447 }
4448 }
4449 if (pipe_error)
4450 {
4451 MSG_PUTS(_("\nCannot create pipes\n"));
4452 out_flush();
4453 }
4454 }
4455 }
4456
4457 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004459 SIGSET_DECL(curset)
4460
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461# ifdef __BEOS__
4462 beos_cleanup_read_thread();
4463# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004464
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004465 BLOCK_SIGNALS(&curset);
4466 pid = fork(); /* maybe we should use vfork() */
4467 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004469 UNBLOCK_SIGNALS(&curset);
4470
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004472 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004474 || (gui.in_use && show_shell_mess)
4475# endif
4476 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004478# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 if (pty_master_fd >= 0) /* close the pseudo tty */
4480 {
4481 close(pty_master_fd);
4482 close(pty_slave_fd);
4483 }
4484 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004485# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 {
4487 close(fd_toshell[0]);
4488 close(fd_toshell[1]);
4489 close(fd_fromshell[0]);
4490 close(fd_fromshell[1]);
4491 }
4492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 }
4494 else if (pid == 0) /* child */
4495 {
4496 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004497 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498
4499 if (!show_shell_mess || (options & SHELL_EXPAND))
4500 {
4501 int fd;
4502
4503 /*
4504 * Don't want to show any message from the shell. Can't just
4505 * close stdout and stderr though, because some systems will
4506 * break if you try to write to them after that, so we must
4507 * use dup() to replace them with something else -- webb
4508 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4509 * waiting for input.
4510 */
4511 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4512 fclose(stdin);
4513 fclose(stdout);
4514 fclose(stderr);
4515
4516 /*
4517 * If any of these open()'s and dup()'s fail, we just continue
4518 * anyway. It's not fatal, and on most systems it will make
4519 * no difference at all. On a few it will cause the execvp()
4520 * to exit with a non-zero status even when the completion
4521 * could be done, which is nothing too serious. If the open()
4522 * or dup() failed we'd just do the same thing ourselves
4523 * anyway -- webb
4524 */
4525 if (fd >= 0)
4526 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004527 ignored = dup(fd); /* To replace stdin (fd 0) */
4528 ignored = dup(fd); /* To replace stdout (fd 1) */
4529 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530
4531 /* Don't need this now that we've duplicated it */
4532 close(fd);
4533 }
4534 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004535 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004537 || gui.in_use
4538# endif
4539 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 {
4541
Bram Moolenaardf177f62005-02-22 08:39:57 +00004542# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004543 /* Create our own process group, so that the child and all its
4544 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004545 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004546 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004547 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004548 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004549# if defined(SIGHUP)
4550 /* When doing "!xterm&" and 'shell' is bash: the shell
4551 * will exit and send SIGHUP to all processes in its
4552 * group, killing the just started process. Ignore SIGHUP
4553 * to avoid that. (suggested by Simon Schubert)
4554 */
4555 signal(SIGHUP, SIG_IGN);
4556# endif
4557 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004558# endif
4559# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004560 if (pty_slave_fd >= 0)
4561 {
4562 /* push stream discipline modules */
4563 if (options & SHELL_COOKED)
4564 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004566 /* Try to become controlling tty (probably doesn't work,
4567 * unless run by root) */
4568 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004570 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004571# endif
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004572 set_default_child_environment();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573
Bram Moolenaara5792f52005-11-23 21:25:05 +00004574 /*
4575 * stderr is only redirected when using the GUI, so that a
4576 * program like gpg can still access the terminal to get a
4577 * passphrase using stderr.
4578 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004579# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580 if (pty_master_fd >= 0)
4581 {
4582 close(pty_master_fd); /* close master side of pty */
4583
4584 /* set up stdin/stdout/stderr for the child */
4585 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004586 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004588 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004589 if (gui.in_use)
4590 {
4591 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004592 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004593 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
4595 close(pty_slave_fd); /* has been dupped, close it now */
4596 }
4597 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004598# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 {
4600 /* set up stdin for the child */
4601 close(fd_toshell[1]);
4602 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004603 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 close(fd_toshell[0]);
4605
4606 /* set up stdout for the child */
4607 close(fd_fromshell[0]);
4608 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004609 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 close(fd_fromshell[1]);
4611
Bram Moolenaara5792f52005-11-23 21:25:05 +00004612# ifdef FEAT_GUI
4613 if (gui.in_use)
4614 {
4615 /* set up stderr for the child */
4616 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004617 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004618 }
4619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 }
4621 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004622
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 /*
4624 * There is no type cast for the argv, because the type may be
4625 * different on different machines. This may cause a warning
4626 * message with strict compilers, don't worry about it.
4627 * Call _exit() instead of exit() to avoid closing the connection
4628 * to the X server (esp. with GTK, which uses atexit()).
4629 */
4630 execvp(argv[0], argv);
4631 _exit(EXEC_FAILED); /* exec failed, return failure code */
4632 }
4633 else /* parent */
4634 {
4635 /*
4636 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004637 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638 */
4639 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004640 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004641 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004642# ifdef FEAT_JOB_CHANNEL
4643 ++dont_check_job_ended;
4644# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645 /*
4646 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004647 * This is also used to pipe stdin/stdout to/from the external
4648 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004650 if ((options & (SHELL_READ|SHELL_WRITE))
4651# ifdef FEAT_GUI
4652 || (gui.in_use && show_shell_mess)
4653# endif
4654 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004656# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004658# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004660# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4662 int ta_len = 0; /* valid bytes in ta_buf[] */
4663 int len;
4664 int p_more_save;
4665 int old_State;
4666 int c;
4667 int toshell_fd;
4668 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004669 garray_T ga;
4670 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004671# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4672 struct timeval start_tv;
4673# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674
Bram Moolenaardf177f62005-02-22 08:39:57 +00004675# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 if (pty_master_fd >= 0)
4677 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 fromshell_fd = pty_master_fd;
4679 toshell_fd = dup(pty_master_fd);
4680 }
4681 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004682# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683 {
4684 close(fd_toshell[0]);
4685 close(fd_fromshell[1]);
4686 toshell_fd = fd_toshell[1];
4687 fromshell_fd = fd_fromshell[0];
4688 }
4689
4690 /*
4691 * Write to the child if there are typed characters.
4692 * Read from the child if there are characters available.
4693 * Repeat the reading a few times if more characters are
4694 * available. Need to check for typed keys now and then, but
4695 * not too often (delays when no chars are available).
4696 * This loop is quit if no characters can be read from the pty
4697 * (WaitForChar detected special condition), or there are no
4698 * characters available and the child has exited.
4699 * Only check if the child has exited when there is no more
4700 * output. The child may exit before all the output has
4701 * been printed.
4702 *
4703 * Currently this busy loops!
4704 * This can probably dead-lock when the write blocks!
4705 */
4706 p_more_save = p_more;
4707 p_more = FALSE;
4708 old_State = State;
4709 State = EXTERNCMD; /* don't redraw at window resize */
4710
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004711 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004712 {
4713 /* Fork a process that will write the lines to the
4714 * external program. */
4715 if ((wpid = fork()) == -1)
4716 {
4717 MSG_PUTS(_("\nCannot fork\n"));
4718 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004719 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004720 {
4721 linenr_T lnum = curbuf->b_op_start.lnum;
4722 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004723 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004724 size_t l;
4725
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004726 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004727 for (;;)
4728 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004729 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004730 if (l == 0)
4731 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004732 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004733 /* NL -> NUL translation */
4734 len = write(toshell_fd, "", (size_t)1);
4735 else
4736 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004737 char_u *s = vim_strchr(lp + written, NL);
4738
Bram Moolenaar89d40322006-08-29 15:30:07 +00004739 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004740 s == NULL ? l
4741 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004742 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004743 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004744 {
4745 /* Finished a line, add a NL, unless this line
4746 * should not have one. */
4747 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004748 || (!curbuf->b_p_bin
4749 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004750 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004751 && (lnum !=
4752 curbuf->b_ml.ml_line_count
4753 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004754 ignored = write(toshell_fd, "\n",
4755 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004756 ++lnum;
4757 if (lnum > curbuf->b_op_end.lnum)
4758 {
4759 /* finished all the lines, close pipe */
4760 close(toshell_fd);
4761 toshell_fd = -1;
4762 break;
4763 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004764 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004765 written = 0;
4766 }
4767 else if (len > 0)
4768 written += len;
4769 }
4770 _exit(0);
4771 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004772 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004773 {
4774 close(toshell_fd);
4775 toshell_fd = -1;
4776 }
4777 }
4778
4779 if (options & SHELL_READ)
4780 ga_init2(&ga, 1, BUFLEN);
4781
4782 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004783# ifdef ELAPSED_FUNC
4784 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004785# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 for (;;)
4787 {
4788 /*
4789 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004790 * if there are any.
4791 * Don't do this if we are expanding wild cards (would eat
4792 * typeahead).
4793 * Don't do this when filtering and terminal is in cooked
4794 * mode, the shell command will handle the I/O. Avoids
4795 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004796 * Don't get characters when the child has already
4797 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004798 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004799 * while (noread_cnt > 4), avoids that ":r !ls" eats
4800 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801 */
4802 len = 0;
4803 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004804 && ((options &
4805 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4806 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004807# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004808 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004809# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004810 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004811 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004812 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004814 if (ta_len == 0)
4815 {
4816 /* Get extra characters when we don't have any.
4817 * Reset the counter and timer. */
4818 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004819# ifdef ELAPSED_FUNC
4820 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004821# endif
4822 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4823 }
4824 if (ta_len > 0 || len > 0)
4825 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 /*
4827 * For pipes:
4828 * Check for CTRL-C: send interrupt signal to child.
4829 * Check for CTRL-D: EOF, close pipe to child.
4830 */
4831 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4832 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 /*
4834 * Send SIGINT to the child's group or all
4835 * processes in our group.
4836 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02004837 may_send_sigint(ta_buf[ta_len], pid, wpid);
4838
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 if (pty_master_fd < 0 && toshell_fd >= 0
4840 && ta_buf[ta_len] == Ctrl_D)
4841 {
4842 close(toshell_fd);
4843 toshell_fd = -1;
4844 }
4845 }
4846
4847 /* replace K_BS by <BS> and K_DEL by <DEL> */
4848 for (i = ta_len; i < ta_len + len; ++i)
4849 {
4850 if (ta_buf[i] == CSI && len - i > 2)
4851 {
4852 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4853 if (c == K_DEL || c == K_KDEL || c == K_BS)
4854 {
4855 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4856 (size_t)(len - i - 2));
4857 if (c == K_DEL || c == K_KDEL)
4858 ta_buf[i] = DEL;
4859 else
4860 ta_buf[i] = Ctrl_H;
4861 len -= 2;
4862 }
4863 }
4864 else if (ta_buf[i] == '\r')
4865 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004866# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004868 i += (*mb_ptr2len_len)(ta_buf + i,
4869 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004870# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 }
4872
4873 /*
4874 * For pipes: echo the typed characters.
4875 * For a pty this does not seem to work.
4876 */
4877 if (pty_master_fd < 0)
4878 {
4879 for (i = ta_len; i < ta_len + len; ++i)
4880 {
4881 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4882 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004883# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 else if (has_mbyte)
4885 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004886 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887
4888 msg_outtrans_len(ta_buf + i, l);
4889 i += l - 1;
4890 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004891# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892 else
4893 msg_outtrans_len(ta_buf + i, 1);
4894 }
4895 windgoto(msg_row, msg_col);
4896 out_flush();
4897 }
4898
4899 ta_len += len;
4900
4901 /*
4902 * Write the characters to the child, unless EOF has
4903 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004904 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004905 * When writing buffer lines, drop the typed
4906 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004908 if (options & SHELL_WRITE)
4909 ta_len = 0;
4910 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911 {
4912 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4913 if (len > 0)
4914 {
4915 ta_len -= len;
4916 mch_memmove(ta_buf, ta_buf + len, ta_len);
4917 }
4918 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004919 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920 }
4921
Bram Moolenaardf177f62005-02-22 08:39:57 +00004922 if (got_int)
4923 {
4924 /* CTRL-C sends a signal to the child, we ignore it
4925 * ourselves */
4926# ifdef HAVE_SETSID
4927 kill(-pid, SIGINT);
4928# else
4929 kill(0, SIGINT);
4930# endif
4931 if (wpid > 0)
4932 kill(wpid, SIGINT);
4933 got_int = FALSE;
4934 }
4935
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936 /*
4937 * Check if the child has any characters to be printed.
4938 * Read them and write them to our window. Repeat this as
4939 * long as there is something to do, avoid the 10ms wait
4940 * for mch_inchar(), or sending typeahead characters to
4941 * the external process.
4942 * TODO: This should handle escape sequences, compatible
4943 * to some terminal (vt52?).
4944 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004945 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01004946 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004948 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004949# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004950 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004951# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004953# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004954 );
4955 if (len <= 0) /* end of file or error */
4956 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004957
4958 noread_cnt = 0;
4959 if (options & SHELL_READ)
4960 {
4961 /* Do NUL -> NL translation, append NL separated
4962 * lines to the current buffer. */
4963 for (i = 0; i < len; ++i)
4964 {
4965 if (buffer[i] == NL)
4966 append_ga_line(&ga);
4967 else if (buffer[i] == NUL)
4968 ga_append(&ga, NL);
4969 else
4970 ga_append(&ga, buffer[i]);
4971 }
4972 }
4973# ifdef FEAT_MBYTE
4974 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004975 {
4976 int l;
4977
Bram Moolenaardf177f62005-02-22 08:39:57 +00004978 len += buffer_off;
4979 buffer[len] = NUL;
4980
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981 /* Check if the last character in buffer[] is
4982 * incomplete, keep these bytes for the next
4983 * round. */
4984 for (p = buffer; p < buffer + len; p += l)
4985 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02004986 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004987 if (l == 0)
4988 l = 1; /* NUL byte? */
4989 else if (MB_BYTE2LEN(*p) != l)
4990 break;
4991 }
4992 if (p == buffer) /* no complete character */
4993 {
4994 /* avoid getting stuck at an illegal byte */
4995 if (len >= 12)
4996 ++p;
4997 else
4998 {
4999 buffer_off = len;
5000 continue;
5001 }
5002 }
5003 c = *p;
5004 *p = NUL;
5005 msg_puts(buffer);
5006 if (p < buffer + len)
5007 {
5008 *p = c;
5009 buffer_off = (buffer + len) - p;
5010 mch_memmove(buffer, p, buffer_off);
5011 continue;
5012 }
5013 buffer_off = 0;
5014 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005015# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 {
5018 buffer[len] = NUL;
5019 msg_puts(buffer);
5020 }
5021
5022 windgoto(msg_row, msg_col);
5023 cursor_on();
5024 out_flush();
5025 if (got_int)
5026 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005027
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005028# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005029 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005030 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005031 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005032
5033 /* Avoid that we keep looping here without
5034 * checking for a CTRL-C for a long time. Don't
5035 * break out too often to avoid losing typeahead. */
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005036 if (msec > 2000)
5037 {
5038 noread_cnt = 5;
5039 break;
5040 }
5041 }
5042# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 }
5044
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005045 /* If we already detected the child has finished, continue
5046 * reading output for a short while. Some text may be
5047 * buffered. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005048 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005049 {
5050 if (noread_cnt < 5)
5051 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005052 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005053 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005054
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055 /*
5056 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005057 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005059# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005060 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005061# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005063# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5065 || (wait_pid == pid && WIFEXITED(status)))
5066 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005067 /* Don't break the loop yet, try reading more
5068 * characters from "fromshell_fd" first. When using
5069 * pipes there might still be something to read and
5070 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005072 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005073 else
5074 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005075
Bram Moolenaar95a51352013-03-21 22:53:50 +01005076# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005077 /* Handle any X events, e.g. serving the clipboard. */
5078 clip_update();
5079# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080 }
5081finished:
5082 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005083 if (options & SHELL_READ)
5084 {
5085 if (ga.ga_len > 0)
5086 {
5087 append_ga_line(&ga);
5088 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005089 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005090 }
5091 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005092 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005093 ga_clear(&ga);
5094 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 /*
5097 * Give all typeahead that wasn't used back to ui_inchar().
5098 */
5099 if (ta_len)
5100 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 State = old_State;
5102 if (toshell_fd >= 0)
5103 close(toshell_fd);
5104 close(fromshell_fd);
5105 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005106# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005107 else
5108 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005109 long delay_msec = 1;
5110
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005111 /*
5112 * Similar to the loop above, but only handle X events, no
5113 * I/O.
5114 */
5115 for (;;)
5116 {
5117 if (got_int)
5118 {
5119 /* CTRL-C sends a signal to the child, we ignore it
5120 * ourselves */
5121# ifdef HAVE_SETSID
5122 kill(-pid, SIGINT);
5123# else
5124 kill(0, SIGINT);
5125# endif
5126 got_int = FALSE;
5127 }
5128# ifdef __NeXT__
5129 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5130# else
5131 wait_pid = waitpid(pid, &status, WNOHANG);
5132# endif
5133 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5134 || (wait_pid == pid && WIFEXITED(status)))
5135 {
5136 wait_pid = pid;
5137 break;
5138 }
5139
5140 /* Handle any X events, e.g. serving the clipboard. */
5141 clip_update();
5142
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005143 /* Wait for 1 to 10 msec. 1 is faster but gives the child
5144 * less time. */
5145 mch_delay(delay_msec, TRUE);
5146 if (++delay_msec > 10)
5147 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005148 }
5149 }
5150# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005151
5152 /*
5153 * Wait until our child has exited.
5154 * Ignore wait() returning pids of other children and returning
5155 * because of some signal like SIGWINCH.
5156 * Don't wait if wait_pid was already set above, indicating the
5157 * child already exited.
5158 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005159 if (wait_pid != pid)
5160 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161
Bram Moolenaar624891f2010-10-13 16:22:09 +02005162# ifdef FEAT_GUI
5163 /* Close slave side of pty. Only do this after the child has
5164 * exited, otherwise the child may hang when it tries to write on
5165 * the pty. */
5166 if (pty_master_fd >= 0)
5167 close(pty_slave_fd);
5168# endif
5169
Bram Moolenaardf177f62005-02-22 08:39:57 +00005170 /* Make sure the child that writes to the external program is
5171 * dead. */
5172 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005173 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005174 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005175 wait4pid(wpid, NULL);
5176 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005177
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005178# ifdef FEAT_JOB_CHANNEL
5179 --dont_check_job_ended;
5180# endif
5181
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182 /*
5183 * Set to raw mode right now, otherwise a CTRL-C after
5184 * catch_signals() will kill Vim.
5185 */
5186 if (tmode == TMODE_RAW)
5187 settmode(TMODE_RAW);
5188 did_settmode = TRUE;
5189 set_signals();
5190
5191 if (WIFEXITED(status))
5192 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00005193 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005195 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005196 {
5197 if (retval == EXEC_FAILED)
5198 {
5199 MSG_PUTS(_("\nCannot execute shell "));
5200 msg_outtrans(p_sh);
5201 msg_putchar('\n');
5202 }
5203 else if (!(options & SHELL_SILENT))
5204 {
5205 MSG_PUTS(_("\nshell returned "));
5206 msg_outnum((long)retval);
5207 msg_putchar('\n');
5208 }
5209 }
5210 }
5211 else
5212 MSG_PUTS(_("\nCommand terminated\n"));
5213 }
5214 }
5215 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02005216 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217
5218error:
5219 if (!did_settmode)
5220 if (tmode == TMODE_RAW)
5221 settmode(TMODE_RAW); /* set to raw mode */
5222# ifdef FEAT_TITLE
5223 resettitle();
5224# endif
5225 vim_free(newcmd);
5226
5227 return retval;
5228
5229#endif /* USE_SYSTEM */
5230}
5231
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005232#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005233 void
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005234mch_job_start(char **argv, job_T *job, jobopt_T *options)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005235{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005236 pid_t pid;
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02005237 int fd_in[2] = {-1, -1}; /* for stdin */
5238 int fd_out[2] = {-1, -1}; /* for stdout */
5239 int fd_err[2] = {-1, -1}; /* for stderr */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005240 int pty_master_fd = -1;
5241 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005242 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005243 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5244 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5245 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005246 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005247 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5248 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005249 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005250 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005251 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005252
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005253 if (use_out_for_err && use_null_for_out)
5254 use_null_for_err = TRUE;
5255
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005256 /* default is to fail */
5257 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005258
Bram Moolenaarb2412082017-08-20 18:09:14 +02005259 if (options->jo_pty
5260 && (!(use_file_for_in || use_null_for_in)
5261 || !(use_file_for_in || use_null_for_out)
5262 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005263 {
5264 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5265 if (job->jv_tty_out != NULL)
5266 job->jv_tty_in = vim_strsave(job->jv_tty_out);
5267 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005268
Bram Moolenaar12dcf022016-02-15 23:09:04 +01005269 /* TODO: without the channel feature connect the child to /dev/null? */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005270 /* Open pipes for stdin, stdout, stderr. */
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005271 if (use_file_for_in)
5272 {
5273 char_u *fname = options->jo_io_name[PART_IN];
5274
5275 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5276 if (fd_in[0] < 0)
5277 {
5278 EMSG2(_(e_notopen), fname);
5279 goto failed;
5280 }
5281 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005282 else
5283 /* When writing buffer lines to the input don't use the pty, so that
5284 * the pipe can be closed when all lines were written. */
5285 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5286 && pipe(fd_in) < 0)
5287 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005288
5289 if (use_file_for_out)
5290 {
5291 char_u *fname = options->jo_io_name[PART_OUT];
5292
5293 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5294 if (fd_out[1] < 0)
5295 {
5296 EMSG2(_(e_notopen), fname);
5297 goto failed;
5298 }
5299 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005300 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005301 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005302
5303 if (use_file_for_err)
5304 {
5305 char_u *fname = options->jo_io_name[PART_ERR];
5306
5307 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5308 if (fd_err[1] < 0)
5309 {
5310 EMSG2(_(e_notopen), fname);
5311 goto failed;
5312 }
5313 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005314 else if (!use_out_for_err && !use_null_for_err
5315 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005316 goto failed;
5317
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005318 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5319 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005320 if (options->jo_set & JO_CHANNEL)
5321 {
5322 channel = options->jo_channel;
5323 if (channel != NULL)
5324 ++channel->ch_refcount;
5325 }
5326 else
5327 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005328 if (channel == NULL)
5329 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005330 if (job->jv_tty_out != NULL)
5331 ch_log(channel, "using pty %s on fd %d",
5332 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005333 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005334
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005335 BLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005336 pid = fork(); /* maybe we should use vfork() */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005337 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005338 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005339 /* failed to fork */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005340 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005341 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005342 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005343 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005344 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005345 int null_fd = -1;
5346 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005347
Bram Moolenaar835dc632016-02-07 14:27:38 +01005348 /* child */
5349 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005350 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005351
5352# ifdef HAVE_SETSID
5353 /* Create our own process group, so that the child and all its
5354 * children can be kill()ed. Don't do this when using pipes,
5355 * because stdin is not a tty, we would lose /dev/tty. */
5356 (void)setsid();
5357# endif
5358
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005359# ifdef FEAT_TERMINAL
5360 if (options->jo_term_rows > 0)
5361 set_child_environment(
5362 (long)options->jo_term_rows,
5363 (long)options->jo_term_cols,
Bram Moolenaar93723a42017-07-28 15:55:32 +02005364 STRNCMP(T_NAME, "xterm", 5) == 0
5365 ? (char *)T_NAME : "xterm");
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005366 else
5367# endif
5368 set_default_child_environment();
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005369
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005370 if (options->jo_env != NULL)
5371 {
5372 dict_T *dict = options->jo_env;
5373 hashitem_T *hi;
5374 int todo = (int)dict->dv_hashtab.ht_used;
5375
5376 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5377 if (!HASHITEM_EMPTY(hi))
5378 {
5379 typval_T *item = &dict_lookup(hi)->di_tv;
5380
5381 vim_setenv((char_u*)hi->hi_key, get_tv_string(item));
5382 --todo;
5383 }
5384 }
5385
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005386 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005387 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005388 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005389 if (null_fd < 0)
5390 {
5391 perror("opening /dev/null failed");
5392 _exit(OPEN_NULL_FAILED);
5393 }
5394 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005395
Bram Moolenaar223896d2017-08-02 22:33:28 +02005396 if (pty_slave_fd >= 0)
5397 {
5398 /* push stream discipline modules */
5399 SetupSlavePTY(pty_slave_fd);
5400# ifdef TIOCSCTTY
5401 /* Try to become controlling tty (probably doesn't work,
5402 * unless run by root) */
5403 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5404# endif
5405 }
5406
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005407 /* set up stdin for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005408 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005409 if (use_null_for_in && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005410 ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005411 else if (fd_in[0] < 0)
5412 ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005413 else
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005414 ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005415
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005416 /* set up stderr for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005417 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005418 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005419 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005420 ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005421 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005422 }
5423 else if (use_out_for_err)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005424 ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005425 else if (fd_err[1] < 0)
5426 ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005427 else
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005428 ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005429
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005430 /* set up stdout for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005431 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005432 if (use_null_for_out && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005433 ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005434 else if (fd_out[1] < 0)
5435 ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005436 else
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005437 ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005438
5439 if (fd_in[0] >= 0)
5440 close(fd_in[0]);
5441 if (fd_in[1] >= 0)
5442 close(fd_in[1]);
5443 if (fd_out[0] >= 0)
5444 close(fd_out[0]);
5445 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005446 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005447 if (fd_err[0] >= 0)
5448 close(fd_err[0]);
5449 if (fd_err[1] >= 0)
5450 close(fd_err[1]);
5451 if (pty_master_fd >= 0)
5452 {
Bram Moolenaar223896d2017-08-02 22:33:28 +02005453 close(pty_master_fd); /* not used in the child */
5454 close(pty_slave_fd); /* was duped above */
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005455 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005456
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005457 if (null_fd >= 0)
5458 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005459
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005460 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5461 _exit(EXEC_FAILED);
5462
Bram Moolenaar835dc632016-02-07 14:27:38 +01005463 /* See above for type of argv. */
5464 execvp(argv[0], argv);
5465
Bram Moolenaar4694a172016-04-21 14:05:23 +02005466 if (stderr_works)
5467 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005468# ifdef EXITFREE
Bram Moolenaarcda77642016-06-04 13:32:35 +02005469 /* calling free_all_mem() here causes problems. Ignore valgrind
5470 * reporting possibly leaked memory. */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005471# endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005472 _exit(EXEC_FAILED); /* exec failed, return failure code */
5473 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005474
5475 /* parent */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005476 UNBLOCK_SIGNALS(&curset);
5477
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005478 job->jv_pid = pid;
5479 job->jv_status = JOB_STARTED;
Bram Moolenaarde279892016-03-11 22:19:44 +01005480 job->jv_channel = channel; /* ch_refcount was set above */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005481
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005482 if (pty_master_fd >= 0)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005483 close(pty_slave_fd); /* not used in the parent */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005484 /* close child stdin, stdout and stderr */
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005485 if (!use_file_for_in && fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005486 close(fd_in[0]);
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005487 if (!use_file_for_out && fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005488 close(fd_out[1]);
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005489 if (!use_out_for_err && !use_file_for_err && fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005490 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005491 if (channel != NULL)
5492 {
5493 channel_set_pipes(channel,
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005494 use_file_for_in || use_null_for_in
5495 ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1],
5496 use_file_for_out || use_null_for_out
5497 ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0],
5498 use_out_for_err || use_file_for_err || use_null_for_err
5499 ? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005500 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005501 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005502 else
5503 {
5504 if (fd_in[1] >= 0)
5505 close(fd_in[1]);
5506 if (fd_out[0] >= 0)
5507 close(fd_out[0]);
5508 if (fd_err[0] >= 0)
5509 close(fd_err[0]);
5510 if (pty_master_fd >= 0)
5511 close(pty_master_fd);
5512 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005513
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005514 /* success! */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005515 return;
5516
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005517failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005518 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005519 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005520 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005521 if (fd_in[1] >= 0)
5522 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005523 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005524 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005525 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005526 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005527 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005528 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005529 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005530 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005531 if (pty_master_fd >= 0)
5532 close(pty_master_fd);
5533 if (pty_slave_fd >= 0)
5534 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005535}
5536
5537 char *
5538mch_job_status(job_T *job)
5539{
5540# ifdef HAVE_UNION_WAIT
5541 union wait status;
5542# else
5543 int status = -1;
5544# endif
5545 pid_t wait_pid = 0;
5546
5547# ifdef __NeXT__
5548 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5549# else
5550 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5551# endif
5552 if (wait_pid == -1)
5553 {
5554 /* process must have exited */
Bram Moolenaar97792de2016-10-15 18:36:49 +02005555 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005556 }
5557 if (wait_pid == 0)
5558 return "run";
5559 if (WIFEXITED(status))
5560 {
5561 /* LINTED avoid "bitwise operation on signed value" */
5562 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005563 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005564 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005565 if (WIFSIGNALED(status))
5566 {
5567 job->jv_exitval = -1;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005568 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005569 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005570 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005571
5572return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005573 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005574 {
5575 ch_log(job->jv_channel, "Job ended");
5576 job->jv_status = JOB_ENDED;
5577 }
5578 return "dead";
5579}
5580
5581 job_T *
5582mch_detect_ended_job(job_T *job_list)
5583{
5584# ifdef HAVE_UNION_WAIT
5585 union wait status;
5586# else
5587 int status = -1;
5588# endif
5589 pid_t wait_pid = 0;
5590 job_T *job;
5591
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005592# ifndef USE_SYSTEM
5593 /* Do not do this when waiting for a shell command to finish, we would get
5594 * the exit value here (and discard it), the exit value obtained there
5595 * would then be wrong. */
5596 if (dont_check_job_ended > 0)
5597 return NULL;
5598# endif
5599
Bram Moolenaar97792de2016-10-15 18:36:49 +02005600# ifdef __NeXT__
5601 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5602# else
5603 wait_pid = waitpid(-1, &status, WNOHANG);
5604# endif
5605 if (wait_pid <= 0)
5606 /* no process ended */
5607 return NULL;
5608 for (job = job_list; job != NULL; job = job->jv_next)
5609 {
5610 if (job->jv_pid == wait_pid)
5611 {
5612 if (WIFEXITED(status))
5613 /* LINTED avoid "bitwise operation on signed value" */
5614 job->jv_exitval = WEXITSTATUS(status);
5615 else if (WIFSIGNALED(status))
5616 job->jv_exitval = -1;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005617 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005618 {
5619 ch_log(job->jv_channel, "Job ended");
5620 job->jv_status = JOB_ENDED;
5621 }
5622 return job;
5623 }
5624 }
5625 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005626}
5627
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005628/*
5629 * Send a (deadly) signal to "job".
5630 * Return FAIL if "how" is not a valid name.
5631 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005632 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005633mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005634{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005635 int sig = -1;
5636 pid_t job_pid;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005637
Bram Moolenaar923d9262016-02-25 20:56:01 +01005638 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005639 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005640 else if (STRCMP(how, "hup") == 0)
5641 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005642 else if (STRCMP(how, "quit") == 0)
5643 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005644 else if (STRCMP(how, "int") == 0)
5645 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005646 else if (STRCMP(how, "kill") == 0)
5647 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005648#ifdef SIGWINCH
5649 else if (STRCMP(how, "winch") == 0)
5650 sig = SIGWINCH;
5651#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005652 else if (isdigit(*how))
5653 sig = atoi((char *)how);
5654 else
5655 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005656
Bram Moolenaar72801402016-02-09 11:37:50 +01005657 /* TODO: have an option to only kill the process, not the group? */
Bram Moolenaar76467df2016-02-12 19:30:26 +01005658 job_pid = job->jv_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005659#ifdef HAVE_GETPGID
Bram Moolenaar76467df2016-02-12 19:30:26 +01005660 if (job_pid == getpgid(job_pid))
5661 job_pid = -job_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005662#endif
Bram Moolenaar76467df2016-02-12 19:30:26 +01005663
Bram Moolenaar61a66052017-07-22 18:39:00 +02005664 /* Never kill ourselves! */
5665 if (job_pid != 0)
5666 kill(job_pid, sig);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005667
Bram Moolenaar835dc632016-02-07 14:27:38 +01005668 return OK;
5669}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005670
5671/*
5672 * Clear the data related to "job".
5673 */
5674 void
5675mch_clear_job(job_T *job)
5676{
5677 /* call waitpid because child process may become zombie */
5678# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005679 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005680# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005681 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005682# endif
5683}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005684#endif
5685
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005686#if defined(FEAT_TERMINAL) || defined(PROTO)
5687 int
5688mch_create_pty_channel(job_T *job, jobopt_T *options)
5689{
5690 int pty_master_fd = -1;
5691 int pty_slave_fd = -1;
5692 channel_T *channel;
5693
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005694 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5695 if (job->jv_tty_out != NULL)
5696 job->jv_tty_in = vim_strsave(job->jv_tty_out);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005697 close(pty_slave_fd);
5698
5699 channel = add_channel();
5700 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005701 {
5702 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005703 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005704 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005705 if (job->jv_tty_out != NULL)
5706 ch_log(channel, "using pty %s on fd %d",
5707 job->jv_tty_out, pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005708 job->jv_channel = channel; /* ch_refcount was set by add_channel() */
5709 channel->ch_keep_open = TRUE;
5710
5711 channel_set_pipes(channel, pty_master_fd, pty_master_fd, pty_master_fd);
5712 channel_set_job(channel, job, options);
5713 return OK;
5714}
5715#endif
5716
Bram Moolenaar071d4272004-06-13 20:20:40 +00005717/*
5718 * Check for CTRL-C typed by reading all available characters.
5719 * In cooked mode we should get SIGINT, no need to check.
5720 */
5721 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005722mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005723{
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005724 if ((curr_tmode == TMODE_RAW || force)
5725 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005726 fill_input_buf(FALSE);
5727}
5728
5729/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005730 * Wait "msec" msec until a character is available from the mouse, keyboard,
5731 * from inbuf[].
5732 * "msec" == -1 will block forever.
5733 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005734 * When "ignore_input" is TRUE even check for pending input when input is
5735 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005736 * "interrupted" (if not NULL) is set to TRUE when no character is available
5737 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005738 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005739 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740 */
5741 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005742WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005743{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005744#ifdef FEAT_TIMERS
5745 long due_time;
5746 long remaining = msec;
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005747 int tb_change_cnt = typebuf.tb_change_cnt;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005748
5749 /* When waiting very briefly don't trigger timers. */
5750 if (msec >= 0 && msec < 10L)
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005751 return WaitForCharOrMouse(msec, NULL, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005752
5753 while (msec < 0 || remaining > 0)
5754 {
5755 /* Trigger timers and then get the time in msec until the next one is
5756 * due. Wait up to that time. */
5757 due_time = check_due_timer();
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005758 if (typebuf.tb_change_cnt != tb_change_cnt)
5759 {
5760 /* timer may have used feedkeys() */
5761 return FALSE;
5762 }
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005763 if (due_time <= 0 || (msec > 0 && due_time > remaining))
5764 due_time = remaining;
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005765 if (WaitForCharOrMouse(due_time, interrupted, ignore_input))
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005766 return TRUE;
Bram Moolenaarcda77642016-06-04 13:32:35 +02005767 if (interrupted != NULL && *interrupted)
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005768 /* Nothing available, but need to return so that side effects get
5769 * handled, such as handling a message on a channel. */
5770 return FALSE;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005771 if (msec > 0)
5772 remaining -= due_time;
5773 }
5774 return FALSE;
5775#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005776 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005777#endif
5778}
5779
5780/*
5781 * Wait "msec" msec until a character is available from the mouse or keyboard
5782 * or from inbuf[].
5783 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005784 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02005785 * "interrupted" (if not NULL) is set to TRUE when no character is available
5786 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005787 * When a GUI is being used, this will never get called -- webb
5788 */
5789 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005790WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005791{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792#ifdef FEAT_MOUSE_GPM
5793 int gpm_process_wanted;
5794#endif
5795#ifdef FEAT_XCLIPBOARD
5796 int rest;
5797#endif
5798 int avail;
5799
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005800 if (!ignore_input && input_available()) /* something in inbuf[] */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005801 return 1;
5802
5803#if defined(FEAT_MOUSE_DEC)
5804 /* May need to query the mouse position. */
5805 if (WantQueryMouse)
5806 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00005807 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005808 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
5809 }
5810#endif
5811
5812 /*
5813 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
5814 * events. This is a bit complicated, because they might both be defined.
5815 */
5816#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
5817# ifdef FEAT_XCLIPBOARD
5818 rest = 0;
5819 if (do_xterm_trace())
5820 rest = msec;
5821# endif
5822 do
5823 {
5824# ifdef FEAT_XCLIPBOARD
5825 if (rest != 0)
5826 {
5827 msec = XT_TRACE_DELAY;
5828 if (rest >= 0 && rest < XT_TRACE_DELAY)
5829 msec = rest;
5830 if (rest >= 0)
5831 rest -= msec;
5832 }
5833# endif
5834# ifdef FEAT_MOUSE_GPM
5835 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005836 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02005837 &gpm_process_wanted, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005838# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02005839 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005840# endif
5841 if (!avail)
5842 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005843 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00005844 return 1;
5845# ifdef FEAT_XCLIPBOARD
5846 if (rest == 0 || !do_xterm_trace())
5847# endif
5848 break;
5849 }
5850 }
5851 while (FALSE
5852# ifdef FEAT_MOUSE_GPM
5853 || (gpm_process_wanted && mch_gpm_process() == 0)
5854# endif
5855# ifdef FEAT_XCLIPBOARD
5856 || (!avail && rest != 0)
5857# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005858 )
5859 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860
5861#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02005862 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863#endif
5864 return avail;
5865}
5866
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01005867#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868/*
5869 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005870 * "msec" == 0 will check for characters once.
5871 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005873 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02005874 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005875 * "interrupted" (if not NULL) is set to TRUE when no character is available
5876 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878#if defined(__BEOS__)
5879 int
5880#else
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005881 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02005883RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005884{
5885 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005886 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005887#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888 static int busy = FALSE;
5889
5890 /* May retry getting characters after an event was handled. */
5891# define MAY_LOOP
5892
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005893# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00005894 /* Remember at what time we started, so that we know how much longer we
5895 * should wait after being interrupted. */
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02005896 long start_msec = msec;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005897 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005898
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02005899 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005900 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901# endif
5902
5903 /* Handle being called recursively. This may happen for the session
5904 * manager stuff, it may save the file, which does a breakcheck. */
5905 if (busy)
5906 return 0;
5907#endif
5908
5909#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005910 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911#endif
5912 {
5913#ifdef MAY_LOOP
5914 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005915# ifdef FEAT_MZSCHEME
5916 int mzquantum_used = FALSE;
5917# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005918#endif
5919#ifndef HAVE_SELECT
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005920 /* each channel may use in, out and err */
5921 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922 int nfd;
5923# ifdef FEAT_XCLIPBOARD
5924 int xterm_idx = -1;
5925# endif
5926# ifdef FEAT_MOUSE_GPM
5927 int gpm_idx = -1;
5928# endif
5929# ifdef USE_XSMP
5930 int xsmp_idx = -1;
5931# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005932 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005933
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005934# ifdef FEAT_MZSCHEME
5935 mzvim_check_threads();
5936 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5937 {
5938 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5939 mzquantum_used = TRUE;
5940 }
5941# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005942 fds[0].fd = fd;
5943 fds[0].events = POLLIN;
5944 nfd = 1;
5945
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01005947 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948 if (xterm_Shell != (Widget)0)
5949 {
5950 xterm_idx = nfd;
5951 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5952 fds[nfd].events = POLLIN;
5953 nfd++;
5954 }
5955# endif
5956# ifdef FEAT_MOUSE_GPM
5957 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5958 {
5959 gpm_idx = nfd;
5960 fds[nfd].fd = gpm_fd;
5961 fds[nfd].events = POLLIN;
5962 nfd++;
5963 }
5964# endif
5965# ifdef USE_XSMP
5966 if (xsmp_icefd != -1)
5967 {
5968 xsmp_idx = nfd;
5969 fds[nfd].fd = xsmp_icefd;
5970 fds[nfd].events = POLLIN;
5971 nfd++;
5972 }
5973# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005974#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02005975 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02005976#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02005977 if (interrupted != NULL)
5978 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005979
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005980 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005981
5982 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02005983 if (result == 0 && interrupted != NULL && ret > 0)
5984 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005985
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005986# ifdef FEAT_MZSCHEME
5987 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005988 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005989 finished = FALSE;
5990# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992# ifdef FEAT_XCLIPBOARD
5993 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5994 {
5995 xterm_update(); /* Maybe we should hand out clipboard */
5996 if (--ret == 0 && !input_available())
5997 /* Try again */
5998 finished = FALSE;
5999 }
6000# endif
6001# ifdef FEAT_MOUSE_GPM
6002 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
6003 {
6004 *check_for_gpm = 1;
6005 }
6006# endif
6007# ifdef USE_XSMP
6008 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6009 {
6010 if (fds[xsmp_idx].revents & POLLIN)
6011 {
6012 busy = TRUE;
6013 xsmp_handle_requests();
6014 busy = FALSE;
6015 }
6016 else if (fds[xsmp_idx].revents & POLLHUP)
6017 {
6018 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006019 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020 xsmp_close();
6021 }
6022 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006023 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024 }
6025# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006026#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006027 /* also call when ret == 0, we may be polling a keep-open channel */
6028 if (ret >= 0)
Bram Moolenaare0874f82016-01-24 20:36:41 +01006029 ret = channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006030#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032#else /* HAVE_SELECT */
6033
6034 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006035 struct timeval *tvp;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006036 fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006037 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006038 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006039
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006040# ifdef FEAT_MZSCHEME
6041 mzvim_check_threads();
6042 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6043 {
6044 towait = p_mzq; /* don't wait longer than 'mzquantum' */
6045 mzquantum_used = TRUE;
6046 }
6047# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006048
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006049 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006051 tv.tv_sec = towait / 1000;
6052 tv.tv_usec = (towait % 1000) * (1000000/1000);
6053 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006054 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006055 else
6056 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006057
6058 /*
6059 * Select on ready for reading and exceptional condition (end of file).
6060 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006061select_eintr:
6062 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006063 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064 FD_ZERO(&efds);
6065 FD_SET(fd, &rfds);
6066# if !defined(__QNX__) && !defined(__CYGWIN32__)
6067 /* For QNX select() always returns 1 if this is set. Why? */
6068 FD_SET(fd, &efds);
6069# endif
6070 maxfd = fd;
6071
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006073 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074 if (xterm_Shell != (Widget)0)
6075 {
6076 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6077 if (maxfd < ConnectionNumber(xterm_dpy))
6078 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006079
6080 /* An event may have already been read but not handled. In
6081 * particulary, XFlush may cause this. */
6082 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083 }
6084# endif
6085# ifdef FEAT_MOUSE_GPM
6086 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6087 {
6088 FD_SET(gpm_fd, &rfds);
6089 FD_SET(gpm_fd, &efds);
6090 if (maxfd < gpm_fd)
6091 maxfd = gpm_fd;
6092 }
6093# endif
6094# ifdef USE_XSMP
6095 if (xsmp_icefd != -1)
6096 {
6097 FD_SET(xsmp_icefd, &rfds);
6098 FD_SET(xsmp_icefd, &efds);
6099 if (maxfd < xsmp_icefd)
6100 maxfd = xsmp_icefd;
6101 }
6102# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006103# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006104 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006105# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006106 if (interrupted != NULL)
6107 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006108
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006109 ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006110 result = ret > 0 && FD_ISSET(fd, &rfds);
6111 if (result)
6112 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006113 else if (interrupted != NULL && ret > 0)
6114 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006115
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006116# ifdef EINTR
6117 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006118 {
6119 /* Check whether window has been resized, EINTR may be caused by
6120 * SIGWINCH. */
6121 if (do_resize)
6122 handle_resize();
6123
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006124 /* Interrupted by a signal, need to try again. We ignore msec
6125 * here, because we do want to check even after a timeout if
6126 * characters are available. Needed for reading output of an
6127 * external command after the process has finished. */
6128 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006129 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006130# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006131# ifdef __TANDEM
6132 if (ret == -1 && errno == ENOTSUP)
6133 {
6134 FD_ZERO(&rfds);
6135 FD_ZERO(&efds);
6136 ret = 0;
6137 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006138# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006139# ifdef FEAT_MZSCHEME
6140 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006141 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006142 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006143# endif
6144
Bram Moolenaar071d4272004-06-13 20:20:40 +00006145# ifdef FEAT_XCLIPBOARD
6146 if (ret > 0 && xterm_Shell != (Widget)0
6147 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6148 {
6149 xterm_update(); /* Maybe we should hand out clipboard */
6150 /* continue looping when we only got the X event and the input
6151 * buffer is empty */
6152 if (--ret == 0 && !input_available())
6153 {
6154 /* Try again */
6155 finished = FALSE;
6156 }
6157 }
6158# endif
6159# ifdef FEAT_MOUSE_GPM
6160 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6161 {
6162 if (FD_ISSET(gpm_fd, &efds))
6163 gpm_close();
6164 else if (FD_ISSET(gpm_fd, &rfds))
6165 *check_for_gpm = 1;
6166 }
6167# endif
6168# ifdef USE_XSMP
6169 if (ret > 0 && xsmp_icefd != -1)
6170 {
6171 if (FD_ISSET(xsmp_icefd, &efds))
6172 {
6173 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006174 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006175 xsmp_close();
6176 if (--ret == 0)
6177 finished = FALSE; /* keep going if event was only one */
6178 }
6179 else if (FD_ISSET(xsmp_icefd, &rfds))
6180 {
6181 busy = TRUE;
6182 xsmp_handle_requests();
6183 busy = FALSE;
6184 if (--ret == 0)
6185 finished = FALSE; /* keep going if event was only one */
6186 }
6187 }
6188# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006189#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006190 /* also call when ret == 0, we may be polling a keep-open channel */
6191 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006192 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006193#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194
6195#endif /* HAVE_SELECT */
6196
6197#ifdef MAY_LOOP
6198 if (finished || msec == 0)
6199 break;
6200
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006201# ifdef FEAT_CLIENTSERVER
6202 if (server_waiting())
6203 break;
6204# endif
6205
Bram Moolenaar071d4272004-06-13 20:20:40 +00006206 /* We're going to loop around again, find out for how long */
6207 if (msec > 0)
6208 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006209# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006210 /* Compute remaining wait time. */
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006211 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006212# else
6213 /* Guess we got interrupted halfway. */
6214 msec = msec / 2;
6215# endif
6216 if (msec <= 0)
6217 break; /* waited long enough */
6218 }
6219#endif
6220 }
6221
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006222 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223}
6224
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006227 * Expand a path into all matching files and/or directories. Handles "*",
6228 * "?", "[a-z]", "**", etc.
6229 * "path" has backslashes before chars that are not to be expanded.
6230 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006231 */
6232 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006233mch_expandpath(
6234 garray_T *gap,
6235 char_u *path,
6236 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237{
Bram Moolenaar02743632005-07-25 20:42:36 +00006238 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239}
6240#endif
6241
6242/*
6243 * mch_expand_wildcards() - this code does wild-card pattern matching using
6244 * the shell
6245 *
6246 * return OK for success, FAIL for error (you may lose some memory) and put
6247 * an error message in *file.
6248 *
6249 * num_pat is number of input patterns
6250 * pat is array of pointers to input patterns
6251 * num_file is pointer to number of matched file names
6252 * file is pointer to array of pointers to matched file names
6253 */
6254
6255#ifndef SEEK_SET
6256# define SEEK_SET 0
6257#endif
6258#ifndef SEEK_END
6259# define SEEK_END 2
6260#endif
6261
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006262#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006263
Bram Moolenaar071d4272004-06-13 20:20:40 +00006264 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006265mch_expand_wildcards(
6266 int num_pat,
6267 char_u **pat,
6268 int *num_file,
6269 char_u ***file,
6270 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271{
6272 int i;
6273 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006274 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275 char_u *p;
6276 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277
Bram Moolenaarc7247912008-01-13 12:54:11 +00006278 /*
6279 * This is the non-OS/2 implementation (really Unix).
6280 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006281 int j;
6282 char_u *tempname;
6283 char_u *command;
6284 FILE *fd;
6285 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006286#define STYLE_ECHO 0 /* use "echo", the default */
6287#define STYLE_GLOB 1 /* use "glob", for csh */
6288#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
6289#define STYLE_PRINT 3 /* use "print -N", for zsh */
6290#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
6291 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 int shell_style = STYLE_ECHO;
6293 int check_spaces;
6294 static int did_find_nul = FALSE;
6295 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006296 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006297 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298
6299 *num_file = 0; /* default: no files found */
6300 *file = NULL;
6301
6302 /*
6303 * If there are no wildcards, just copy the names to allocated memory.
6304 * Saves a lot of time, because we don't have to start a new shell.
6305 */
6306 if (!have_wildcard(num_pat, pat))
6307 return save_patterns(num_pat, pat, num_file, file);
6308
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006309# ifdef HAVE_SANDBOX
6310 /* Don't allow any shell command in the sandbox. */
6311 if (sandbox != 0 && check_secure())
6312 return FAIL;
6313# endif
6314
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315 /*
6316 * Don't allow the use of backticks in secure and restricted mode.
6317 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006318 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006319 for (i = 0; i < num_pat; ++i)
6320 if (vim_strchr(pat[i], '`') != NULL
6321 && (check_restricted() || check_secure()))
6322 return FAIL;
6323
6324 /*
6325 * get a name for the temp file
6326 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006327 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328 {
6329 EMSG(_(e_notmp));
6330 return FAIL;
6331 }
6332
6333 /*
6334 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006335 * file.
6336 * STYLE_BT: NL separated
6337 * If expanding `cmd` execute it directly.
6338 * STYLE_GLOB: NUL separated
6339 * If we use *csh, "glob" will work better than "echo".
6340 * STYLE_PRINT: NL or NUL separated
6341 * If we use *zsh, "print -N" will work better than "glob".
6342 * STYLE_VIMGLOB: NL separated
6343 * If we use *sh*, we define "vimglob()".
6344 * STYLE_ECHO: space separated.
6345 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346 */
6347 if (num_pat == 1 && *pat[0] == '`'
6348 && (len = STRLEN(pat[0])) > 2
6349 && *(pat[0] + len - 1) == '`')
6350 shell_style = STYLE_BT;
6351 else if ((len = STRLEN(p_sh)) >= 3)
6352 {
6353 if (STRCMP(p_sh + len - 3, "csh") == 0)
6354 shell_style = STYLE_GLOB;
6355 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6356 shell_style = STYLE_PRINT;
6357 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006358 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6359 "sh") != NULL)
6360 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006361
Bram Moolenaarc7247912008-01-13 12:54:11 +00006362 /* Compute the length of the command. We need 2 extra bytes: for the
6363 * optional '&' and for the NUL.
6364 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006365 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006366 if (shell_style == STYLE_VIMGLOB)
6367 len += STRLEN(sh_vimglob_func);
6368
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006369 for (i = 0; i < num_pat; ++i)
6370 {
6371 /* Count the length of the patterns in the same way as they are put in
6372 * "command" below. */
6373#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00006374 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006375#else
6376 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006377 for (j = 0; pat[i][j] != NUL; ++j)
6378 {
6379 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
6380 ++len; /* may add a backslash */
6381 ++len;
6382 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006383#endif
6384 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006385 command = alloc(len);
6386 if (command == NULL)
6387 {
6388 /* out of memory */
6389 vim_free(tempname);
6390 return FAIL;
6391 }
6392
6393 /*
6394 * Build the shell command:
6395 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6396 * recognizes this).
6397 * - Add the shell command to print the expanded names.
6398 * - Add the temp file name.
6399 * - Add the file name patterns.
6400 */
6401 if (shell_style == STYLE_BT)
6402 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00006403 /* change `command; command& ` to (command; command ) */
6404 STRCPY(command, "(");
6405 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006406 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006407 *p-- = ')'; /* remove last backtick */
Bram Moolenaar1c465442017-03-12 20:10:05 +01006408 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006409 --p;
6410 if (*p == '&') /* remove trailing '&' */
6411 {
6412 ampersent = TRUE;
6413 *p = ' ';
6414 }
6415 STRCAT(command, ">");
6416 }
6417 else
6418 {
6419 if (flags & EW_NOTFOUND)
6420 STRCPY(command, "set nonomatch; ");
6421 else
6422 STRCPY(command, "unset nonomatch; ");
6423 if (shell_style == STYLE_GLOB)
6424 STRCAT(command, "glob >");
6425 else if (shell_style == STYLE_PRINT)
6426 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006427 else if (shell_style == STYLE_VIMGLOB)
6428 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006429 else
6430 STRCAT(command, "echo >");
6431 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006432
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006434
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435 if (shell_style != STYLE_BT)
6436 for (i = 0; i < num_pat; ++i)
6437 {
6438 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00006439 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006440 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441#ifdef USE_SYSTEM
6442 STRCAT(command, " \"");
6443 STRCAT(command, pat[i]);
6444 STRCAT(command, "\"");
6445#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006446 int intick = FALSE;
6447
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448 p = command + STRLEN(command);
6449 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006450 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006451 {
6452 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006453 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006454 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6455 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006456 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00006457 * backslash inside backticks, before a special character
6458 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006459 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006460 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6461 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006462 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006463 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006464 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006465 else if (!intick
6466 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6467 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00006468 /* Put a backslash before a special character, but not
Bram Moolenaare4df1642014-08-29 12:58:44 +02006469 * when inside ``. And not for $var when EW_KEEPDOLLAR is
6470 * set. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006471 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006472
6473 /* Copy one character. */
6474 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006475 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476 *p = NUL;
6477#endif
6478 }
6479 if (flags & EW_SILENT)
6480 show_shell_mess = FALSE;
6481 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00006482 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006483
6484 /*
6485 * Using zsh -G: If a pattern has no matches, it is just deleted from
6486 * the argument list, otherwise zsh gives an error message and doesn't
6487 * expand any other pattern.
6488 */
6489 if (shell_style == STYLE_PRINT)
6490 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
6491
6492 /*
6493 * If we use -f then shell variables set in .cshrc won't get expanded.
6494 * vi can do it, so we will too, but it is only necessary if there is a "$"
6495 * in one of the patterns, otherwise we can still use the fast option.
6496 */
6497 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
6498 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
6499
6500 /*
6501 * execute the shell command
6502 */
6503 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6504
6505 /* When running in the background, give it some time to create the temp
6506 * file, but don't wait for it to finish. */
6507 if (ampersent)
6508 mch_delay(10L, TRUE);
6509
6510 extra_shell_arg = NULL; /* cleanup */
6511 show_shell_mess = TRUE;
6512 vim_free(command);
6513
Bram Moolenaarc7247912008-01-13 12:54:11 +00006514 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006515 {
6516 mch_remove(tempname);
6517 vim_free(tempname);
6518 /*
6519 * With interactive completion, the error message is not printed.
6520 * However with USE_SYSTEM, I don't know how to turn off error messages
6521 * from the shell, so screen may still get messed up -- webb.
6522 */
6523#ifndef USE_SYSTEM
6524 if (!(flags & EW_SILENT))
6525#endif
6526 {
6527 redraw_later_clear(); /* probably messed up screen */
6528 msg_putchar('\n'); /* clear bottom line quickly */
6529 cmdline_row = Rows - 1; /* continue on last line */
6530#ifdef USE_SYSTEM
6531 if (!(flags & EW_SILENT))
6532#endif
6533 {
6534 MSG(_(e_wildexpand));
6535 msg_start(); /* don't overwrite this message */
6536 }
6537 }
6538 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
6539 * EW_NOTFOUND is given */
6540 if (shell_style == STYLE_BT)
6541 return FAIL;
6542 goto notfound;
6543 }
6544
6545 /*
6546 * read the names from the file into memory
6547 */
6548 fd = fopen((char *)tempname, READBIN);
6549 if (fd == NULL)
6550 {
6551 /* Something went wrong, perhaps a file name with a special char. */
6552 if (!(flags & EW_SILENT))
6553 {
6554 MSG(_(e_wildexpand));
6555 msg_start(); /* don't overwrite this message */
6556 }
6557 vim_free(tempname);
6558 goto notfound;
6559 }
6560 fseek(fd, 0L, SEEK_END);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006561 llen = ftell(fd); /* get size of temp file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006562 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006563 if (llen < 0)
6564 /* just in case ftell() would fail */
6565 buffer = NULL;
6566 else
6567 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006568 if (buffer == NULL)
6569 {
6570 /* out of memory */
6571 mch_remove(tempname);
6572 vim_free(tempname);
6573 fclose(fd);
6574 return FAIL;
6575 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006576 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577 i = fread((char *)buffer, 1, len, fd);
6578 fclose(fd);
6579 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006580 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006581 {
6582 /* unexpected read error */
6583 EMSG2(_(e_notread), tempname);
6584 vim_free(tempname);
6585 vim_free(buffer);
6586 return FAIL;
6587 }
6588 vim_free(tempname);
6589
Bram Moolenaarc7247912008-01-13 12:54:11 +00006590# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006591 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
6592 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006593 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006594 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6595 *p++ = buffer[i];
6596 len = p - buffer;
6597# endif
6598
6599
6600 /* file names are separated with Space */
6601 if (shell_style == STYLE_ECHO)
6602 {
6603 buffer[len] = '\n'; /* make sure the buffer ends in NL */
6604 p = buffer;
6605 for (i = 0; *p != '\n'; ++i) /* count number of entries */
6606 {
6607 while (*p != ' ' && *p != '\n')
6608 ++p;
6609 p = skipwhite(p); /* skip to next entry */
6610 }
6611 }
6612 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006613 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006614 {
6615 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6616 p = buffer;
6617 for (i = 0; *p != NUL; ++i) /* count number of entries */
6618 {
6619 while (*p != '\n' && *p != NUL)
6620 ++p;
6621 if (*p != NUL)
6622 ++p;
6623 p = skipwhite(p); /* skip leading white space */
6624 }
6625 }
6626 /* file names are separated with NUL */
6627 else
6628 {
6629 /*
6630 * Some versions of zsh use spaces instead of NULs to separate
6631 * results. Only do this when there is no NUL before the end of the
6632 * buffer, otherwise we would never be able to use file names with
6633 * embedded spaces when zsh does use NULs.
6634 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6635 * don't check for spaces again.
6636 */
6637 check_spaces = FALSE;
6638 if (shell_style == STYLE_PRINT && !did_find_nul)
6639 {
6640 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006641 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006642 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006643 did_find_nul = TRUE;
6644 else
6645 check_spaces = TRUE;
6646 }
6647
6648 /*
6649 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6650 * already is one, for STYLE_GLOB it needs to be added.
6651 */
6652 if (len && buffer[len - 1] == NUL)
6653 --len;
6654 else
6655 buffer[len] = NUL;
6656 i = 0;
6657 for (p = buffer; p < buffer + len; ++p)
6658 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6659 {
6660 ++i;
6661 *p = NUL;
6662 }
6663 if (len)
6664 ++i; /* count last entry */
6665 }
6666 if (i == 0)
6667 {
6668 /*
6669 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6670 * /bin/sh will happily expand it to nothing rather than returning an
6671 * error; and hey, it's good to check anyway -- webb.
6672 */
6673 vim_free(buffer);
6674 goto notfound;
6675 }
6676 *num_file = i;
6677 *file = (char_u **)alloc(sizeof(char_u *) * i);
6678 if (*file == NULL)
6679 {
6680 /* out of memory */
6681 vim_free(buffer);
6682 return FAIL;
6683 }
6684
6685 /*
6686 * Isolate the individual file names.
6687 */
6688 p = buffer;
6689 for (i = 0; i < *num_file; ++i)
6690 {
6691 (*file)[i] = p;
6692 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006693 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6694 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006695 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006696 while (!(shell_style == STYLE_ECHO && *p == ' ')
6697 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006698 ++p;
6699 if (p == buffer + len) /* last entry */
6700 *p = NUL;
6701 else
6702 {
6703 *p++ = NUL;
6704 p = skipwhite(p); /* skip to next entry */
6705 }
6706 }
6707 else /* NUL separates */
6708 {
6709 while (*p && p < buffer + len) /* skip entry */
6710 ++p;
6711 ++p; /* skip NUL */
6712 }
6713 }
6714
6715 /*
6716 * Move the file names to allocated memory.
6717 */
6718 for (j = 0, i = 0; i < *num_file; ++i)
6719 {
6720 /* Require the files to exist. Helps when using /bin/sh */
6721 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6722 continue;
6723
6724 /* check if this entry should be included */
6725 dir = (mch_isdir((*file)[i]));
6726 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6727 continue;
6728
Bram Moolenaara2031822006-03-07 22:29:51 +00006729 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01006730 if (!dir && (flags & EW_EXEC)
6731 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006732 continue;
6733
Bram Moolenaar071d4272004-06-13 20:20:40 +00006734 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6735 if (p)
6736 {
6737 STRCPY(p, (*file)[i]);
6738 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006739 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006740 (*file)[j++] = p;
6741 }
6742 }
6743 vim_free(buffer);
6744 *num_file = j;
6745
6746 if (*num_file == 0) /* rejected all entries */
6747 {
6748 vim_free(*file);
6749 *file = NULL;
6750 goto notfound;
6751 }
6752
6753 return OK;
6754
6755notfound:
6756 if (flags & EW_NOTFOUND)
6757 return save_patterns(num_pat, pat, num_file, file);
6758 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006759}
6760
6761#endif /* VMS */
6762
Bram Moolenaar071d4272004-06-13 20:20:40 +00006763 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006764save_patterns(
6765 int num_pat,
6766 char_u **pat,
6767 int *num_file,
6768 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006769{
6770 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006771 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006772
6773 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6774 if (*file == NULL)
6775 return FAIL;
6776 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006777 {
6778 s = vim_strsave(pat[i]);
6779 if (s != NULL)
6780 /* Be compatible with expand_filename(): halve the number of
6781 * backslashes. */
6782 backslash_halve(s);
6783 (*file)[i] = s;
6784 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785 *num_file = num_pat;
6786 return OK;
6787}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006788
Bram Moolenaar071d4272004-06-13 20:20:40 +00006789/*
6790 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6791 * expand.
6792 */
6793 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006794mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006795{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006796 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006797 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006798 if (*p == '\\' && p[1] != NUL)
6799 ++p;
6800 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801 if (vim_strchr((char_u *)
6802#ifdef VMS
6803 "*?%"
6804#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006805 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006806#endif
6807 , *p) != NULL)
6808 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 }
6810 return FALSE;
6811}
6812
6813/*
6814 * Return TRUE if the string "p" contains a wildcard.
6815 * Don't recognize '~' at the end as a wildcard.
6816 */
6817 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006818mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006819{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006820 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006821 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006822 if (*p == '\\' && p[1] != NUL)
6823 ++p;
6824 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006825 if (vim_strchr((char_u *)
6826#ifdef VMS
6827 "*?%$"
6828#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006829 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006830#endif
6831 , *p) != NULL
6832 || (*p == '~' && p[1] != NUL))
6833 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006834 }
6835 return FALSE;
6836}
6837
Bram Moolenaar071d4272004-06-13 20:20:40 +00006838 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006839have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006840{
6841 int i;
6842
6843 for (i = 0; i < num; i++)
6844 if (mch_has_wildcard(file[i]))
6845 return 1;
6846 return 0;
6847}
6848
6849 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006850have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006851{
6852 int i;
6853
6854 for (i = 0; i < num; i++)
6855 if (vim_strchr(file[i], '$') != NULL)
6856 return TRUE;
6857 return FALSE;
6858}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006859
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01006860#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006861/*
6862 * Scaled-down version of rename(), which is missing in Xenix.
6863 * This version can only move regular files and will fail if the
6864 * destination exists.
6865 */
6866 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01006867mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006868{
6869 struct stat st;
6870
6871 if (stat(dest, &st) >= 0) /* fail if destination exists */
6872 return -1;
6873 if (link(src, dest) != 0) /* link file to new name */
6874 return -1;
6875 if (mch_remove(src) == 0) /* delete link to old name */
6876 return 0;
6877 return -1;
6878}
6879#endif /* !HAVE_RENAME */
6880
6881#ifdef FEAT_MOUSE_GPM
6882/*
6883 * Initializes connection with gpm (if it isn't already opened)
6884 * Return 1 if succeeded (or connection already opened), 0 if failed
6885 */
6886 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006887gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006888{
6889 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6890
6891 if (!gpm_flag)
6892 {
6893 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6894 gpm_connect.defaultMask = ~GPM_HARD;
6895 /* Default handling for mouse move*/
6896 gpm_connect.minMod = 0; /* Handle any modifier keys */
6897 gpm_connect.maxMod = 0xffff;
6898 if (Gpm_Open(&gpm_connect, 0) > 0)
6899 {
6900 /* gpm library tries to handling TSTP causes
6901 * problems. Anyways, we close connection to Gpm whenever
6902 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006903 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006904 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006905# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006907# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006908 return 1; /* succeed */
6909 }
6910 if (gpm_fd == -2)
6911 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6912 return 0;
6913 }
6914 return 1; /* already open */
6915}
6916
6917/*
6918 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006919 */
6920 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006921gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922{
6923 if (gpm_flag && gpm_fd >= 0) /* if Open */
6924 Gpm_Close();
6925}
6926
6927/* Reads gpm event and adds special keys to input buf. Returns length of
6928 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02006929 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 */
6931 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006932mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006933{
6934 int button;
6935 static Gpm_Event gpm_event;
6936 char_u string[6];
6937 int_u vim_modifiers;
6938 int row,col;
6939 unsigned char buttons_mask;
6940 unsigned char gpm_modifiers;
6941 static unsigned char old_buttons = 0;
6942
6943 Gpm_GetEvent(&gpm_event);
6944
6945#ifdef FEAT_GUI
6946 /* Don't put events in the input queue now. */
6947 if (hold_gui_events)
6948 return 0;
6949#endif
6950
6951 row = gpm_event.y - 1;
6952 col = gpm_event.x - 1;
6953
6954 string[0] = ESC; /* Our termcode */
6955 string[1] = 'M';
6956 string[2] = 'G';
6957 switch (GPM_BARE_EVENTS(gpm_event.type))
6958 {
6959 case GPM_DRAG:
6960 string[3] = MOUSE_DRAG;
6961 break;
6962 case GPM_DOWN:
6963 buttons_mask = gpm_event.buttons & ~old_buttons;
6964 old_buttons = gpm_event.buttons;
6965 switch (buttons_mask)
6966 {
6967 case GPM_B_LEFT:
6968 button = MOUSE_LEFT;
6969 break;
6970 case GPM_B_MIDDLE:
6971 button = MOUSE_MIDDLE;
6972 break;
6973 case GPM_B_RIGHT:
6974 button = MOUSE_RIGHT;
6975 break;
6976 default:
6977 return 0;
6978 /*Don't know what to do. Can more than one button be
6979 * reported in one event? */
6980 }
6981 string[3] = (char_u)(button | 0x20);
6982 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6983 break;
6984 case GPM_UP:
6985 string[3] = MOUSE_RELEASE;
6986 old_buttons &= ~gpm_event.buttons;
6987 break;
6988 default:
6989 return 0;
6990 }
6991 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6992 gpm_modifiers = gpm_event.modifiers;
6993 vim_modifiers = 0x0;
6994 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6995 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6996 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6997 */
6998 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6999 vim_modifiers |= MOUSE_SHIFT;
7000
7001 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7002 vim_modifiers |= MOUSE_CTRL;
7003 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7004 vim_modifiers |= MOUSE_ALT;
7005 string[3] |= vim_modifiers;
7006 string[4] = (char_u)(col + ' ' + 1);
7007 string[5] = (char_u)(row + ' ' + 1);
7008 add_to_input_buf(string, 6);
7009 return 6;
7010}
7011#endif /* FEAT_MOUSE_GPM */
7012
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007013#ifdef FEAT_SYSMOUSE
7014/*
7015 * Initialize connection with sysmouse.
7016 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7017 * output, any sysmouse output than will be processed via sig_sysmouse().
7018 * Return OK if succeeded, FAIL if failed.
7019 */
7020 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007021sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007022{
7023 struct mouse_info mouse;
7024
7025 mouse.operation = MOUSE_MODE;
7026 mouse.u.mode.mode = 0;
7027 mouse.u.mode.signal = SIGUSR2;
7028 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7029 {
7030 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7031 mouse.operation = MOUSE_SHOW;
7032 ioctl(1, CONS_MOUSECTL, &mouse);
7033 return OK;
7034 }
7035 return FAIL;
7036}
7037
7038/*
7039 * Stop processing SIGUSR2 signals, and also make sure that
7040 * virtual console do not send us any sysmouse related signal.
7041 */
7042 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007043sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007044{
7045 struct mouse_info mouse;
7046
7047 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7048 mouse.operation = MOUSE_MODE;
7049 mouse.u.mode.mode = 0;
7050 mouse.u.mode.signal = 0;
7051 ioctl(1, CONS_MOUSECTL, &mouse);
7052}
7053
7054/*
7055 * Gets info from sysmouse and adds special keys to input buf.
7056 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007057 static RETSIGTYPE
7058sig_sysmouse SIGDEFARG(sigarg)
7059{
7060 struct mouse_info mouse;
7061 struct video_info video;
7062 char_u string[6];
7063 int row, col;
7064 int button;
7065 int buttons;
7066 static int oldbuttons = 0;
7067
7068#ifdef FEAT_GUI
7069 /* Don't put events in the input queue now. */
7070 if (hold_gui_events)
7071 return;
7072#endif
7073
7074 mouse.operation = MOUSE_GETINFO;
7075 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7076 && ioctl(1, FBIO_MODEINFO, &video) != -1
7077 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7078 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7079 {
7080 row = mouse.u.data.y / video.vi_cheight;
7081 col = mouse.u.data.x / video.vi_cwidth;
7082 buttons = mouse.u.data.buttons;
7083 string[0] = ESC; /* Our termcode */
7084 string[1] = 'M';
7085 string[2] = 'S';
7086 if (oldbuttons == buttons && buttons != 0)
7087 {
7088 button = MOUSE_DRAG;
7089 }
7090 else
7091 {
7092 switch (buttons)
7093 {
7094 case 0:
7095 button = MOUSE_RELEASE;
7096 break;
7097 case 1:
7098 button = MOUSE_LEFT;
7099 break;
7100 case 2:
7101 button = MOUSE_MIDDLE;
7102 break;
7103 case 4:
7104 button = MOUSE_RIGHT;
7105 break;
7106 default:
7107 return;
7108 }
7109 oldbuttons = buttons;
7110 }
7111 string[3] = (char_u)(button);
7112 string[4] = (char_u)(col + ' ' + 1);
7113 string[5] = (char_u)(row + ' ' + 1);
7114 add_to_input_buf(string, 6);
7115 }
7116 return;
7117}
7118#endif /* FEAT_SYSMOUSE */
7119
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007121typedef char_u * (*STRPROCSTR)(char_u *);
7122typedef char_u * (*INTPROCSTR)(int);
7123typedef int (*STRPROCINT)(char_u *);
7124typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007125
7126/*
7127 * Call a DLL routine which takes either a string or int param
7128 * and returns an allocated string.
7129 */
7130 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007131mch_libcall(
7132 char_u *libname,
7133 char_u *funcname,
7134 char_u *argstring, /* NULL when using a argint */
7135 int argint,
7136 char_u **string_result,/* NULL when using number_result */
7137 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007138{
7139# if defined(USE_DLOPEN)
7140 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007141 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007142# else
7143 shl_t hinstLib;
7144# endif
7145 STRPROCSTR ProcAdd;
7146 INTPROCSTR ProcAddI;
7147 char_u *retval_str = NULL;
7148 int retval_int = 0;
7149 int success = FALSE;
7150
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007151 /*
7152 * Get a handle to the DLL module.
7153 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007155 /* First clear any error, it's not cleared by the dlopen() call. */
7156 (void)dlerror();
7157
Bram Moolenaar071d4272004-06-13 20:20:40 +00007158 hinstLib = dlopen((char *)libname, RTLD_LAZY
7159# ifdef RTLD_LOCAL
7160 | RTLD_LOCAL
7161# endif
7162 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007163 if (hinstLib == NULL)
7164 {
7165 /* "dlerr" must be used before dlclose() */
7166 dlerr = (char *)dlerror();
7167 if (dlerr != NULL)
7168 EMSG2(_("dlerror = \"%s\""), dlerr);
7169 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007170# else
7171 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7172# endif
7173
7174 /* If the handle is valid, try to get the function address. */
7175 if (hinstLib != NULL)
7176 {
7177# ifdef HAVE_SETJMP_H
7178 /*
7179 * Catch a crash when calling the library function. For example when
7180 * using a number where a string pointer is expected.
7181 */
7182 mch_startjmp();
7183 if (SETJMP(lc_jump_env) != 0)
7184 {
7185 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007186# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007187 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007188# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007189 mch_didjmp();
7190 }
7191 else
7192# endif
7193 {
7194 retval_str = NULL;
7195 retval_int = 0;
7196
7197 if (argstring != NULL)
7198 {
7199# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007200 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007201 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007202# else
7203 if (shl_findsym(&hinstLib, (const char *)funcname,
7204 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7205 ProcAdd = NULL;
7206# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007207 if ((success = (ProcAdd != NULL
7208# if defined(USE_DLOPEN)
7209 && dlerr == NULL
7210# endif
7211 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007212 {
7213 if (string_result == NULL)
7214 retval_int = ((STRPROCINT)ProcAdd)(argstring);
7215 else
7216 retval_str = (ProcAdd)(argstring);
7217 }
7218 }
7219 else
7220 {
7221# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007222 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007223 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007224# else
7225 if (shl_findsym(&hinstLib, (const char *)funcname,
7226 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7227 ProcAddI = NULL;
7228# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007229 if ((success = (ProcAddI != NULL
7230# if defined(USE_DLOPEN)
7231 && dlerr == NULL
7232# endif
7233 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234 {
7235 if (string_result == NULL)
7236 retval_int = ((INTPROCINT)ProcAddI)(argint);
7237 else
7238 retval_str = (ProcAddI)(argint);
7239 }
7240 }
7241
7242 /* Save the string before we free the library. */
7243 /* Assume that a "1" or "-1" result is an illegal pointer. */
7244 if (string_result == NULL)
7245 *number_result = retval_int;
7246 else if (retval_str != NULL
7247 && retval_str != (char_u *)1
7248 && retval_str != (char_u *)-1)
7249 *string_result = vim_strsave(retval_str);
7250 }
7251
7252# ifdef HAVE_SETJMP_H
7253 mch_endjmp();
7254# ifdef SIGHASARG
7255 if (lc_signal != 0)
7256 {
7257 int i;
7258
7259 /* try to find the name of this signal */
7260 for (i = 0; signal_info[i].sig != -1; i++)
7261 if (lc_signal == signal_info[i].sig)
7262 break;
7263 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
7264 }
7265# endif
7266# endif
7267
Bram Moolenaar071d4272004-06-13 20:20:40 +00007268# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007269 /* "dlerr" must be used before dlclose() */
7270 if (dlerr != NULL)
7271 EMSG2(_("dlerror = \"%s\""), dlerr);
7272
7273 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007274 (void)dlclose(hinstLib);
7275# else
7276 (void)shl_unload(hinstLib);
7277# endif
7278 }
7279
7280 if (!success)
7281 {
7282 EMSG2(_(e_libcall), funcname);
7283 return FAIL;
7284 }
7285
7286 return OK;
7287}
7288#endif
7289
7290#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
7291static int xterm_trace = -1; /* default: disabled */
7292static int xterm_button;
7293
7294/*
7295 * Setup a dummy window for X selections in a terminal.
7296 */
7297 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007298setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007299{
7300 int z = 0;
7301 char *strp = "";
7302 Widget AppShell;
7303
7304 if (!x_connect_to_server())
7305 return;
7306
7307 open_app_context();
7308 if (app_context != NULL && xterm_Shell == (Widget)0)
7309 {
7310 int (*oldhandler)();
7311#if defined(HAVE_SETJMP_H)
7312 int (*oldIOhandler)();
7313#endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007314# ifdef ELAPSED_FUNC
7315 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007316
7317 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007318 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007319# endif
7320
7321 /* Ignore X errors while opening the display */
7322 oldhandler = XSetErrorHandler(x_error_check);
7323
7324#if defined(HAVE_SETJMP_H)
7325 /* Ignore X IO errors while opening the display */
7326 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7327 mch_startjmp();
7328 if (SETJMP(lc_jump_env) != 0)
7329 {
7330 mch_didjmp();
7331 xterm_dpy = NULL;
7332 }
7333 else
7334#endif
7335 {
7336 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7337 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
7338#if defined(HAVE_SETJMP_H)
7339 mch_endjmp();
7340#endif
7341 }
7342
7343#if defined(HAVE_SETJMP_H)
7344 /* Now handle X IO errors normally. */
7345 (void)XSetIOErrorHandler(oldIOhandler);
7346#endif
7347 /* Now handle X errors normally. */
7348 (void)XSetErrorHandler(oldhandler);
7349
7350 if (xterm_dpy == NULL)
7351 {
7352 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007353 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007354 return;
7355 }
7356
7357 /* Catch terminating error of the X server connection. */
7358 (void)XSetIOErrorHandler(x_IOerror_handler);
7359
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007360# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007361 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007362 {
7363 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007364 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007365 verbose_leave();
7366 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007367# endif
7368
7369 /* Create a Shell to make converters work. */
7370 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7371 applicationShellWidgetClass, xterm_dpy,
7372 NULL);
7373 if (AppShell == (Widget)0)
7374 return;
7375 xterm_Shell = XtVaCreatePopupShell("VIM",
7376 topLevelShellWidgetClass, AppShell,
7377 XtNmappedWhenManaged, 0,
7378 XtNwidth, 1,
7379 XtNheight, 1,
7380 NULL);
7381 if (xterm_Shell == (Widget)0)
7382 return;
7383
7384 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007385 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007386 if (x11_display == NULL)
7387 x11_display = xterm_dpy;
7388
7389 XtRealizeWidget(xterm_Shell);
7390 XSync(xterm_dpy, False);
7391 xterm_update();
7392 }
7393 if (xterm_Shell != (Widget)0)
7394 {
7395 clip_init(TRUE);
7396 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7397 x11_window = (Window)atol(strp);
7398 /* Check if $WINDOWID is valid. */
7399 if (test_x11_window(xterm_dpy) == FAIL)
7400 x11_window = 0;
7401 if (x11_window != 0)
7402 xterm_trace = 0;
7403 }
7404}
7405
7406 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007407start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007408{
7409 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7410 return;
7411 xterm_trace = 1;
7412 xterm_button = button;
7413 do_xterm_trace();
7414}
7415
7416
7417 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007418stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007419{
7420 if (xterm_trace < 0)
7421 return;
7422 xterm_trace = 0;
7423}
7424
7425/*
7426 * Query the xterm pointer and generate mouse termcodes if necessary
7427 * return TRUE if dragging is active, else FALSE
7428 */
7429 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007430do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007431{
7432 Window root, child;
7433 int root_x, root_y;
7434 int win_x, win_y;
7435 int row, col;
7436 int_u mask_return;
7437 char_u buf[50];
7438 char_u *strp;
7439 long got_hints;
7440 static char_u *mouse_code;
7441 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7442 static int prev_row = 0, prev_col = 0;
7443 static XSizeHints xterm_hints;
7444
7445 if (xterm_trace <= 0)
7446 return FALSE;
7447
7448 if (xterm_trace == 1)
7449 {
7450 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007451 * have changed recently. */
7452 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7453 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007454 || xterm_hints.width_inc <= 1
7455 || xterm_hints.height_inc <= 1)
7456 {
7457 xterm_trace = -1; /* Not enough data -- disable tracing */
7458 return FALSE;
7459 }
7460
7461 /* Rely on the same mouse code for the duration of this */
7462 mouse_code = find_termcode(mouse_name);
7463 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007464 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007465 xterm_trace = 2;
7466
7467 /* Find the offset of the chars, there might be a scrollbar on the
7468 * left of the window and/or a menu on the top (eterm etc.) */
7469 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7470 &win_x, &win_y, &mask_return);
7471 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7472 - (xterm_hints.height_inc / 2);
7473 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7474 xterm_hints.y = 2;
7475 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7476 - (xterm_hints.width_inc / 2);
7477 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7478 xterm_hints.x = 2;
7479 return TRUE;
7480 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007481 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007482 {
7483 xterm_trace = 0;
7484 return FALSE;
7485 }
7486
7487 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7488 &win_x, &win_y, &mask_return);
7489
7490 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7491 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7492 if (row == prev_row && col == prev_col)
7493 return TRUE;
7494
7495 STRCPY(buf, mouse_code);
7496 strp = buf + STRLEN(buf);
7497 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7498 *strp++ = (char_u)(col + ' ' + 1);
7499 *strp++ = (char_u)(row + ' ' + 1);
7500 *strp = 0;
7501 add_to_input_buf(buf, STRLEN(buf));
7502
7503 prev_row = row;
7504 prev_col = col;
7505 return TRUE;
7506}
7507
7508# if defined(FEAT_GUI) || defined(PROTO)
7509/*
7510 * Destroy the display, window and app_context. Required for GTK.
7511 */
7512 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007513clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007514{
7515 if (xterm_Shell != (Widget)0)
7516 {
7517 XtDestroyWidget(xterm_Shell);
7518 xterm_Shell = (Widget)0;
7519 }
7520 if (xterm_dpy != NULL)
7521 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007522# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007523 /* Lesstif and Solaris crash here, lose some memory */
7524 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007525# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007526 if (x11_display == xterm_dpy)
7527 x11_display = NULL;
7528 xterm_dpy = NULL;
7529 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007530# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007531 if (app_context != (XtAppContext)NULL)
7532 {
7533 /* Lesstif and Solaris crash here, lose some memory */
7534 XtDestroyApplicationContext(app_context);
7535 app_context = (XtAppContext)NULL;
7536 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007537# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007538}
7539# endif
7540
7541/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007542 * Catch up with GUI or X events.
7543 */
7544 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007545clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007546{
7547# ifdef FEAT_GUI
7548 if (gui.in_use)
7549 gui_mch_update();
7550 else
7551# endif
7552 if (xterm_Shell != (Widget)0)
7553 xterm_update();
7554}
7555
7556/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007557 * Catch up with any queued X events. This may put keyboard input into the
7558 * input buffer, call resize call-backs, trigger timers etc. If there is
7559 * nothing in the X event queue (& no timers pending), then we return
7560 * immediately.
7561 */
7562 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007563xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564{
7565 XEvent event;
7566
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007567 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007568 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007569 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007570
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007571 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007572 break;
7573
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007574 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007575 {
7576 /* There is an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007577 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007578#ifdef FEAT_CLIENTSERVER
7579 {
7580 XPropertyEvent *e = (XPropertyEvent *)&event;
7581
7582 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007583 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007584 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007585 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007586#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007587 XtDispatchEvent(&event);
7588 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007589 else
7590 {
7591 /* There is something else than an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007592 XtAppProcessEvent(app_context, mask);
7593 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007594 }
7595}
7596
7597 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007598clip_xterm_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007599{
7600 if (xterm_Shell != (Widget)0)
7601 return clip_x11_own_selection(xterm_Shell, cbd);
7602 return FAIL;
7603}
7604
7605 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007606clip_xterm_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007607{
7608 if (xterm_Shell != (Widget)0)
7609 clip_x11_lose_selection(xterm_Shell, cbd);
7610}
7611
7612 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007613clip_xterm_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007614{
7615 if (xterm_Shell != (Widget)0)
7616 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7617}
7618
7619 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007620clip_xterm_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007621{
7622 clip_x11_set_selection(cbd);
7623}
7624#endif
7625
7626
7627#if defined(USE_XSMP) || defined(PROTO)
7628/*
7629 * Code for X Session Management Protocol.
7630 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007631static void xsmp_handle_save_yourself(SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast);
7632static void xsmp_die(SmcConn smc_conn, SmPointer client_data);
7633static void xsmp_save_complete(SmcConn smc_conn, SmPointer client_data);
7634static void xsmp_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data);
7635static void xsmp_ice_connection(IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007636
7637
7638# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007639static void xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640
7641/*
7642 * This is our chance to ask the user if they want to save,
7643 * or abort the logout
7644 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007645 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007646xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007647{
7648 cmdmod_T save_cmdmod;
7649 int cancel_shutdown = False;
7650
7651 save_cmdmod = cmdmod;
7652 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007653 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007654 /* Mustn't logout */
7655 cancel_shutdown = True;
7656 cmdmod = save_cmdmod;
7657 setcursor(); /* position cursor */
7658 out_flush();
7659
7660 /* Done interaction */
7661 SmcInteractDone(smc_conn, cancel_shutdown);
7662
7663 /* Finish off
7664 * Only end save-yourself here if we're not cancelling shutdown;
7665 * we'll get a cancelled callback later in which we'll end it.
7666 * Hopefully get around glitchy SMs (like GNOME-1)
7667 */
7668 if (!cancel_shutdown)
7669 {
7670 xsmp.save_yourself = False;
7671 SmcSaveYourselfDone(smc_conn, True);
7672 }
7673}
7674# endif
7675
7676/*
7677 * Callback that starts save-yourself.
7678 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007679 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007680xsmp_handle_save_yourself(
7681 SmcConn smc_conn,
7682 SmPointer client_data UNUSED,
7683 int save_type UNUSED,
7684 Bool shutdown,
7685 int interact_style UNUSED,
7686 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007687{
7688 /* Handle already being in saveyourself */
7689 if (xsmp.save_yourself)
7690 SmcSaveYourselfDone(smc_conn, True);
7691 xsmp.save_yourself = True;
7692 xsmp.shutdown = shutdown;
7693
7694 /* First up, preserve all files */
7695 out_flush();
7696 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7697
7698 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007699 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007700
7701# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7702 /* Now see if we can ask about unsaved files */
7703 if (shutdown && !fast && gui.in_use)
7704 /* Need to interact with user, but need SM's permission */
7705 SmcInteractRequest(smc_conn, SmDialogError,
7706 xsmp_handle_interaction, client_data);
7707 else
7708# endif
7709 {
7710 /* Can stop the cycle here */
7711 SmcSaveYourselfDone(smc_conn, True);
7712 xsmp.save_yourself = False;
7713 }
7714}
7715
7716
7717/*
7718 * Callback to warn us of imminent death.
7719 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007720 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007721xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007722{
7723 xsmp_close();
7724
7725 /* quit quickly leaving swapfiles for modified buffers behind */
7726 getout_preserve_modified(0);
7727}
7728
7729
7730/*
7731 * Callback to tell us that save-yourself has completed.
7732 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007733 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007734xsmp_save_complete(
7735 SmcConn smc_conn UNUSED,
7736 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007737{
7738 xsmp.save_yourself = False;
7739}
7740
7741
7742/*
7743 * Callback to tell us that an instigated shutdown was cancelled
7744 * (maybe even by us)
7745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007746 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007747xsmp_shutdown_cancelled(
7748 SmcConn smc_conn,
7749 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007750{
7751 if (xsmp.save_yourself)
7752 SmcSaveYourselfDone(smc_conn, True);
7753 xsmp.save_yourself = False;
7754 xsmp.shutdown = False;
7755}
7756
7757
7758/*
7759 * Callback to tell us that a new ICE connection has been established.
7760 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007761 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007762xsmp_ice_connection(
7763 IceConn iceConn,
7764 IcePointer clientData UNUSED,
7765 Bool opening,
7766 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007767{
7768 /* Intercept creation of ICE connection fd */
7769 if (opening)
7770 {
7771 xsmp_icefd = IceConnectionNumber(iceConn);
7772 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7773 }
7774}
7775
7776
7777/* Handle any ICE processing that's required; return FAIL if SM lost */
7778 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007779xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007780{
7781 Bool rep;
7782
7783 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7784 == IceProcessMessagesIOError)
7785 {
7786 /* Lost ICE */
7787 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007788 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007789 xsmp_close();
7790 return FAIL;
7791 }
7792 else
7793 return OK;
7794}
7795
7796static int dummy;
7797
7798/* Set up X Session Management Protocol */
7799 void
7800xsmp_init(void)
7801{
7802 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007803 SmcCallbacks smcallbacks;
7804#if 0
7805 SmPropValue smname;
7806 SmProp smnameprop;
7807 SmProp *smprops[1];
7808#endif
7809
7810 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007811 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007812
7813 xsmp.save_yourself = xsmp.shutdown = False;
7814
7815 /* Set up SM callbacks - must have all, even if they're not used */
7816 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7817 smcallbacks.save_yourself.client_data = NULL;
7818 smcallbacks.die.callback = xsmp_die;
7819 smcallbacks.die.client_data = NULL;
7820 smcallbacks.save_complete.callback = xsmp_save_complete;
7821 smcallbacks.save_complete.client_data = NULL;
7822 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7823 smcallbacks.shutdown_cancelled.client_data = NULL;
7824
7825 /* Set up a watch on ICE connection creations. The "dummy" argument is
7826 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7827 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7828 {
7829 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007830 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007831 return;
7832 }
7833
7834 /* Create an SM connection */
7835 xsmp.smcconn = SmcOpenConnection(
7836 NULL,
7837 NULL,
7838 SmProtoMajor,
7839 SmProtoMinor,
7840 SmcSaveYourselfProcMask | SmcDieProcMask
7841 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7842 &smcallbacks,
7843 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007844 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007845 sizeof(errorstring),
7846 errorstring);
7847 if (xsmp.smcconn == NULL)
7848 {
7849 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007850
Bram Moolenaar071d4272004-06-13 20:20:40 +00007851 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007852 {
7853 vim_snprintf(errorreport, sizeof(errorreport),
7854 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7855 verb_msg((char_u *)errorreport);
7856 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007857 return;
7858 }
7859 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7860
7861#if 0
7862 /* ID ourselves */
7863 smname.value = "vim";
7864 smname.length = 3;
7865 smnameprop.name = "SmProgram";
7866 smnameprop.type = "SmARRAY8";
7867 smnameprop.num_vals = 1;
7868 smnameprop.vals = &smname;
7869
7870 smprops[0] = &smnameprop;
7871 SmcSetProperties(xsmp.smcconn, 1, smprops);
7872#endif
7873}
7874
7875
7876/* Shut down XSMP comms. */
7877 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007878xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007879{
7880 if (xsmp_icefd != -1)
7881 {
7882 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007883 if (xsmp.clientid != NULL)
7884 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007885 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007886 xsmp_icefd = -1;
7887 }
7888}
7889#endif /* USE_XSMP */
7890
7891
7892#ifdef EBCDIC
7893/* Translate character to its CTRL- value */
7894char CtrlTable[] =
7895{
7896/* 00 - 5E */
7897 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7899 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7900 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7901 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7902 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7903/* ^ */ 0x1E,
7904/* - */ 0x1F,
7905/* 61 - 6C */
7906 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7907/* _ */ 0x1F,
7908/* 6E - 80 */
7909 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7910/* a */ 0x01,
7911/* b */ 0x02,
7912/* c */ 0x03,
7913/* d */ 0x37,
7914/* e */ 0x2D,
7915/* f */ 0x2E,
7916/* g */ 0x2F,
7917/* h */ 0x16,
7918/* i */ 0x05,
7919/* 8A - 90 */
7920 0, 0, 0, 0, 0, 0, 0,
7921/* j */ 0x15,
7922/* k */ 0x0B,
7923/* l */ 0x0C,
7924/* m */ 0x0D,
7925/* n */ 0x0E,
7926/* o */ 0x0F,
7927/* p */ 0x10,
7928/* q */ 0x11,
7929/* r */ 0x12,
7930/* 9A - A1 */
7931 0, 0, 0, 0, 0, 0, 0, 0,
7932/* s */ 0x13,
7933/* t */ 0x3C,
7934/* u */ 0x3D,
7935/* v */ 0x32,
7936/* w */ 0x26,
7937/* x */ 0x18,
7938/* y */ 0x19,
7939/* z */ 0x3F,
7940/* AA - AC */
7941 0, 0, 0,
7942/* [ */ 0x27,
7943/* AE - BC */
7944 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7945/* ] */ 0x1D,
7946/* BE - C0 */ 0, 0, 0,
7947/* A */ 0x01,
7948/* B */ 0x02,
7949/* C */ 0x03,
7950/* D */ 0x37,
7951/* E */ 0x2D,
7952/* F */ 0x2E,
7953/* G */ 0x2F,
7954/* H */ 0x16,
7955/* I */ 0x05,
7956/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7957/* J */ 0x15,
7958/* K */ 0x0B,
7959/* L */ 0x0C,
7960/* M */ 0x0D,
7961/* N */ 0x0E,
7962/* O */ 0x0F,
7963/* P */ 0x10,
7964/* Q */ 0x11,
7965/* R */ 0x12,
7966/* DA - DF */ 0, 0, 0, 0, 0, 0,
7967/* \ */ 0x1C,
7968/* E1 */ 0,
7969/* S */ 0x13,
7970/* T */ 0x3C,
7971/* U */ 0x3D,
7972/* V */ 0x32,
7973/* W */ 0x26,
7974/* X */ 0x18,
7975/* Y */ 0x19,
7976/* Z */ 0x3F,
7977/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7978 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7979};
7980
7981char MetaCharTable[]=
7982{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7983 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7984 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7985 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7986 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7987};
7988
7989
7990/* TODO: Use characters NOT numbers!!! */
7991char CtrlCharTable[]=
7992{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7993 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7994 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7995 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7996 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7997};
7998
7999
8000#endif