blob: 4d902d93950f30b8a802be9604c24e29ae82b63a [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram Moolenaar071d4272004-06-13 20:20:40 +000027#include "os_unixx.h" /* unix includes for os_unix.c only */
28
29#ifdef USE_XSMP
30# include <X11/SM/SMlib.h>
31#endif
32
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000033#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35static int selinux_enabled = -1;
36#endif
37
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020038#ifdef HAVE_SMACK
39# include <attr/xattr.h>
40# include <linux/xattr.h>
41# ifndef SMACK_LABEL_LEN
42# define SMACK_LABEL_LEN 1024
43# endif
44#endif
45
Bram Moolenaar643b6142018-09-12 20:29:09 +020046#ifdef __BEOS__
Bram Moolenaar311d9822007-02-27 15:48:28 +000047# undef select
Bram Moolenaar643b6142018-09-12 20:29:09 +020048# define select beos_select
Bram Moolenaar071d4272004-06-13 20:20:40 +000049#endif
50
Bram Moolenaara2442432007-04-26 14:26:37 +000051#ifdef __CYGWIN__
52# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000053# include <cygwin/version.h>
54# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
55 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010056# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
57# define WIN32_LEAN_AND_MEAN
58# include <windows.h>
59# include "winclip.pro"
60# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000061# endif
62#endif
63
Bram Moolenaar071d4272004-06-13 20:20:40 +000064#ifdef FEAT_MOUSE_GPM
65# include <gpm.h>
66/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
67 * I just copied relevant defines here. A cleaner solution would be to put gpm
68 * code into separate file and include there linux/keyboard.h
69 */
70/* #include <linux/keyboard.h> */
71# define KG_SHIFT 0
72# define KG_CTRL 2
73# define KG_ALT 3
74# define KG_ALTGR 1
75# define KG_SHIFTL 4
76# define KG_SHIFTR 5
77# define KG_CTRLL 6
78# define KG_CTRLR 7
79# define KG_CAPSSHIFT 8
80
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010081static void gpm_close(void);
82static int gpm_open(void);
83static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000084#endif
85
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000086#ifdef FEAT_SYSMOUSE
87# include <sys/consio.h>
88# include <sys/fbio.h>
89
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010090static int sysmouse_open(void);
91static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +010092static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000093#endif
94
Bram Moolenaar071d4272004-06-13 20:20:40 +000095/*
96 * end of autoconf section. To be extended...
97 */
98
99/* Are the following #ifdefs still required? And why? Is that for X11? */
100
101#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
102# ifdef SIGWINCH
103# undef SIGWINCH
104# endif
105# ifdef TIOCGWINSZ
106# undef TIOCGWINSZ
107# endif
108#endif
109
110#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
111# define SIGWINCH SIGWINDOW
112#endif
113
114#ifdef FEAT_X11
115# include <X11/Xlib.h>
116# include <X11/Xutil.h>
117# include <X11/Xatom.h>
118# ifdef FEAT_XCLIPBOARD
119# include <X11/Intrinsic.h>
120# include <X11/Shell.h>
121# include <X11/StringDefs.h>
122static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100123static void clip_update(void);
124static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125# endif
126
127# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
128Window x11_window = 0;
129# endif
130Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131#endif
132
133#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100134static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135
136static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200137static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138static int did_set_title = FALSE;
139static char_u *oldicon = NULL;
140static int did_set_icon = FALSE;
141#endif
142
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
Bram Moolenaar205b8862011-09-07 15:04:31 +0200145#ifdef HAVE_UNION_WAIT
146typedef union wait waitstatus;
147#else
148typedef int waitstatus;
149#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200150static int WaitForChar(long msec, int *interrupted, int ignore_input);
151static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100152#if defined(__BEOS__) || defined(VMS)
Bram Moolenaarcda77642016-06-04 13:32:35 +0200153int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200155static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156#endif
157
158#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100159static int do_xterm_trace(void);
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000160# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161#endif
162
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100163static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164
165#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100166static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167#endif
168#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100169static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170#endif
171#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100172static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173#endif
174#if defined(SIGALRM) && defined(FEAT_X11) \
175 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
176# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100177static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000178/* volatile because it is used in signal handler sig_alarm(). */
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200179static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100181static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100183static void catch_int_signal(void);
184static void set_signals(void);
185static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200186#ifdef HAVE_SIGPROCMASK
187# define SIGSET_DECL(set) sigset_t set;
188# define BLOCK_SIGNALS(set) block_signals(set)
189# define UNBLOCK_SIGNALS(set) unblock_signals(set)
190#else
191# define SIGSET_DECL(set)
192# define BLOCK_SIGNALS(set) do { /**/ } while (0)
193# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
194#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100195static int have_wildcard(int, char_u **);
196static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100198static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199
200#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000201# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202#endif
203
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000204/* volatile because it is used in signal handler sig_winch(). */
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200205static volatile sig_atomic_t do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206static char_u *extra_shell_arg = NULL;
207static int show_shell_mess = TRUE;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000208/* volatile because it is used in signal handler deathtrap(). */
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200209static volatile sig_atomic_t deadly_signal = 0; /* The signal we caught */
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000210/* volatile because it is used in signal handler deathtrap(). */
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200211static volatile sig_atomic_t in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100213#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
214static int dont_check_job_ended = 0;
215#endif
216
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
218
219#ifdef USE_XSMP
220typedef struct
221{
222 SmcConn smcconn; /* The SM connection ID */
223 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200224 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225 Bool save_yourself; /* If we're in the middle of a save_yourself */
226 Bool shutdown; /* If we're in shutdown mode */
227} xsmp_config_T;
228
229static xsmp_config_T xsmp;
230#endif
231
232#ifdef SYS_SIGLIST_DECLARED
233/*
234 * I have seen
235 * extern char *_sys_siglist[NSIG];
236 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
237 * that describe the signals. That is nearly what we want here. But
238 * autoconf does only check for sys_siglist (without the underscore), I
239 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100240 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 */
242#endif
243
244static struct signalinfo
245{
246 int sig; /* Signal number, eg. SIGSEGV etc */
247 char *name; /* Signal name (not char_u!). */
248 char deadly; /* Catch as a deadly signal? */
249} signal_info[] =
250{
251#ifdef SIGHUP
252 {SIGHUP, "HUP", TRUE},
253#endif
254#ifdef SIGQUIT
255 {SIGQUIT, "QUIT", TRUE},
256#endif
257#ifdef SIGILL
258 {SIGILL, "ILL", TRUE},
259#endif
260#ifdef SIGTRAP
261 {SIGTRAP, "TRAP", TRUE},
262#endif
263#ifdef SIGABRT
264 {SIGABRT, "ABRT", TRUE},
265#endif
266#ifdef SIGEMT
267 {SIGEMT, "EMT", TRUE},
268#endif
269#ifdef SIGFPE
270 {SIGFPE, "FPE", TRUE},
271#endif
272#ifdef SIGBUS
273 {SIGBUS, "BUS", TRUE},
274#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100275#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
276 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 {SIGSEGV, "SEGV", TRUE},
278#endif
279#ifdef SIGSYS
280 {SIGSYS, "SYS", TRUE},
281#endif
282#ifdef SIGALRM
283 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
284#endif
285#ifdef SIGTERM
286 {SIGTERM, "TERM", TRUE},
287#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100288#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 {SIGVTALRM, "VTALRM", TRUE},
290#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000291#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
292 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
293 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294 {SIGPROF, "PROF", TRUE},
295#endif
296#ifdef SIGXCPU
297 {SIGXCPU, "XCPU", TRUE},
298#endif
299#ifdef SIGXFSZ
300 {SIGXFSZ, "XFSZ", TRUE},
301#endif
302#ifdef SIGUSR1
303 {SIGUSR1, "USR1", TRUE},
304#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000305#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
306 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 {SIGUSR2, "USR2", TRUE},
308#endif
309#ifdef SIGINT
310 {SIGINT, "INT", FALSE},
311#endif
312#ifdef SIGWINCH
313 {SIGWINCH, "WINCH", FALSE},
314#endif
315#ifdef SIGTSTP
316 {SIGTSTP, "TSTP", FALSE},
317#endif
318#ifdef SIGPIPE
319 {SIGPIPE, "PIPE", FALSE},
320#endif
321 {-1, "Unknown!", FALSE}
322};
323
Bram Moolenaar25724922009-07-14 15:38:41 +0000324 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100325mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000326{
327 if (p_verbose >= 5)
328 {
329 verbose_enter();
330 smsg((char_u *)"chdir(%s)", path);
331 verbose_leave();
332 }
333# ifdef VMS
334 return chdir(vms_fixfilename(path));
335# else
336 return chdir(path);
337# endif
338}
339
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200340/* Why is NeXT excluded here (and not in os_unixx.h)? */
341#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
342# define NEW_TTY_SYSTEM
343#endif
344
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000345/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100346 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000347 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100349mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200351 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 if (p_wd) /* Unix is too fast, slow down a bit more */
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100353 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354}
355
356/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000357 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 * Get a characters from the keyboard.
359 * Return the number of characters that are available.
360 * If wtime == 0 do not wait for characters.
361 * If wtime == n wait a short time for characters.
362 * If wtime == -1 wait forever for characters.
363 */
364 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100365mch_inchar(
366 char_u *buf,
367 int maxlen,
368 long wtime, /* don't use "time", MIPS cannot handle it */
369 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370{
371 int len;
Bram Moolenaarcda77642016-06-04 13:32:35 +0200372 int interrupted = FALSE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200373 int did_start_blocking = FALSE;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200374 long wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200375 long elapsed_time = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100376#ifdef ELAPSED_FUNC
377 ELAPSED_TYPE start_tv;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200378
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100379 ELAPSED_INIT(start_tv);
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200380#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200382 /* repeat until we got a character or waited long enough */
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200383 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200385 /* Check if window changed size while we were busy, perhaps the ":set
386 * columns=99" command was used. */
387 while (do_resize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200389
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200390#ifdef MESSAGE_QUEUE
Bram Moolenaared5a9d62018-09-06 13:14:43 +0200391 // Only process messages when waiting.
392 if (wtime != 0)
393 {
394 parse_queued_messages();
395 // If input was put directly in typeahead buffer bail out here.
396 if (typebuf_changed(tb_change_cnt))
397 return 0;
398 }
Bram Moolenaar67c53842010-05-22 18:28:27 +0200399#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200400 if (wtime < 0 && did_start_blocking)
401 /* blocking and already waited for p_ut */
402 wait_time = -1;
403 else
404 {
405 if (wtime >= 0)
406 wait_time = wtime;
407 else
408 /* going to block after p_ut */
409 wait_time = p_ut;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100410#ifdef ELAPSED_FUNC
411 elapsed_time = ELAPSED_FUNC(start_tv);
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200412#endif
413 wait_time -= elapsed_time;
414 if (wait_time < 0)
415 {
416 if (wtime >= 0)
417 /* no character available within "wtime" */
418 return 0;
419
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200420 else
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200421 {
422 /* no character available within 'updatetime' */
423 did_start_blocking = TRUE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200424 if (trigger_cursorhold() && maxlen >= 3
425 && !typebuf_changed(tb_change_cnt))
426 {
427 buf[0] = K_SPECIAL;
428 buf[1] = KS_EXTRA;
429 buf[2] = (int)KE_CURSORHOLD;
430 return 3;
431 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200432 /*
433 * If there is no character available within 'updatetime'
434 * seconds flush all the swap files to disk.
435 * Also done when interrupted by SIGWINCH.
436 */
437 before_blocking();
438 continue;
439 }
440 }
441 }
442
443#ifdef FEAT_JOB_CHANNEL
444 /* Checking if a job ended requires polling. Do this every 100 msec. */
445 if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
446 wait_time = 100L;
Bram Moolenaar8a8199e2016-11-26 15:13:33 +0100447 /* If there is readahead then parse_queued_messages() timed out and we
448 * should call it again soon. */
449 if ((wait_time < 0 || wait_time > 100L) && channel_any_readahead())
450 wait_time = 10L;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200451#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100452#ifdef FEAT_BEVAL_GUI
Bram Moolenaar59716a22017-03-01 20:32:44 +0100453 if (p_beval && wait_time > 100L)
454 /* The 'balloonexpr' may indirectly invoke a callback while waiting
455 * for a character, need to check often. */
456 wait_time = 100L;
457#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200458
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200460 * We want to be interrupted by the winch signal
461 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 */
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200463 if (WaitForChar(wait_time, &interrupted, FALSE))
Bram Moolenaar67c53842010-05-22 18:28:27 +0200464 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200465 /* If input was put directly in typeahead buffer bail out here. */
466 if (typebuf_changed(tb_change_cnt))
467 return 0;
468
469 /*
470 * For some terminals we only get one character at a time.
471 * We want the get all available characters, so we could keep on
472 * trying until none is available
473 * For some other terminals this is quite slow, that's why we don't
474 * do it.
475 */
476 len = read_from_input_buf(buf, (long)maxlen);
477 if (len > 0)
478 return len;
479 continue;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200480 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200482 /* no character available */
483#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
484 /* estimate the elapsed time */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +0100485 elapsed_time += wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200486#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000487
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200488 if (do_resize /* interrupted by SIGWINCH signal */
489#ifdef FEAT_CLIENTSERVER
490 || server_waiting()
491#endif
492#ifdef MESSAGE_QUEUE
493 || interrupted
494#endif
495 || wait_time > 0
Bram Moolenaar1572e302017-03-25 20:16:28 +0100496 || (wtime < 0 && !did_start_blocking))
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200497 continue;
498
499 /* no character available or interrupted */
500 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200502 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503}
504
505 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100506handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507{
508 do_resize = FALSE;
509 shell_resized();
510}
511
512/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200513 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514 */
515 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100516mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200518 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519}
520
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200521#if defined(FEAT_TERMINAL) || defined(PROTO)
522/*
523 * Check for any pending input or messages.
524 */
525 int
526mch_check_messages(void)
527{
528 return WaitForChar(0L, NULL, TRUE);
529}
530#endif
531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
533# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000534# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535# endif
536# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
537# include <sys/sysctl.h>
538# endif
539# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
540# include <sys/sysinfo.h>
541# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100542# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100543# include <mach/mach_host.h>
544# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100545# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
547/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000548 * Return total amount of memory available in Kbyte.
549 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100552mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000555 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556
Bram Moolenaar362dc332018-03-05 21:59:37 +0100557# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100558 {
559 /* Mac (Darwin) way of getting the amount of RAM available */
560 mach_port_t host = mach_host_self();
561 kern_return_t kret;
562# ifdef HOST_VM_INFO64
563 struct vm_statistics64 vm_stat;
564 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565
Bram Moolenaar988615f2018-02-27 17:58:20 +0100566 kret = host_statistics64(host, HOST_VM_INFO64,
567 (host_info64_t)&vm_stat, &count);
568# else
569 struct vm_statistics vm_stat;
570 natural_t count = HOST_VM_INFO_COUNT;
571
572 kret = host_statistics(host, HOST_VM_INFO,
573 (host_info_t)&vm_stat, &count);
574# endif
575 if (kret == KERN_SUCCESS)
576 /* get the amount of user memory by summing each usage */
577 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
578 + vm_stat.inactive_count
579# ifdef MAC_OS_X_VERSION_10_9
580 + vm_stat.compressor_page_count
581# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100582 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100583 mach_port_deallocate(mach_task_self(), host);
584 }
585# endif
586
587# ifdef HAVE_SYSCTL
588 if (mem == 0)
589 {
590 /* BSD way of getting the amount of RAM available. */
591 int mib[2];
592 size_t len = sizeof(long_u);
593# ifdef HW_USERMEM64
594 long_u physmem;
595# else
596 /* sysctl() may return 32 bit or 64 bit, accept both */
597 union {
598 int_u u32;
599 long_u u64;
600 } physmem;
601# endif
602
603 mib[0] = CTL_HW;
604# ifdef HW_USERMEM64
605 mib[1] = HW_USERMEM64;
606# else
607 mib[1] = HW_USERMEM;
608# endif
609 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
610 {
611# ifdef HW_USERMEM64
612 mem = (long_u)physmem;
613# else
614 if (len == sizeof(physmem.u64))
615 mem = (long_u)physmem.u64;
616 else
617 mem = (long_u)physmem.u32;
618# endif
619 }
620 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200621# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200623# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 if (mem == 0)
625 {
626 struct sysinfo sinfo;
627
628 /* Linux way of getting amount of RAM available */
629 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000630 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200631# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar914572a2007-05-01 11:37:47 +0000632 /* avoid overflow as much as possible */
633 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
634 {
635 sinfo.mem_unit = sinfo.mem_unit >> 1;
636 --shiftright;
637 }
638 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200639# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200641# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200644# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200646# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 if (mem == 0)
648 {
649 long pagesize, pagecount;
650
651 /* Solaris way of getting amount of RAM available */
652 pagesize = sysconf(_SC_PAGESIZE);
653 pagecount = sysconf(_SC_PHYS_PAGES);
654 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000655 {
656 /* avoid overflow as much as possible */
657 while (shiftright > 0 && (pagesize & 1) == 0)
658 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000659 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000660 --shiftright;
661 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000663 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200665# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666
667 /* Return the minimum of the physical memory and the user limit, because
668 * using more than the user limit may cause Vim to be terminated. */
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200669# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670 {
671 struct rlimit rlp;
672
673 if (getrlimit(RLIMIT_DATA, &rlp) == 0
674 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200675# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200677# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000678 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000680 {
681 mem = (long_u)rlp.rlim_cur;
682 shiftright = 10;
683 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200685# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686
687 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000688 return mem >> shiftright;
689 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690}
691#endif
692
693 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100694mch_delay(long msec, int ignoreinput)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695{
696 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000697#ifdef FEAT_MZSCHEME
698 long total = msec; /* remember original value */
699#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700
701 if (ignoreinput)
702 {
703 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000704 * here. But we don't want QUIT to kill us (CTRL-\ used in a
705 * shell may produce SIGQUIT). */
706 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707 old_tmode = curr_tmode;
708 if (curr_tmode == TMODE_RAW)
709 settmode(TMODE_SLEEP);
710
711 /*
712 * Everybody sleeps in a different way...
713 * Prefer nanosleep(), some versions of usleep() can only sleep up to
714 * one second.
715 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000716#ifdef FEAT_MZSCHEME
717 do
718 {
719 /* if total is large enough, wait by portions in p_mzq */
720 if (total > p_mzq)
721 msec = p_mzq;
722 else
723 msec = total;
724 total -= msec;
725#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726#ifdef HAVE_NANOSLEEP
727 {
728 struct timespec ts;
729
730 ts.tv_sec = msec / 1000;
731 ts.tv_nsec = (msec % 1000) * 1000000;
732 (void)nanosleep(&ts, NULL);
733 }
734#else
735# ifdef HAVE_USLEEP
736 while (msec >= 1000)
737 {
738 usleep((unsigned int)(999 * 1000));
739 msec -= 999;
740 }
741 usleep((unsigned int)(msec * 1000));
742# else
743# ifndef HAVE_SELECT
744 poll(NULL, 0, (int)msec);
745# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 {
747 struct timeval tv;
748
749 tv.tv_sec = msec / 1000;
750 tv.tv_usec = (msec % 1000) * 1000;
751 /*
752 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
753 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
754 */
755 select(0, NULL, NULL, NULL, &tv);
756 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757# endif /* HAVE_SELECT */
758# endif /* HAVE_NANOSLEEP */
759#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000760#ifdef FEAT_MZSCHEME
761 }
762 while (total > 0);
763#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764
765 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000766 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 }
768 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200769 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770}
771
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000772#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
774# define HAVE_CHECK_STACK_GROWTH
775/*
776 * Support for checking for an almost-out-of-stack-space situation.
777 */
778
779/*
780 * Return a pointer to an item on the stack. Used to find out if the stack
781 * grows up or down.
782 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783static int stack_grows_downwards;
784
785/*
786 * Find out if the stack grows upwards or downwards.
787 * "p" points to a variable on the stack of the caller.
788 */
789 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100790check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791{
792 int i;
793
794 stack_grows_downwards = (p > (char *)&i);
795}
796#endif
797
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000798#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799static char *stack_limit = NULL;
800
801#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
802# include <pthread.h>
803# include <pthread_np.h>
804#endif
805
806/*
807 * Find out until how var the stack can grow without getting into trouble.
808 * Called when starting up and when switching to the signal stack in
809 * deathtrap().
810 */
811 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100812get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813{
814 struct rlimit rlp;
815 int i;
816 long lim;
817
818 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
819 * limit doesn't fit in a long (rlim_cur might be "long long"). */
820 if (getrlimit(RLIMIT_STACK, &rlp) == 0
821 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
822# ifdef RLIM_INFINITY
823 && rlp.rlim_cur != RLIM_INFINITY
824# endif
825 )
826 {
827 lim = (long)rlp.rlim_cur;
828#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
829 {
830 pthread_attr_t attr;
831 size_t size;
832
833 /* On FreeBSD the initial thread always has a fixed stack size, no
834 * matter what the limits are set to. Normally it's 1 Mbyte. */
835 pthread_attr_init(&attr);
836 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
837 {
838 pthread_attr_getstacksize(&attr, &size);
839 if (lim > (long)size)
840 lim = (long)size;
841 }
842 pthread_attr_destroy(&attr);
843 }
844#endif
845 if (stack_grows_downwards)
846 {
847 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
848 if (stack_limit >= (char *)&i)
849 /* overflow, set to 1/16 of current stack position */
850 stack_limit = (char *)((long)&i / 16L);
851 }
852 else
853 {
854 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
855 if (stack_limit <= (char *)&i)
856 stack_limit = NULL; /* overflow */
857 }
858 }
859}
860
861/*
862 * Return FAIL when running out of stack space.
863 * "p" must point to any variable local to the caller that's on the stack.
864 */
865 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100866mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867{
868 if (stack_limit != NULL)
869 {
870 if (stack_grows_downwards)
871 {
872 if (p < stack_limit)
873 return FAIL;
874 }
875 else if (p > stack_limit)
876 return FAIL;
877 }
878 return OK;
879}
880#endif
881
882#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
883/*
884 * Support for using the signal stack.
885 * This helps when we run out of stack space, which causes a SIGSEGV. The
886 * signal handler then must run on another stack, since the normal stack is
887 * completely full.
888 */
889
890#ifndef SIGSTKSZ
891# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
892#endif
893
894# ifdef HAVE_SIGALTSTACK
895static stack_t sigstk; /* for sigaltstack() */
896# else
897static struct sigstack sigstk; /* for sigstack() */
898# endif
899
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900static char *signal_stack;
901
902 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100903init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904{
905 if (signal_stack != NULL)
906 {
907# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908# ifdef HAVE_SS_BASE
909 sigstk.ss_base = signal_stack;
910# else
911 sigstk.ss_sp = signal_stack;
912# endif
913 sigstk.ss_size = SIGSTKSZ;
914 sigstk.ss_flags = 0;
915 (void)sigaltstack(&sigstk, NULL);
916# else
917 sigstk.ss_sp = signal_stack;
918 if (stack_grows_downwards)
919 sigstk.ss_sp += SIGSTKSZ - 1;
920 sigstk.ss_onstack = 0;
921 (void)sigstack(&sigstk, NULL);
922# endif
923 }
924}
925#endif
926
927/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000928 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000929 * will barf when the second argument to signal() is ``wrong''.
930 * Let me try it with a few tricky defines from my own osdef.h (jw).
931 */
932#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 static RETSIGTYPE
934sig_winch SIGDEFARG(sigarg)
935{
936 /* this is not required on all systems, but it doesn't hurt anybody */
937 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
938 do_resize = TRUE;
939 SIGRETURN;
940}
941#endif
942
943#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 static RETSIGTYPE
945catch_sigint SIGDEFARG(sigarg)
946{
947 /* this is not required on all systems, but it doesn't hurt anybody */
948 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
949 got_int = TRUE;
950 SIGRETURN;
951}
952#endif
953
954#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 static RETSIGTYPE
956catch_sigpwr SIGDEFARG(sigarg)
957{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000958 /* this is not required on all systems, but it doesn't hurt anybody */
959 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 /*
961 * I'm not sure we get the SIGPWR signal when the system is really going
962 * down or when the batteries are almost empty. Just preserve the swap
963 * files and don't exit, that can't do any harm.
964 */
965 ml_sync_all(FALSE, FALSE);
966 SIGRETURN;
967}
968#endif
969
970#ifdef SET_SIG_ALARM
971/*
972 * signal function for alarm().
973 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 static RETSIGTYPE
975sig_alarm SIGDEFARG(sigarg)
976{
977 /* doesn't do anything, just to break a system call */
978 sig_alarm_called = TRUE;
979 SIGRETURN;
980}
981#endif
982
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000983#if (defined(HAVE_SETJMP_H) \
984 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
985 || defined(FEAT_LIBCALL))) \
986 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987/*
988 * A simplistic version of setjmp() that only allows one level of using.
989 * Don't call twice before calling mch_endjmp()!.
990 * Usage:
991 * mch_startjmp();
992 * if (SETJMP(lc_jump_env) != 0)
993 * {
994 * mch_didjmp();
995 * EMSG("crash!");
996 * }
997 * else
998 * {
999 * do_the_work;
1000 * mch_endjmp();
1001 * }
1002 * Note: Can't move SETJMP() here, because a function calling setjmp() must
1003 * not return before the saved environment is used.
1004 * Returns OK for normal return, FAIL when the protected code caused a
1005 * problem and LONGJMP() was used.
1006 */
1007 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001008mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009{
1010#ifdef SIGHASARG
1011 lc_signal = 0;
1012#endif
1013 lc_active = TRUE;
1014}
1015
1016 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001017mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018{
1019 lc_active = FALSE;
1020}
1021
1022 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001023mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024{
1025# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
1026 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
1027 * otherwise catching the signal only works once. */
1028 init_signal_stack();
1029# endif
1030}
1031#endif
1032
1033/*
1034 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001035 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001037 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1038 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 */
1040 static RETSIGTYPE
1041deathtrap SIGDEFARG(sigarg)
1042{
1043 static int entered = 0; /* count the number of times we got here.
1044 Note: when memory has been corrupted
1045 this may get an arbitrary value! */
1046#ifdef SIGHASARG
1047 int i;
1048#endif
1049
1050#if defined(HAVE_SETJMP_H)
1051 /*
1052 * Catch a crash in protected code.
1053 * Restores the environment saved in lc_jump_env, which looks like
1054 * SETJMP() returns 1.
1055 */
1056 if (lc_active)
1057 {
1058# if defined(SIGHASARG)
1059 lc_signal = sigarg;
1060# endif
1061 lc_active = FALSE; /* don't jump again */
1062 LONGJMP(lc_jump_env, 1);
1063 /* NOTREACHED */
1064 }
1065#endif
1066
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001067#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001068# ifdef SIGQUIT
1069 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
1070 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1071 * pressing CTRL-\, but we don't want Vim to exit then. */
1072 if (in_mch_delay && sigarg == SIGQUIT)
1073 SIGRETURN;
1074# endif
1075
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001076 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1077 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1078 * free(). Calling free() again may then cause a crash. */
1079 if (entered == 0
1080 && (0
1081# ifdef SIGHUP
1082 || sigarg == SIGHUP
1083# endif
1084# ifdef SIGQUIT
1085 || sigarg == SIGQUIT
1086# endif
1087# ifdef SIGTERM
1088 || sigarg == SIGTERM
1089# endif
1090# ifdef SIGPWR
1091 || sigarg == SIGPWR
1092# endif
1093# ifdef SIGUSR1
1094 || sigarg == SIGUSR1
1095# endif
1096# ifdef SIGUSR2
1097 || sigarg == SIGUSR2
1098# endif
1099 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001100 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001101 SIGRETURN;
1102#endif
1103
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 /* Remember how often we have been called. */
1105 ++entered;
1106
Bram Moolenaare429e702016-06-10 19:49:14 +02001107 /* Executing autocommands is likely to use more stack space than we have
1108 * available in the signal stack. */
1109 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001110
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111#ifdef FEAT_EVAL
1112 /* Set the v:dying variable. */
1113 set_vim_var_nr(VV_DYING, (long)entered);
1114#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001115 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001117#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 /* Since we are now using the signal stack, need to reset the stack
1119 * limit. Otherwise using a regexp will fail. */
1120 get_stack_limit();
1121#endif
1122
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001123#if 0
1124 /* This is for opening gdb the moment Vim crashes.
1125 * You need to manually adjust the file name and Vim executable name.
1126 * Suggested by SungHyun Nam. */
1127 {
1128# define VI_GDB_FILE "/tmp/vimgdb"
1129# define VIM_NAME "/usr/bin/vim"
1130 FILE *fp = fopen(VI_GDB_FILE, "w");
1131 if (fp)
1132 {
1133 fprintf(fp,
1134 "file %s\n"
1135 "attach %d\n"
1136 "set height 1000\n"
1137 "bt full\n"
1138 , VIM_NAME, getpid());
1139 fclose(fp);
1140 system("xterm -e gdb -x "VI_GDB_FILE);
1141 unlink(VI_GDB_FILE);
1142 }
1143 }
1144#endif
1145
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146#ifdef SIGHASARG
1147 /* try to find the name of this signal */
1148 for (i = 0; signal_info[i].sig != -1; i++)
1149 if (sigarg == signal_info[i].sig)
1150 break;
1151 deadly_signal = sigarg;
1152#endif
1153
1154 full_screen = FALSE; /* don't write message to the GUI, it might be
1155 * part of the problem... */
1156 /*
1157 * If something goes wrong after entering here, we may get here again.
1158 * When this happens, give a message and try to exit nicely (resetting the
1159 * terminal mode, etc.)
1160 * When this happens twice, just exit, don't even try to give a message,
1161 * stack may be corrupt or something weird.
1162 * When this still happens again (or memory was corrupted in such a way
1163 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1164 */
1165 if (entered >= 3)
1166 {
1167 reset_signals(); /* don't catch any signals anymore */
1168 may_core_dump();
1169 if (entered >= 4)
1170 _exit(8);
1171 exit(7);
1172 }
1173 if (entered == 2)
1174 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001175 /* No translation, it may call malloc(). */
1176 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177 out_flush();
1178 getout(1);
1179 }
1180
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001181 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001183 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184 signal_info[i].name);
1185#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001186 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001188
1189 /* Preserve files and exit. This sets the really_exiting flag to prevent
1190 * calling free(). */
1191 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192
Bram Moolenaare429e702016-06-10 19:49:14 +02001193 /* NOTREACHED */
1194
Bram Moolenaar009b2592004-10-24 19:18:58 +00001195#ifdef NBDEBUG
1196 reset_signals();
1197 may_core_dump();
1198 abort();
1199#endif
1200
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 SIGRETURN;
1202}
1203
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001205 * Invoked after receiving SIGCONT. We don't know what happened while
1206 * sleeping, deal with part of that.
1207 */
1208 static void
1209after_sigcont(void)
1210{
1211# ifdef FEAT_TITLE
1212 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1213 // again later.
1214 oldtitle_outdated = TRUE;
1215# endif
1216 settmode(TMODE_RAW);
1217 need_check_timestamps = TRUE;
1218 did_check_timestamps = FALSE;
1219}
1220
1221#if defined(SIGCONT)
1222static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001223static volatile sig_atomic_t in_mch_suspend = FALSE;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001224
1225/*
1226 * With multi-threading, suspending might not work immediately. Catch the
1227 * SIGCONT signal, which will be used as an indication whether the suspending
1228 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001229 *
1230 * On Linux, signal is not always handled immediately either.
1231 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001232 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001233 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001234 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001236static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001237static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238
1239/*
1240 * signal handler for SIGCONT
1241 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 static RETSIGTYPE
1243sigcont_handler SIGDEFARG(sigarg)
1244{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001245 if (in_mch_suspend)
1246 {
1247 sigcont_received = TRUE;
1248 }
1249 else
1250 {
1251 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1252 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1253 // back to a sane mode. We should redraw, but we can't really do that
1254 // in a signal handler, do a redraw later.
1255 after_sigcont();
1256 redraw_later(CLEAR);
1257 cursor_on_force();
1258 out_flush();
1259 }
1260
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261 SIGRETURN;
1262}
1263#endif
1264
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001265#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001266# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001267static void *clip_star_save = NULL;
1268static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001269# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001270
1271/*
1272 * Called when Vim is going to sleep or execute a shell command.
1273 * We can't respond to requests for the X selections. Lose them, otherwise
1274 * other applications will hang. But first copy the text to cut buffer 0.
1275 */
1276 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001277loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001278{
1279 if (clip_star.owned || clip_plus.owned)
1280 {
1281 x11_export_final_selection();
1282 if (clip_star.owned)
1283 clip_lose_selection(&clip_star);
1284 if (clip_plus.owned)
1285 clip_lose_selection(&clip_plus);
1286 if (x11_display != NULL)
1287 XFlush(x11_display);
1288 }
1289}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001290
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001291# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001292/*
1293 * Save clipboard text to restore later.
1294 */
1295 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001296save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001297{
1298 if (clip_star.owned)
1299 clip_star_save = get_register('*', TRUE);
1300 if (clip_plus.owned)
1301 clip_plus_save = get_register('+', TRUE);
1302}
1303
1304/*
1305 * Restore clipboard text if no one own the X selection.
1306 */
1307 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001308restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001309{
1310 if (clip_star_save != NULL)
1311 {
1312 if (!clip_gen_owner_exists(&clip_star))
1313 put_register('*', clip_star_save);
1314 else
1315 free_register(clip_star_save);
1316 clip_star_save = NULL;
1317 }
1318 if (clip_plus_save != NULL)
1319 {
1320 if (!clip_gen_owner_exists(&clip_plus))
1321 put_register('+', clip_plus_save);
1322 else
1323 free_register(clip_plus_save);
1324 clip_plus_save = NULL;
1325 }
1326}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001327# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001328#endif
1329
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330/*
1331 * If the machine has job control, use it to suspend the program,
1332 * otherwise fake it by starting a new shell.
1333 */
1334 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001335mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336{
1337 /* BeOS does have SIGTSTP, but it doesn't work. */
1338#if defined(SIGTSTP) && !defined(__BEOS__)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001339 in_mch_suspend = TRUE;
1340
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 out_flush(); /* needed to make cursor visible on some systems */
1342 settmode(TMODE_COOK);
1343 out_flush(); /* needed to disable mouse on some systems */
1344
1345# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001346 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001347# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001348# if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001349 sigcont_received = FALSE;
1350# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001351
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar2e310482018-08-21 13:09:10 +02001353
1354# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001355 /*
1356 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001357 * immediately, but somehow not all the time, probably because it's handled
1358 * in another thread. Do not call pause() because there would be race
1359 * condition which would hang Vim if signal happened in between the test of
1360 * sigcont_received and the call to pause(). If signal is not yet received,
1361 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1362 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001363 */
1364 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001365 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001366
Bram Moolenaar262735e2009-07-14 10:20:22 +00001367 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar262735e2009-07-14 10:20:22 +00001368 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001371 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372
Bram Moolenaar2e310482018-08-21 13:09:10 +02001373 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374#else
1375 suspend_shell();
1376#endif
1377}
1378
1379 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001380mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381{
1382 Columns = 80;
1383 Rows = 24;
1384
1385 out_flush();
1386 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001387
Bram Moolenaar56718732006-03-15 22:53:57 +00001388#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001389 mac_conv_init();
1390#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001391#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1392 win_clip_init();
1393#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394}
1395
1396 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001397set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398{
1399#if defined(SIGWINCH)
1400 /*
1401 * WINDOW CHANGE signal is handled with sig_winch().
1402 */
1403 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1404#endif
1405
1406 /*
1407 * We want the STOP signal to work, to make mch_suspend() work.
1408 * For "rvim" the STOP signal is ignored.
1409 */
1410#ifdef SIGTSTP
1411 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1412#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001413#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414 signal(SIGCONT, sigcont_handler);
1415#endif
1416
1417 /*
1418 * We want to ignore breaking of PIPEs.
1419 */
1420#ifdef SIGPIPE
1421 signal(SIGPIPE, SIG_IGN);
1422#endif
1423
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001425 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426#endif
1427
1428 /*
1429 * Ignore alarm signals (Perl's alarm() generates it).
1430 */
1431#ifdef SIGALRM
1432 signal(SIGALRM, SIG_IGN);
1433#endif
1434
1435 /*
1436 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1437 * work will be lost.
1438 */
1439#ifdef SIGPWR
1440 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1441#endif
1442
1443 /*
1444 * Arrange for other signals to gracefully shutdown Vim.
1445 */
1446 catch_signals(deathtrap, SIG_ERR);
1447
1448#if defined(FEAT_GUI) && defined(SIGHUP)
1449 /*
1450 * When the GUI is running, ignore the hangup signal.
1451 */
1452 if (gui.in_use)
1453 signal(SIGHUP, SIG_IGN);
1454#endif
1455}
1456
Bram Moolenaardf177f62005-02-22 08:39:57 +00001457#if defined(SIGINT) || defined(PROTO)
1458/*
1459 * Catch CTRL-C (only works while in Cooked mode).
1460 */
1461 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001462catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001463{
1464 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1465}
1466#endif
1467
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001469reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470{
1471 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001472#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 /* SIGCONT isn't in the list, because its default action is ignore */
1474 signal(SIGCONT, SIG_DFL);
1475#endif
1476}
1477
1478 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001479catch_signals(
1480 RETSIGTYPE (*func_deadly)(),
1481 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482{
1483 int i;
1484
1485 for (i = 0; signal_info[i].sig != -1; i++)
1486 if (signal_info[i].deadly)
1487 {
1488#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1489 struct sigaction sa;
1490
1491 /* Setup to use the alternate stack for the signal function. */
1492 sa.sa_handler = func_deadly;
1493 sigemptyset(&sa.sa_mask);
1494# if defined(__linux__) && defined(_REENTRANT)
1495 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1496 * thread handling in combination with using the alternate stack:
1497 * pthread library functions try to use the stack pointer to
1498 * identify the current thread, causing a SEGV signal, which
1499 * recursively calls deathtrap() and hangs. */
1500 sa.sa_flags = 0;
1501# else
1502 sa.sa_flags = SA_ONSTACK;
1503# endif
1504 sigaction(signal_info[i].sig, &sa, NULL);
1505#else
1506# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1507 struct sigvec sv;
1508
1509 /* Setup to use the alternate stack for the signal function. */
1510 sv.sv_handler = func_deadly;
1511 sv.sv_mask = 0;
1512 sv.sv_flags = SV_ONSTACK;
1513 sigvec(signal_info[i].sig, &sv, NULL);
1514# else
1515 signal(signal_info[i].sig, func_deadly);
1516# endif
1517#endif
1518 }
1519 else if (func_other != SIG_ERR)
1520 signal(signal_info[i].sig, func_other);
1521}
1522
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001523#ifdef HAVE_SIGPROCMASK
1524 static void
1525block_signals(sigset_t *set)
1526{
1527 sigset_t newset;
1528 int i;
1529
1530 sigemptyset(&newset);
1531
1532 for (i = 0; signal_info[i].sig != -1; i++)
1533 sigaddset(&newset, signal_info[i].sig);
1534
Bram Moolenaar2e310482018-08-21 13:09:10 +02001535# if defined(SIGCONT)
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001536 /* SIGCONT isn't in the list, because its default action is ignore */
1537 sigaddset(&newset, SIGCONT);
1538# endif
1539
1540 sigprocmask(SIG_BLOCK, &newset, set);
1541}
1542
1543 static void
1544unblock_signals(sigset_t *set)
1545{
1546 sigprocmask(SIG_SETMASK, set, NULL);
1547}
1548#endif
1549
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001551 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001552 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1553 * return TRUE
1554 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1555 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001556 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001557 * Returns TRUE when Vim should exit.
1558 */
1559 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001560vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001561{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001562 static int got_signal = 0;
1563 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001564
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001565 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001566 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001567 case SIGNAL_BLOCK: blocked = TRUE;
1568 break;
1569
1570 case SIGNAL_UNBLOCK: blocked = FALSE;
1571 if (got_signal != 0)
1572 {
1573 kill(getpid(), got_signal);
1574 got_signal = 0;
1575 }
1576 break;
1577
1578 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001579 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001580 got_signal = sig;
1581#ifdef SIGPWR
1582 if (sig != SIGPWR)
1583#endif
1584 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001585 break;
1586 }
1587 return FALSE;
1588}
1589
1590/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 * Check_win checks whether we have an interactive stdout.
1592 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001594mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 if (isatty(1))
1597 return OK;
1598 return FAIL;
1599}
1600
1601/*
1602 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1603 */
1604 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001605mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606{
1607 if (isatty(read_cmd_fd))
1608 return TRUE;
1609 return FALSE;
1610}
1611
1612#ifdef FEAT_X11
1613
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001614# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1616
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617/*
1618 * Give a message about the elapsed time for opening the X window.
1619 */
1620 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001621xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622{
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001623 smsg((char_u *)_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001624}
1625# endif
1626#endif
1627
1628#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1629/*
1630 * A few functions shared by X11 title and clipboard code.
1631 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632
1633static int got_x_error = FALSE;
1634
1635/*
1636 * X Error handler, otherwise X just exits! (very rude) -- webb
1637 */
1638 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001639x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001641 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001642 STRCAT(IObuff, _("\nVim: Got X error\n"));
1643
1644 /* We cannot print a message and continue, because no X calls are allowed
1645 * here (causes my system to hang). Silently continuing might be an
1646 * alternative... */
1647 preserve_exit(); /* preserve files and exit */
1648
1649 return 0; /* NOTREACHED */
1650}
1651
1652/*
1653 * Another X Error handler, just used to check for errors.
1654 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001656x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657{
1658 got_x_error = TRUE;
1659 return 0;
1660}
1661
1662#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1663# if defined(HAVE_SETJMP_H)
1664/*
1665 * An X IO Error handler, used to catch error while opening the display.
1666 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001668x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669{
1670 /* This function should not return, it causes exit(). Longjump instead. */
1671 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001672# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001673 return 0; /* avoid the compiler complains about missing return value */
1674# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675}
1676# endif
1677
1678/*
1679 * An X IO Error handler, used to catch terminal errors.
1680 */
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001681static int xterm_dpy_was_reset = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001684x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685{
1686 xterm_dpy = NULL;
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001687 xterm_dpy_was_reset = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688 x11_window = 0;
1689 x11_display = NULL;
1690 xterm_Shell = (Widget)0;
1691
1692 /* This function should not return, it causes exit(). Longjump instead. */
1693 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001694# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001695 return 0; /* avoid the compiler complains about missing return value */
1696# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001698
1699/*
1700 * If the X11 connection was lost try to restore it.
1701 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001702 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001703 */
1704 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001705may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001706{
1707 if (xterm_dpy_was_reset)
1708 {
1709 xterm_dpy_was_reset = FALSE;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001710
1711# ifndef LESSTIF_VERSION
1712 /* This has been reported to avoid Vim getting stuck. */
1713 if (app_context != (XtAppContext)NULL)
1714 {
1715 XtDestroyApplicationContext(app_context);
1716 app_context = (XtAppContext)NULL;
1717 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
1718 }
1719# endif
1720
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001721 setup_term_clip();
1722 get_x11_title(FALSE);
1723 }
1724}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725#endif
1726
1727/*
1728 * Return TRUE when connection to the X server is desired.
1729 */
1730 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001731x_connect_to_server(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733#if defined(FEAT_CLIENTSERVER)
1734 if (x_force_connect)
1735 return TRUE;
1736#endif
1737 if (x_no_connect)
1738 return FALSE;
1739
1740 /* Check for a match with "exclude:" from 'clipboard'. */
1741 if (clip_exclude_prog != NULL)
1742 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01001743 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 return FALSE;
1745 }
1746 return TRUE;
1747}
1748
1749/*
1750 * Test if "dpy" and x11_window are valid by getting the window title.
1751 * I don't actually want it yet, so there may be a simpler call to use, but
1752 * this will cause the error handler x_error_check() to be called if anything
1753 * is wrong, such as the window pointer being invalid (as can happen when the
1754 * user changes his DISPLAY, but not his WINDOWID) -- webb
1755 */
1756 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001757test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758{
1759 int (*old_handler)();
1760 XTextProperty text_prop;
1761
1762 old_handler = XSetErrorHandler(x_error_check);
1763 got_x_error = FALSE;
1764 if (XGetWMName(dpy, x11_window, &text_prop))
1765 XFree((void *)text_prop.value);
1766 XSync(dpy, False);
1767 (void)XSetErrorHandler(old_handler);
1768
1769 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001770 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771
1772 return (got_x_error ? FAIL : OK);
1773}
1774#endif
1775
1776#ifdef FEAT_TITLE
1777
1778#ifdef FEAT_X11
1779
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001780static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781
1782/*
1783 * try to get x11 window and display
1784 *
1785 * return FAIL for failure, OK otherwise
1786 */
1787 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001788get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789{
1790 char *winid;
1791 static int result = -1;
1792#define XD_NONE 0 /* x11_display not set here */
1793#define XD_HERE 1 /* x11_display opened here */
1794#define XD_GUI 2 /* x11_display used from gui.dpy */
1795#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1796 static int x11_display_from = XD_NONE;
1797 static int did_set_error_handler = FALSE;
1798
1799 if (!did_set_error_handler)
1800 {
1801 /* X just exits if it finds an error otherwise! */
1802 (void)XSetErrorHandler(x_error_handler);
1803 did_set_error_handler = TRUE;
1804 }
1805
Bram Moolenaar9372a112005-12-06 19:59:18 +00001806#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807 if (gui.in_use)
1808 {
1809 /*
1810 * If the X11 display was opened here before, for the window where Vim
1811 * was started, close that one now to avoid a memory leak.
1812 */
1813 if (x11_display_from == XD_HERE && x11_display != NULL)
1814 {
1815 XCloseDisplay(x11_display);
1816 x11_display_from = XD_NONE;
1817 }
1818 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1819 {
1820 x11_display_from = XD_GUI;
1821 return OK;
1822 }
1823 x11_display = NULL;
1824 return FAIL;
1825 }
1826 else if (x11_display_from == XD_GUI)
1827 {
1828 /* GUI must have stopped somehow, clear x11_display */
1829 x11_window = 0;
1830 x11_display = NULL;
1831 x11_display_from = XD_NONE;
1832 }
1833#endif
1834
1835 /* When started with the "-X" argument, don't try connecting. */
1836 if (!x_connect_to_server())
1837 return FAIL;
1838
1839 /*
1840 * If WINDOWID not set, should try another method to find out
1841 * what the current window number is. The only code I know for
1842 * this is very complicated.
1843 * We assume that zero is invalid for WINDOWID.
1844 */
1845 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1846 x11_window = (Window)atol(winid);
1847
1848#ifdef FEAT_XCLIPBOARD
1849 if (xterm_dpy != NULL && x11_window != 0)
1850 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001851 /* We may have checked it already, but Gnome terminal can move us to
1852 * another window, so we need to check every time. */
1853 if (x11_display_from != XD_XTERM)
1854 {
1855 /*
1856 * If the X11 display was opened here before, for the window where
1857 * Vim was started, close that one now to avoid a memory leak.
1858 */
1859 if (x11_display_from == XD_HERE && x11_display != NULL)
1860 XCloseDisplay(x11_display);
1861 x11_display = xterm_dpy;
1862 x11_display_from = XD_XTERM;
1863 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 if (test_x11_window(x11_display) == FAIL)
1865 {
1866 /* probably bad $WINDOWID */
1867 x11_window = 0;
1868 x11_display = NULL;
1869 x11_display_from = XD_NONE;
1870 return FAIL;
1871 }
1872 return OK;
1873 }
1874#endif
1875
1876 if (x11_window == 0 || x11_display == NULL)
1877 result = -1;
1878
1879 if (result != -1) /* Have already been here and set this */
1880 return result; /* Don't do all these X calls again */
1881
1882 if (x11_window != 0 && x11_display == NULL)
1883 {
1884#ifdef SET_SIG_ALARM
1885 RETSIGTYPE (*sig_save)();
1886#endif
1887#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1888 struct timeval start_tv;
1889
1890 if (p_verbose > 0)
1891 gettimeofday(&start_tv, NULL);
1892#endif
1893
1894#ifdef SET_SIG_ALARM
1895 /*
1896 * Opening the Display may hang if the DISPLAY setting is wrong, or
1897 * the network connection is bad. Set an alarm timer to get out.
1898 */
1899 sig_alarm_called = FALSE;
1900 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1901 (RETSIGTYPE (*)())sig_alarm);
1902 alarm(2);
1903#endif
1904 x11_display = XOpenDisplay(NULL);
1905
1906#ifdef SET_SIG_ALARM
1907 alarm(0);
1908 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1909 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001910 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911#endif
1912 if (x11_display != NULL)
1913 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001914# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001916 {
1917 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001918 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001919 verbose_leave();
1920 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921# endif
1922 if (test_x11_window(x11_display) == FAIL)
1923 {
1924 /* Maybe window id is bad */
1925 x11_window = 0;
1926 XCloseDisplay(x11_display);
1927 x11_display = NULL;
1928 }
1929 else
1930 x11_display_from = XD_HERE;
1931 }
1932 }
1933 if (x11_window == 0 || x11_display == NULL)
1934 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001935
1936# ifdef FEAT_EVAL
1937 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1938# endif
1939
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 return (result = OK);
1941}
1942
1943/*
1944 * Determine original x11 Window Title
1945 */
1946 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001947get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001949 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950}
1951
1952/*
1953 * Determine original x11 Window icon
1954 */
1955 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001956get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957{
1958 int retval = FALSE;
1959
1960 retval = get_x11_thing(FALSE, test_only);
1961
1962 /* could not get old icon, use terminal name */
1963 if (oldicon == NULL && !test_only)
1964 {
1965 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001966 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001968 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 }
1970
1971 return retval;
1972}
1973
1974 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001975get_x11_thing(
1976 int get_title, /* get title string */
1977 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978{
1979 XTextProperty text_prop;
1980 int retval = FALSE;
1981 Status status;
1982
1983 if (get_x11_windis() == OK)
1984 {
1985 /* Get window/icon name if any */
1986 if (get_title)
1987 status = XGetWMName(x11_display, x11_window, &text_prop);
1988 else
1989 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1990
1991 /*
1992 * If terminal is xterm, then x11_window may be a child window of the
1993 * outer xterm window that actually contains the window/icon name, so
1994 * keep traversing up the tree until a window with a title/icon is
1995 * found.
1996 */
1997 /* Previously this was only done for xterm and alikes. I don't see a
1998 * reason why it would fail for other terminal emulators.
1999 * if (term_is_xterm) */
2000 {
2001 Window root;
2002 Window parent;
2003 Window win = x11_window;
2004 Window *children;
2005 unsigned int num_children;
2006
2007 while (!status || text_prop.value == NULL)
2008 {
2009 if (!XQueryTree(x11_display, win, &root, &parent, &children,
2010 &num_children))
2011 break;
2012 if (children)
2013 XFree((void *)children);
2014 if (parent == root || parent == 0)
2015 break;
2016
2017 win = parent;
2018 if (get_title)
2019 status = XGetWMName(x11_display, win, &text_prop);
2020 else
2021 status = XGetWMIconName(x11_display, win, &text_prop);
2022 }
2023 }
2024 if (status && text_prop.value != NULL)
2025 {
2026 retval = TRUE;
2027 if (!test_only)
2028 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002029#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
2030 if (text_prop.encoding == XA_STRING
2031# ifdef FEAT_MBYTE
2032 && !has_mbyte
2033# endif
2034 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035 {
2036#endif
2037 if (get_title)
2038 oldtitle = vim_strsave((char_u *)text_prop.value);
2039 else
2040 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002041#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 }
2043 else
2044 {
2045 char **cl;
2046 Status transform_status;
2047 int n = 0;
2048
2049 transform_status = XmbTextPropertyToTextList(x11_display,
2050 &text_prop,
2051 &cl, &n);
2052 if (transform_status >= Success && n > 0 && cl[0])
2053 {
2054 if (get_title)
2055 oldtitle = vim_strsave((char_u *) cl[0]);
2056 else
2057 oldicon = vim_strsave((char_u *) cl[0]);
2058 XFreeStringList(cl);
2059 }
2060 else
2061 {
2062 if (get_title)
2063 oldtitle = vim_strsave((char_u *)text_prop.value);
2064 else
2065 oldicon = vim_strsave((char_u *)text_prop.value);
2066 }
2067 }
2068#endif
2069 }
2070 XFree((void *)text_prop.value);
2071 }
2072 }
2073 return retval;
2074}
2075
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002076/* Xutf8 functions are not avaialble on older systems. Note that on some
2077 * systems X_HAVE_UTF8_STRING may be defined in a header file but
2078 * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2079 * that and defines HAVE_XUTF8SETWMPROPERTIES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002081# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082# define USE_UTF8_STRING
2083# endif
2084#endif
2085
2086/*
2087 * Set x11 Window Title
2088 *
2089 * get_x11_windis() must be called before this and have returned OK
2090 */
2091 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002092set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093{
2094 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2095 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2096 * supported everywhere and STRING doesn't work for multi-byte titles.
2097 */
2098#ifdef USE_UTF8_STRING
2099 if (enc_utf8)
2100 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2101 NULL, NULL, 0, NULL, NULL, NULL);
2102 else
2103#endif
2104 {
2105#if XtSpecificationRelease >= 4
2106# ifdef FEAT_XFONTSET
2107 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2108 NULL, NULL, 0, NULL, NULL, NULL);
2109# else
2110 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002111 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112
2113 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002114 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 XSetWMProperties(x11_display, x11_window, &text_prop,
2116 NULL, NULL, 0, NULL, NULL, NULL);
2117# endif
2118#else
2119 XStoreName(x11_display, x11_window, (char *)title);
2120#endif
2121 }
2122 XFlush(x11_display);
2123}
2124
2125/*
2126 * Set x11 Window icon
2127 *
2128 * get_x11_windis() must be called before this and have returned OK
2129 */
2130 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002131set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132{
2133 /* See above for comments about using X*SetWMProperties(). */
2134#ifdef USE_UTF8_STRING
2135 if (enc_utf8)
2136 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2137 NULL, 0, NULL, NULL, NULL);
2138 else
2139#endif
2140 {
2141#if XtSpecificationRelease >= 4
2142# ifdef FEAT_XFONTSET
2143 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2144 NULL, 0, NULL, NULL, NULL);
2145# else
2146 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002147 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002149 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002150 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2151 NULL, 0, NULL, NULL, NULL);
2152# endif
2153#else
2154 XSetIconName(x11_display, x11_window, (char *)icon);
2155#endif
2156 }
2157 XFlush(x11_display);
2158}
2159
2160#else /* FEAT_X11 */
2161
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002163get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164{
2165 return FALSE;
2166}
2167
2168 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002169get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170{
2171 if (!test_only)
2172 {
2173 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002174 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002176 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177 }
2178 return FALSE;
2179}
2180
2181#endif /* FEAT_X11 */
2182
2183 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002184mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185{
2186 return get_x11_title(TRUE);
2187}
2188
2189 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002190mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191{
2192 return get_x11_icon(TRUE);
2193}
2194
2195/*
2196 * Set the window title and icon.
2197 */
2198 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002199mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200{
2201 int type = 0;
2202 static int recursive = 0;
2203
2204 if (T_NAME == NULL) /* no terminal name (yet) */
2205 return;
2206 if (title == NULL && icon == NULL) /* nothing to do */
2207 return;
2208
2209 /* When one of the X11 functions causes a deadly signal, we get here again
2210 * recursively. Avoid hanging then (something is probably locked). */
2211 if (recursive)
2212 return;
2213 ++recursive;
2214
2215 /*
2216 * if the window ID and the display is known, we may use X11 calls
2217 */
2218#ifdef FEAT_X11
2219 if (get_x11_windis() == OK)
2220 type = 1;
2221#else
2222# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2223 if (gui.in_use)
2224 type = 1;
2225# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226#endif
2227
2228 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002229 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230 * than x11 calls, because the x11 calls don't always work
2231 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232 if ((type || *T_TS != NUL) && title != NULL)
2233 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002234 if (oldtitle_outdated)
2235 {
2236 oldtitle_outdated = FALSE;
2237 VIM_CLEAR(oldtitle);
2238 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 if (oldtitle == NULL
2240#ifdef FEAT_GUI
2241 && !gui.in_use
2242#endif
2243 ) /* first call but not in GUI, save title */
2244 (void)get_x11_title(FALSE);
2245
2246 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2247 term_settitle(title);
2248#ifdef FEAT_X11
2249 else
2250# ifdef FEAT_GUI_GTK
2251 if (!gui.in_use) /* don't do this if GTK+ is running */
2252# endif
2253 set_x11_title(title); /* x11 */
2254#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002255#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2257 else
2258 gui_mch_settitle(title, icon);
2259#endif
2260 did_set_title = TRUE;
2261 }
2262
2263 if ((type || *T_CIS != NUL) && icon != NULL)
2264 {
2265 if (oldicon == NULL
2266#ifdef FEAT_GUI
2267 && !gui.in_use
2268#endif
2269 ) /* first call, save icon */
2270 get_x11_icon(FALSE);
2271
2272 if (*T_CIS != NUL)
2273 {
2274 out_str(T_CIS); /* set icon start */
2275 out_str_nf(icon);
2276 out_str(T_CIE); /* set icon end */
2277 out_flush();
2278 }
2279#ifdef FEAT_X11
2280 else
2281# ifdef FEAT_GUI_GTK
2282 if (!gui.in_use) /* don't do this if GTK+ is running */
2283# endif
2284 set_x11_icon(icon); /* x11 */
2285#endif
2286 did_set_icon = TRUE;
2287 }
2288 --recursive;
2289}
2290
2291/*
2292 * Restore the window/icon title.
2293 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002294 * SAVE_RESTORE_TITLE only restore title
2295 * SAVE_RESTORE_ICON only restore icon
2296 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 */
2298 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002299mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300{
2301 /* only restore the title or icon when it has been set */
Bram Moolenaar40385db2018-08-07 22:31:44 +02002302 mch_settitle(((which & SAVE_RESTORE_TITLE) && did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002304 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2305
2306 // pop and push from/to the stack
2307 term_pop_title(which);
2308 term_push_title(which);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309}
2310
2311#endif /* FEAT_TITLE */
2312
2313/*
2314 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002315 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 */
2317 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002318vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319{
2320 if (name == NULL)
2321 return FALSE;
2322 return (STRNICMP(name, "xterm", 5) == 0
2323 || STRNICMP(name, "nxterm", 6) == 0
2324 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002325 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002327 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 || STRCMP(name, "builtin_xterm") == 0);
2329}
2330
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002331#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2332/*
2333 * Return TRUE if "name" appears to be that of a terminal
2334 * known to support the xterm-style mouse protocol.
2335 * Relies on term_is_xterm having been set to its correct value.
2336 */
2337 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002338use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002339{
2340 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002341 && (term_is_xterm
2342 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002343 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002344 || STRICMP(name, "st") == 0
2345 || STRNICMP(name, "st-", 3) == 0
2346 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002347}
2348#endif
2349
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2351/*
2352 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2353 * Return 1 for "xterm".
2354 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002355 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002356 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 */
2358 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002359use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002361 if (ttym_flags == TTYM_SGR)
2362 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002363 if (ttym_flags == TTYM_URXVT)
2364 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 if (ttym_flags == TTYM_XTERM2)
2366 return 2;
2367 if (ttym_flags == TTYM_XTERM)
2368 return 1;
2369 return 0;
2370}
2371#endif
2372
2373 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002374vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375{
2376 if (name == NULL)
2377 return FALSE;
2378 return (STRNICMP(name, "iris-ansi", 9) == 0
2379 || STRCMP(name, "builtin_iris-ansi") == 0);
2380}
2381
2382 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002383vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384{
2385 if (name == NULL)
2386 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002387 /* catch VT100 - VT5xx */
2388 return ((STRNICMP(name, "vt", 2) == 0
2389 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 || STRCMP(name, "builtin_vt320") == 0);
2391}
2392
2393/*
2394 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2395 * This should include all windowed terminal emulators.
2396 */
2397 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002398vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399{
2400 if (name == NULL)
2401 return FALSE;
2402 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2403 return TRUE;
2404 return ( STRNICMP(name, "hpterm", 6) == 0
2405 || STRNICMP(name, "sun-cmd", 7) == 0
2406 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002407 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 || STRNICMP(name, "dtterm", 6) == 0);
2409}
2410
2411/*
2412 * Insert user name in s[len].
2413 * Return OK if a name found.
2414 */
2415 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002416mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417{
2418#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002419 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 return OK;
2421#else
2422 return mch_get_uname(getuid(), s, len);
2423#endif
2424}
2425
2426/*
2427 * Insert user name for "uid" in s[len].
2428 * Return OK if a name found.
2429 */
2430 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002431mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432{
2433#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2434 struct passwd *pw;
2435
2436 if ((pw = getpwuid(uid)) != NULL
2437 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2438 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002439 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 return OK;
2441 }
2442#endif
2443 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2444 return FAIL; /* a number is not a name */
2445}
2446
2447/*
2448 * Insert host name is s[len].
2449 */
2450
2451#ifdef HAVE_SYS_UTSNAME_H
2452 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002453mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454{
2455 struct utsname vutsname;
2456
2457 if (uname(&vutsname) < 0)
2458 *s = NUL;
2459 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002460 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461}
2462#else /* HAVE_SYS_UTSNAME_H */
2463
2464# ifdef HAVE_SYS_SYSTEMINFO_H
2465# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2466# endif
2467
2468 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002469mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470{
2471# ifdef VAXC
2472 vaxc$gethostname((char *)s, len);
2473# else
2474 gethostname((char *)s, len);
2475# endif
2476 s[len - 1] = NUL; /* make sure it's terminated */
2477}
2478#endif /* HAVE_SYS_UTSNAME_H */
2479
2480/*
2481 * return process ID
2482 */
2483 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002484mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485{
2486 return (long)getpid();
2487}
2488
2489#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002491strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492{
2493 extern int sys_nerr;
2494 extern char *sys_errlist[];
2495 static char er[20];
2496
2497 if (err > 0 && err < sys_nerr)
2498 return (sys_errlist[err]);
2499 sprintf(er, "Error %d", err);
2500 return er;
2501}
2502#endif
2503
2504/*
2505 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2506 * Return OK for success, FAIL for failure.
2507 */
2508 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002509mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510{
2511#if defined(USE_GETCWD)
2512 if (getcwd((char *)buf, len) == NULL)
2513 {
2514 STRCPY(buf, strerror(errno));
2515 return FAIL;
2516 }
2517 return OK;
2518#else
2519 return (getwd((char *)buf) != NULL ? OK : FAIL);
2520#endif
2521}
2522
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002524 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 *
2526 * return FAIL for failure, OK for success
2527 */
2528 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002529mch_FullName(
2530 char_u *fname,
2531 char_u *buf,
2532 int len,
2533 int force) /* also expand when already absolute path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534{
2535 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002536#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537 int fd = -1;
2538 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002539#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 char_u olddir[MAXPATHL];
2541 char_u *p;
2542 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002543#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002544 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2545 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002546#endif
2547
Bram Moolenaar38323e42007-03-06 19:22:53 +00002548#ifdef VMS
2549 fname = vms_fixfilename(fname);
2550#endif
2551
Bram Moolenaara2442432007-04-26 14:26:37 +00002552#ifdef __CYGWIN__
2553 /*
2554 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2555 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002556# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar06b07342015-12-31 22:26:28 +01002557 /* Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2558 * a forward slash. */
2559 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2560 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002561# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002562 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002563# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002564 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002565#endif
2566
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002567 /* Expand it if forced or not an absolute path.
2568 * Do not do it for "/file", the result is always "/". */
2569 if ((force || !mch_isFullName(fname))
2570 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 {
2572 /*
2573 * If the file name has a path, change to that directory for a moment,
2574 * and then do the getwd() (and get back to where we were).
2575 * This will get the correct path name with "../" things.
2576 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002577 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002579#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 /*
2581 * Use fchdir() if possible, it's said to be faster and more
2582 * reliable. But on SunOS 4 it might not work. Check this by
2583 * doing a fchdir() right now.
2584 */
2585 if (!dont_fchdir)
2586 {
2587 fd = open(".", O_RDONLY | O_EXTRA, 0);
2588 if (fd >= 0 && fchdir(fd) < 0)
2589 {
2590 close(fd);
2591 fd = -1;
2592 dont_fchdir = TRUE; /* don't try again */
2593 }
2594 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002595#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596
2597 /* Only change directory when we are sure we can return to where
2598 * we are now. After doing "su" chdir(".") might not work. */
2599 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002600#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002603 (mch_dirname(olddir, MAXPATHL) == FAIL
2604 || mch_chdir((char *)olddir) != 0))
2605 {
2606 p = NULL; /* can't get current dir: don't chdir */
2607 retval = FAIL;
2608 }
2609 else
2610 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611 /* The directory is copied into buf[], to be able to remove
2612 * the file name without changing it (could be a string in
2613 * read-only memory) */
2614 if (p - fname >= len)
2615 retval = FAIL;
2616 else
2617 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002618 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619 if (mch_chdir((char *)buf))
2620 retval = FAIL;
2621 else
2622 fname = p + 1;
2623 *buf = NUL;
2624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625 }
2626 }
2627 if (mch_dirname(buf, len) == FAIL)
2628 {
2629 retval = FAIL;
2630 *buf = NUL;
2631 }
2632 if (p != NULL)
2633 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002634#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 if (fd >= 0)
2636 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002637 if (p_verbose >= 5)
2638 {
2639 verbose_enter();
2640 MSG("fchdir() to previous dir");
2641 verbose_leave();
2642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 l = fchdir(fd);
2644 close(fd);
2645 }
2646 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002647#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 l = mch_chdir((char *)olddir);
2649 if (l != 0)
2650 EMSG(_(e_prev_dir));
2651 }
2652
2653 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002654 if (l >= len - 1)
2655 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002656#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002657 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002659 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002660#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002662
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002664 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 return FAIL;
2666
2667 /* Do not append ".", "/dir/." is equal to "/dir". */
2668 if (STRCMP(fname, ".") != 0)
2669 STRCAT(buf, fname);
2670
2671 return OK;
2672}
2673
2674/*
2675 * Return TRUE if "fname" does not depend on the current directory.
2676 */
2677 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002678mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002680#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 return ( fname[0] == '/' || fname[0] == '.' ||
2682 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2683 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2684 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002685#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687#endif
2688}
2689
Bram Moolenaar24552be2005-12-10 20:17:30 +00002690#if defined(USE_FNAME_CASE) || defined(PROTO)
2691/*
2692 * Set the case of the file name, if it already exists. This will cause the
2693 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002694 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002695 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002696 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002697fname_case(
2698 char_u *name,
2699 int len UNUSED) /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002700{
2701 struct stat st;
2702 char_u *slash, *tail;
2703 DIR *dirp;
2704 struct dirent *dp;
2705
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002706 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002707 {
2708 /* Open the directory where the file is located. */
2709 slash = vim_strrchr(name, '/');
2710 if (slash == NULL)
2711 {
2712 dirp = opendir(".");
2713 tail = name;
2714 }
2715 else
2716 {
2717 *slash = NUL;
2718 dirp = opendir((char *)name);
2719 *slash = '/';
2720 tail = slash + 1;
2721 }
2722
2723 if (dirp != NULL)
2724 {
2725 while ((dp = readdir(dirp)) != NULL)
2726 {
2727 /* Only accept names that differ in case and are the same byte
2728 * length. TODO: accept different length name. */
2729 if (STRICMP(tail, dp->d_name) == 0
2730 && STRLEN(tail) == STRLEN(dp->d_name))
2731 {
2732 char_u newname[MAXPATHL + 1];
2733 struct stat st2;
2734
2735 /* Verify the inode is equal. */
2736 vim_strncpy(newname, name, MAXPATHL);
2737 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2738 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002739 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002740 && st.st_ino == st2.st_ino
2741 && st.st_dev == st2.st_dev)
2742 {
2743 STRCPY(tail, dp->d_name);
2744 break;
2745 }
2746 }
2747 }
2748
2749 closedir(dirp);
2750 }
2751 }
2752}
2753#endif
2754
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755/*
2756 * Get file permissions for 'name'.
2757 * Returns -1 when it doesn't exist.
2758 */
2759 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002760mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761{
2762 struct stat statb;
2763
2764 /* Keep the #ifdef outside of stat(), it may be a macro. */
2765#ifdef VMS
2766 if (stat((char *)vms_fixfilename(name), &statb))
2767#else
2768 if (stat((char *)name, &statb))
2769#endif
2770 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002771#ifdef __INTERIX
2772 /* The top bit makes the value negative, which means the file doesn't
2773 * exist. Remove the bit, we don't use it. */
2774 return statb.st_mode & ~S_ADDACE;
2775#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002777#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002778}
2779
2780/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002781 * Set file permission for "name" to "perm".
2782 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 */
2784 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002785mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786{
2787 return (chmod((char *)
2788#ifdef VMS
2789 vms_fixfilename(name),
2790#else
2791 name,
2792#endif
2793 (mode_t)perm) == 0 ? OK : FAIL);
2794}
2795
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002796#if defined(HAVE_FCHMOD) || defined(PROTO)
2797/*
2798 * Set file permission for open file "fd" to "perm".
2799 * Return FAIL for failure, OK otherwise.
2800 */
2801 int
2802mch_fsetperm(int fd, long perm)
2803{
2804 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2805}
2806#endif
2807
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808#if defined(HAVE_ACL) || defined(PROTO)
2809# ifdef HAVE_SYS_ACL_H
2810# include <sys/acl.h>
2811# endif
2812# ifdef HAVE_SYS_ACCESS_H
2813# include <sys/access.h>
2814# endif
2815
2816# ifdef HAVE_SOLARIS_ACL
2817typedef struct vim_acl_solaris_T {
2818 int acl_cnt;
2819 aclent_t *acl_entry;
2820} vim_acl_solaris_T;
2821# endif
2822
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002823#if defined(HAVE_SELINUX) || defined(PROTO)
2824/*
2825 * Copy security info from "from_file" to "to_file".
2826 */
2827 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002828mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002829{
2830 if (from_file == NULL)
2831 return;
2832
2833 if (selinux_enabled == -1)
2834 selinux_enabled = is_selinux_enabled();
2835
2836 if (selinux_enabled > 0)
2837 {
2838 security_context_t from_context = NULL;
2839 security_context_t to_context = NULL;
2840
2841 if (getfilecon((char *)from_file, &from_context) < 0)
2842 {
2843 /* If the filesystem doesn't support extended attributes,
2844 the original had no special security context and the
2845 target cannot have one either. */
2846 if (errno == EOPNOTSUPP)
2847 return;
2848
2849 MSG_PUTS(_("\nCould not get security context for "));
2850 msg_outtrans(from_file);
2851 msg_putchar('\n');
2852 return;
2853 }
2854 if (getfilecon((char *)to_file, &to_context) < 0)
2855 {
2856 MSG_PUTS(_("\nCould not get security context for "));
2857 msg_outtrans(to_file);
2858 msg_putchar('\n');
2859 freecon (from_context);
2860 return ;
2861 }
2862 if (strcmp(from_context, to_context) != 0)
2863 {
2864 if (setfilecon((char *)to_file, from_context) < 0)
2865 {
2866 MSG_PUTS(_("\nCould not set security context for "));
2867 msg_outtrans(to_file);
2868 msg_putchar('\n');
2869 }
2870 }
2871 freecon(to_context);
2872 freecon(from_context);
2873 }
2874}
2875#endif /* HAVE_SELINUX */
2876
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002877#if defined(HAVE_SMACK) && !defined(PROTO)
2878/*
2879 * Copy security info from "from_file" to "to_file".
2880 */
2881 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002882mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002883{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002884 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002885 {
2886 XATTR_NAME_SMACK,
2887 XATTR_NAME_SMACKEXEC,
2888 XATTR_NAME_SMACKMMAP
2889 };
2890
2891 char buffer[SMACK_LABEL_LEN];
2892 const char *name;
2893 int index;
2894 int ret;
2895 ssize_t size;
2896
2897 if (from_file == NULL)
2898 return;
2899
2900 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2901 / sizeof(smack_copied_attributes)[0]) ; index++)
2902 {
2903 /* get the name of the attribute to copy */
2904 name = smack_copied_attributes[index];
2905
2906 /* get the value of the attribute in buffer */
2907 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2908 if (size >= 0)
2909 {
2910 /* copy the attribute value of buffer */
2911 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2912 if (ret < 0)
2913 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002914 vim_snprintf((char *)IObuff, IOSIZE,
2915 _("Could not set security context %s for %s"),
2916 name, to_file);
2917 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002918 msg_putchar('\n');
2919 }
2920 }
2921 else
2922 {
2923 /* what reason of not having the attribute value? */
2924 switch (errno)
2925 {
2926 case ENOTSUP:
2927 /* extended attributes aren't supported or enabled */
2928 /* should a message be echoed? not sure... */
2929 return; /* leave because it isn't usefull to continue */
2930
2931 case ERANGE:
2932 default:
2933 /* no enough size OR unexpected error */
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002934 vim_snprintf((char *)IObuff, IOSIZE,
2935 _("Could not get security context %s for %s. Removing it!"),
2936 name, from_file);
2937 msg_puts(IObuff);
2938 msg_putchar('\n');
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002939 /* FALLTHROUGH to remove the attribute */
2940
2941 case ENODATA:
2942 /* no attribute of this name */
2943 ret = removexattr((char*)to_file, name);
Bram Moolenaar57a728d2014-04-02 23:09:26 +02002944 /* Silently ignore errors, apparently this happens when
2945 * smack is not actually being used. */
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002946 break;
2947 }
2948 }
2949 }
2950}
2951#endif /* HAVE_SMACK */
2952
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953/*
2954 * Return a pointer to the ACL of file "fname" in allocated memory.
2955 * Return NULL if the ACL is not available for whatever reason.
2956 */
2957 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002958mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959{
2960 vim_acl_T ret = NULL;
2961#ifdef HAVE_POSIX_ACL
2962 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2963#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002964#ifdef HAVE_SOLARIS_ZFS_ACL
2965 acl_t *aclent;
2966
2967 if (acl_get((char *)fname, 0, &aclent) < 0)
2968 return NULL;
2969 ret = (vim_acl_T)aclent;
2970#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971#ifdef HAVE_SOLARIS_ACL
2972 vim_acl_solaris_T *aclent;
2973
2974 aclent = malloc(sizeof(vim_acl_solaris_T));
2975 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2976 {
2977 free(aclent);
2978 return NULL;
2979 }
2980 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2981 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2982 {
2983 free(aclent->acl_entry);
2984 free(aclent);
2985 return NULL;
2986 }
2987 ret = (vim_acl_T)aclent;
2988#else
2989#if defined(HAVE_AIX_ACL)
2990 int aclsize;
2991 struct acl *aclent;
2992
2993 aclsize = sizeof(struct acl);
2994 aclent = malloc(aclsize);
2995 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2996 {
2997 if (errno == ENOSPC)
2998 {
2999 aclsize = aclent->acl_len;
3000 aclent = realloc(aclent, aclsize);
3001 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3002 {
3003 free(aclent);
3004 return NULL;
3005 }
3006 }
3007 else
3008 {
3009 free(aclent);
3010 return NULL;
3011 }
3012 }
3013 ret = (vim_acl_T)aclent;
3014#endif /* HAVE_AIX_ACL */
3015#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003016#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003017#endif /* HAVE_POSIX_ACL */
3018 return ret;
3019}
3020
3021/*
3022 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3023 */
3024 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003025mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026{
3027 if (aclent == NULL)
3028 return;
3029#ifdef HAVE_POSIX_ACL
3030 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3031#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003032#ifdef HAVE_SOLARIS_ZFS_ACL
3033 acl_set((char *)fname, (acl_t *)aclent);
3034#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035#ifdef HAVE_SOLARIS_ACL
3036 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3037 ((vim_acl_solaris_T *)aclent)->acl_entry);
3038#else
3039#ifdef HAVE_AIX_ACL
3040 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
3041#endif /* HAVE_AIX_ACL */
3042#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003043#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044#endif /* HAVE_POSIX_ACL */
3045}
3046
3047 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003048mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049{
3050 if (aclent == NULL)
3051 return;
3052#ifdef HAVE_POSIX_ACL
3053 acl_free((acl_t)aclent);
3054#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003055#ifdef HAVE_SOLARIS_ZFS_ACL
3056 acl_free((acl_t *)aclent);
3057#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058#ifdef HAVE_SOLARIS_ACL
3059 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3060 free(aclent);
3061#else
3062#ifdef HAVE_AIX_ACL
3063 free(aclent);
3064#endif /* HAVE_AIX_ACL */
3065#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003066#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067#endif /* HAVE_POSIX_ACL */
3068}
3069#endif
3070
3071/*
3072 * Set hidden flag for "name".
3073 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003075mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076{
3077 /* can't hide a file */
3078}
3079
3080/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003081 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082 * return FALSE if "name" is not a directory
3083 * return FALSE for error
3084 */
3085 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003086mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087{
3088 struct stat statb;
3089
3090 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3091 return FALSE;
3092 if (stat((char *)name, &statb))
3093 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095}
3096
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003097/*
3098 * return TRUE if "name" is a directory, NOT a symlink to a directory
3099 * return FALSE if "name" is not a directory
3100 * return FALSE for error
3101 */
3102 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003103mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003104{
3105 struct stat statb;
3106
3107 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3108 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003109 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003110 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003111 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003112}
3113
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114/*
3115 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3116 */
3117 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003118executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119{
3120 struct stat st;
3121
3122 if (stat((char *)name, &st))
3123 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003124#ifdef VMS
3125 /* Like on Unix system file can have executable rights but not necessarily
3126 * be an executable, but on Unix is not a default for an ordianry file to
3127 * have an executable flag - on VMS it is in most cases.
3128 * Therefore, this check does not have any sense - let keep us to the
3129 * conventions instead:
3130 * *.COM and *.EXE files are the executables - the rest are not. This is
3131 * not ideal but better then it was.
3132 */
3133 int vms_executable = 0;
3134 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3135 {
3136 if (strstr(vms_tolower((char*)name),".exe") != NULL
3137 || strstr(vms_tolower((char*)name),".com")!= NULL)
3138 vms_executable = 1;
3139 }
3140 return vms_executable;
3141#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003143#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144}
3145
3146/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003147 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003148 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 * Return -1 if unknown.
3150 */
3151 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003152mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153{
3154 char_u *buf;
3155 char_u *p, *e;
3156 int retval;
3157
Bram Moolenaarb5971142015-03-21 17:32:19 +01003158 /* When "use_path" is false and if it's an absolute or relative path don't
3159 * need to use $PATH. */
3160 if (!use_path || mch_isFullName(name) || (name[0] == '.'
3161 && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003162 {
Bram Moolenaarb5971142015-03-21 17:32:19 +01003163 /* There must be a path separator, files in the current directory
3164 * can't be executed. */
3165 if (gettail(name) != name && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003166 {
3167 if (path != NULL)
3168 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003169 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003170 *path = FullName_save(name, TRUE);
3171 else
3172 *path = vim_strsave(name);
3173 }
3174 return TRUE;
3175 }
3176 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178
3179 p = (char_u *)getenv("PATH");
3180 if (p == NULL || *p == NUL)
3181 return -1;
3182 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3183 if (buf == NULL)
3184 return -1;
3185
3186 /*
3187 * Walk through all entries in $PATH to check if "name" exists there and
3188 * is an executable file.
3189 */
3190 for (;;)
3191 {
3192 e = (char_u *)strchr((char *)p, ':');
3193 if (e == NULL)
3194 e = p + STRLEN(p);
3195 if (e - p <= 1) /* empty entry means current dir */
3196 STRCPY(buf, "./");
3197 else
3198 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003199 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200 add_pathsep(buf);
3201 }
3202 STRCAT(buf, name);
3203 retval = executable_file(buf);
3204 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003205 {
3206 if (path != NULL)
3207 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003208 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003209 *path = FullName_save(buf, TRUE);
3210 else
3211 *path = vim_strsave(buf);
3212 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003214 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215
3216 if (*e != ':')
3217 break;
3218 p = e + 1;
3219 }
3220
3221 vim_free(buf);
3222 return retval;
3223}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224
3225/*
3226 * Check what "name" is:
3227 * NODE_NORMAL: file or directory (or doesn't exist)
3228 * NODE_WRITABLE: writable device, socket, fifo, etc.
3229 * NODE_OTHER: non-writable things
3230 */
3231 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003232mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233{
3234 struct stat st;
3235
3236 if (stat((char *)name, &st))
3237 return NODE_NORMAL;
3238 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3239 return NODE_NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3241 return NODE_OTHER;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 /* Everything else is writable? */
3243 return NODE_WRITABLE;
3244}
3245
3246 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003247mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248{
3249#ifdef HAVE_CHECK_STACK_GROWTH
3250 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252 check_stack_growth((char *)&i);
3253
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003254# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 get_stack_limit();
3256# endif
3257
3258#endif
3259
3260 /*
3261 * Setup an alternative stack for signals. Helps to catch signals when
3262 * running out of stack space.
3263 * Use of sigaltstack() is preferred, it's more portable.
3264 * Ignore any errors.
3265 */
3266#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003267 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 init_signal_stack();
3269#endif
3270}
3271
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003272#if defined(EXITFREE) || defined(PROTO)
3273 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003274mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003275{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003276# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3277 if (clip_star.owned)
3278 clip_lose_selection(&clip_star);
3279 if (clip_plus.owned)
3280 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003281# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003282# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003283 if (xterm_Shell != (Widget)0)
3284 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003285# ifndef LESSTIF_VERSION
3286 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003287 if (xterm_dpy != NULL)
3288 XtCloseDisplay(xterm_dpy);
3289 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003290 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003291 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003292# ifdef FEAT_X11
3293 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3294# endif
3295 }
3296# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003297# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003298# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003299 if (x11_display != NULL
3300# ifdef FEAT_XCLIPBOARD
3301 && x11_display != xterm_dpy
3302# endif
3303 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003304 XCloseDisplay(x11_display);
3305# endif
3306# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003307 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003308# endif
3309# ifdef FEAT_TITLE
3310 vim_free(oldtitle);
3311 vim_free(oldicon);
3312# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003313}
3314#endif
3315
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316/*
3317 * Output a newline when exiting.
3318 * Make sure the newline goes to the same stream as the text.
3319 */
3320 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003321exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003323 if (silent_mode)
3324 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 if (newline_on_exit || msg_didout)
3326 {
3327 if (msg_use_printf())
3328 {
3329 if (info_message)
3330 mch_msg("\n");
3331 else
3332 mch_errmsg("\r\n");
3333 }
3334 else
3335 out_char('\n');
3336 }
3337 else
3338 {
3339 restore_cterm_colors(); /* get original colors back */
3340 msg_clr_eos_force(); /* clear the rest of the display */
3341 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3342 }
3343}
3344
3345 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003346mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347{
3348 exiting = TRUE;
3349
3350#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3351 x11_export_final_selection();
3352#endif
3353
3354#ifdef FEAT_GUI
3355 if (!gui.in_use)
3356#endif
3357 {
3358 settmode(TMODE_COOK);
3359#ifdef FEAT_TITLE
Bram Moolenaar40385db2018-08-07 22:31:44 +02003360 // restore xterm title and icon name
3361 mch_restore_title(SAVE_RESTORE_BOTH);
3362 term_pop_title(SAVE_RESTORE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363#endif
3364 /*
3365 * When t_ti is not empty but it doesn't cause swapping terminal
3366 * pages, need to output a newline when msg_didout is set. But when
3367 * t_ti does swap pages it should not go to the shell page. Do this
3368 * before stoptermcap().
3369 */
3370 if (swapping_screen() && !newline_on_exit)
3371 exit_scroll();
3372
3373 /* Stop termcap: May need to check for T_CRV response, which
3374 * requires RAW mode. */
3375 stoptermcap();
3376
3377 /*
3378 * A newline is only required after a message in the alternate screen.
3379 * This is set to TRUE by wait_return().
3380 */
3381 if (!swapping_screen() || newline_on_exit)
3382 exit_scroll();
3383
3384 /* Cursor may have been switched off without calling starttermcap()
3385 * when doing "vim -u vimrc" and vimrc contains ":q". */
3386 if (full_screen)
3387 cursor_on();
3388 }
3389 out_flush();
3390 ml_close_all(TRUE); /* remove all memfiles */
3391 may_core_dump();
3392#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 gui_exit(r);
3395#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003396
Bram Moolenaar56718732006-03-15 22:53:57 +00003397#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003398 mac_conv_cleanup();
3399#endif
3400
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401#ifdef __QNX__
3402 /* A core dump won't be created if the signal handler
3403 * doesn't return, so we can't call exit() */
3404 if (deadly_signal != 0)
3405 return;
3406#endif
3407
Bram Moolenaar009b2592004-10-24 19:18:58 +00003408#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003409 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003410#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003411
3412#ifdef EXITFREE
3413 free_all_mem();
3414#endif
3415
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 exit(r);
3417}
3418
3419 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003420may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421{
3422 if (deadly_signal != 0)
3423 {
3424 signal(deadly_signal, SIG_DFL);
3425 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3426 }
3427}
3428
3429#ifndef VMS
3430
3431 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003432mch_settmode(int tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433{
3434 static int first = TRUE;
3435
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003436#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437# ifdef HAVE_TERMIOS_H
3438 static struct termios told;
3439 struct termios tnew;
3440# else
3441 static struct termio told;
3442 struct termio tnew;
3443# endif
3444
3445 if (first)
3446 {
3447 first = FALSE;
3448# if defined(HAVE_TERMIOS_H)
3449 tcgetattr(read_cmd_fd, &told);
3450# else
3451 ioctl(read_cmd_fd, TCGETA, &told);
3452# endif
3453 }
3454
3455 tnew = told;
3456 if (tmode == TMODE_RAW)
3457 {
3458 /*
3459 * ~ICRNL enables typing ^V^M
3460 */
3461 tnew.c_iflag &= ~ICRNL;
3462 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3463# if defined(IEXTEN) && !defined(__MINT__)
3464 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3465 /* but it breaks function keys on MINT */
3466# endif
3467 );
3468# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3469 tnew.c_oflag &= ~ONLCR;
3470# endif
3471 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3472 tnew.c_cc[VTIME] = 0; /* don't wait */
3473 }
3474 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003475 {
3476 /* Also reset ICANON here, otherwise on Solaris select() won't see
3477 * typeahead characters. */
3478 tnew.c_lflag &= ~(ICANON | ECHO);
3479 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3480 tnew.c_cc[VTIME] = 0; /* don't wait */
3481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482
3483# if defined(HAVE_TERMIOS_H)
3484 {
3485 int n = 10;
3486
3487 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3488 * few times. */
3489 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3490 && errno == EINTR && n > 0)
3491 --n;
3492 }
3493# else
3494 ioctl(read_cmd_fd, TCSETA, &tnew);
3495# endif
3496
3497#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 /*
3499 * for "old" tty systems
3500 */
3501# ifndef TIOCSETN
3502# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3503# endif
3504 static struct sgttyb ttybold;
3505 struct sgttyb ttybnew;
3506
3507 if (first)
3508 {
3509 first = FALSE;
3510 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3511 }
3512
3513 ttybnew = ttybold;
3514 if (tmode == TMODE_RAW)
3515 {
3516 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3517 ttybnew.sg_flags |= RAW;
3518 }
3519 else if (tmode == TMODE_SLEEP)
3520 ttybnew.sg_flags &= ~(ECHO);
3521 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3522#endif
3523 curr_tmode = tmode;
3524}
3525
3526/*
3527 * Try to get the code for "t_kb" from the stty setting
3528 *
3529 * Even if termcap claims a backspace key, the user's setting *should*
3530 * prevail. stty knows more about reality than termcap does, and if
3531 * somebody's usual erase key is DEL (which, for most BSD users, it will
3532 * be), they're going to get really annoyed if their erase key starts
3533 * doing forward deletes for no reason. (Eric Fischer)
3534 */
3535 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003536get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003538 ttyinfo_T info;
3539 char_u buf[2];
3540 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003542 if (get_tty_info(read_cmd_fd, &info) == OK)
3543 {
3544 intr_char = info.interrupt;
3545 buf[0] = info.backspace;
3546 buf[1] = NUL;
3547 add_termcode((char_u *)"kb", buf, FALSE);
3548
3549 /* If <BS> and <DEL> are now the same, redefine <DEL>. */
3550 p = find_termcode((char_u *)"kD");
3551 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3552 do_fixdel(NULL);
3553 }
3554}
3555
3556/*
3557 * Obtain the characters that Backspace and Enter produce on "fd".
3558 * Returns OK or FAIL.
3559 */
3560 int
3561get_tty_info(int fd, ttyinfo_T *info)
3562{
3563#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564# ifdef HAVE_TERMIOS_H
3565 struct termios keys;
3566# else
3567 struct termio keys;
3568# endif
3569
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003570 if (
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571# if defined(HAVE_TERMIOS_H)
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003572 tcgetattr(fd, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573# else
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003574 ioctl(fd, TCGETA, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575# endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003576 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003578 info->backspace = keys.c_cc[VERASE];
3579 info->interrupt = keys.c_cc[VINTR];
3580 if (keys.c_iflag & ICRNL)
3581 info->enter = NL;
3582 else
3583 info->enter = CAR;
3584 if (keys.c_oflag & ONLCR)
3585 info->nl_does_cr = TRUE;
3586 else
3587 info->nl_does_cr = FALSE;
3588 return OK;
3589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590#else
3591 /* for "old" tty systems */
3592 struct sgttyb keys;
3593
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003594 if (ioctl(fd, TIOCGETP, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003596 info->backspace = keys.sg_erase;
3597 info->interrupt = keys.sg_kill;
3598 info->enter = CAR;
3599 info->nl_does_cr = TRUE;
3600 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003603 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604}
3605
3606#endif /* VMS */
3607
3608#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003609static int mouse_ison = FALSE;
3610
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611/*
3612 * Set mouse clicks on or off.
3613 */
3614 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003615mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616{
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003617# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003618 static int bevalterm_ison = FALSE;
3619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620 int xterm_mouse_vers;
3621
Bram Moolenaara06afc72018-08-27 23:24:16 +02003622# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
3623 if (!on)
3624 // Make sure not tracing mouse movements. Important when a button-down
3625 // was received but no release yet.
3626 stop_xterm_trace();
3627# endif
3628
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003629 if (on == mouse_ison
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003630# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003631 && p_bevalterm == bevalterm_ison
3632# endif
3633 )
3634 /* return quickly if nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 return;
3636
3637 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003638
3639# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003640 if (ttym_flags == TTYM_URXVT)
3641 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003642 out_str_nf((char_u *)
3643 (on
3644 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3645 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003646 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003647 }
3648# endif
3649
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003650# ifdef FEAT_MOUSE_SGR
3651 if (ttym_flags == TTYM_SGR)
3652 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003653 /* SGR mode supports columns above 223 */
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003654 out_str_nf((char_u *)
3655 (on
3656 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3657 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003658 mouse_ison = on;
3659 }
3660# endif
3661
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003662# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003663 if (bevalterm_ison != (p_bevalterm && on))
3664 {
3665 bevalterm_ison = (p_bevalterm && on);
3666 if (xterm_mouse_vers > 1 && !bevalterm_ison)
3667 /* disable mouse movement events, enabling is below */
3668 out_str_nf((char_u *)
3669 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003670 }
3671# endif
3672
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 if (xterm_mouse_vers > 0)
3674 {
3675 if (on) /* enable mouse events, use mouse tracking if available */
3676 out_str_nf((char_u *)
3677 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003678 ? (
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003679# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003680 bevalterm_ison
3681 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
3682# endif
3683 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3685 else /* disable mouse events, could probably always send the same */
3686 out_str_nf((char_u *)
3687 (xterm_mouse_vers > 1
3688 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3689 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003690 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691 }
3692
3693# ifdef FEAT_MOUSE_DEC
3694 else if (ttym_flags == TTYM_DEC)
3695 {
3696 if (on) /* enable mouse events */
3697 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3698 else /* disable mouse events */
3699 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003700 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 }
3702# endif
3703
3704# ifdef FEAT_MOUSE_GPM
3705 else
3706 {
3707 if (on)
3708 {
3709 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003710 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 }
3712 else
3713 {
3714 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003715 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 }
3717 }
3718# endif
3719
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003720# ifdef FEAT_SYSMOUSE
3721 else
3722 {
3723 if (on)
3724 {
3725 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003726 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003727 }
3728 else
3729 {
3730 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003731 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003732 }
3733 }
3734# endif
3735
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736# ifdef FEAT_MOUSE_JSB
3737 else
3738 {
3739 if (on)
3740 {
3741 /* D - Enable Mouse up/down messages
3742 * L - Enable Left Button Reporting
3743 * M - Enable Middle Button Reporting
3744 * R - Enable Right Button Reporting
3745 * K - Enable SHIFT and CTRL key Reporting
3746 * + - Enable Advanced messaging of mouse moves and up/down messages
3747 * Q - Quiet No Ack
3748 * # - Numeric value of mouse pointer required
3749 * 0 = Multiview 2000 cursor, used as standard
3750 * 1 = Windows Arrow
3751 * 2 = Windows I Beam
3752 * 3 = Windows Hour Glass
3753 * 4 = Windows Cross Hair
3754 * 5 = Windows UP Arrow
3755 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003756# ifdef JSBTERM_MOUSE_NONADVANCED
3757 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3759 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003760# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3762 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003763# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003764 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 }
3766 else
3767 {
3768 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3769 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003770 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 }
3772 }
3773# endif
3774# ifdef FEAT_MOUSE_PTERM
3775 else
3776 {
3777 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3778 if (on)
3779 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3780 else
3781 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003782 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 }
3784# endif
3785}
3786
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003787#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003788/*
3789 * Called when 'balloonevalterm' changed.
3790 */
3791 void
3792mch_bevalterm_changed(void)
3793{
3794 mch_setmouse(mouse_ison);
3795}
3796#endif
3797
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798/*
3799 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3800 */
3801 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003802check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803{
3804# ifdef FEAT_MOUSE_XTERM
3805 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003806# ifdef FEAT_MOUSE_URXVT
3807 && use_xterm_mouse() != 3
3808# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809# ifdef FEAT_GUI
3810 && !gui.in_use
3811# endif
3812 )
3813 {
3814 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003815 ? IF_EB("\233M", CSI_STR "M")
3816 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 if (*p_mouse != NUL)
3818 {
3819 /* force mouse off and maybe on to send possibly new mouse
3820 * activation sequence to the xterm, with(out) drag tracing. */
3821 mch_setmouse(FALSE);
3822 setmouse();
3823 }
3824 }
3825 else
3826 del_mouse_termcode(KS_MOUSE);
3827# endif
3828
3829# ifdef FEAT_MOUSE_GPM
3830 if (!use_xterm_mouse()
3831# ifdef FEAT_GUI
3832 && !gui.in_use
3833# endif
3834 )
3835 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3836# endif
3837
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003838# ifdef FEAT_SYSMOUSE
3839 if (!use_xterm_mouse()
3840# ifdef FEAT_GUI
3841 && !gui.in_use
3842# endif
3843 )
3844 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3845# endif
3846
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847# ifdef FEAT_MOUSE_JSB
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003848 /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 if (!use_xterm_mouse()
3850# ifdef FEAT_GUI
3851 && !gui.in_use
3852# endif
3853 )
3854 set_mouse_termcode(KS_JSBTERM_MOUSE,
3855 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3856 else
3857 del_mouse_termcode(KS_JSBTERM_MOUSE);
3858# endif
3859
3860# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003861 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 * define it in the GUI or when using an xterm. */
3863 if (!use_xterm_mouse()
3864# ifdef FEAT_GUI
3865 && !gui.in_use
3866# endif
3867 )
3868 set_mouse_termcode(KS_NETTERM_MOUSE,
3869 (char_u *)IF_EB("\033}", ESC_STR "}"));
3870 else
3871 del_mouse_termcode(KS_NETTERM_MOUSE);
3872# endif
3873
3874# ifdef FEAT_MOUSE_DEC
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003875 /* Conflicts with xterm mouse: "\033[" and "\033[M" */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003876 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877# ifdef FEAT_GUI
3878 && !gui.in_use
3879# endif
3880 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003881 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3882 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 else
3884 del_mouse_termcode(KS_DEC_MOUSE);
3885# endif
3886# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003887 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003888 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889# ifdef FEAT_GUI
3890 && !gui.in_use
3891# endif
3892 )
3893 set_mouse_termcode(KS_PTERM_MOUSE,
3894 (char_u *) IF_EB("\033[", ESC_STR "["));
3895 else
3896 del_mouse_termcode(KS_PTERM_MOUSE);
3897# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003898# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003899 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003900# ifdef FEAT_GUI
3901 && !gui.in_use
3902# endif
3903 )
3904 {
3905 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003906 ? IF_EB("\233*M", CSI_STR "*M")
3907 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003908
3909 if (*p_mouse != NUL)
3910 {
3911 mch_setmouse(FALSE);
3912 setmouse();
3913 }
3914 }
3915 else
3916 del_mouse_termcode(KS_URXVT_MOUSE);
3917# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003918# ifdef FEAT_MOUSE_SGR
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003919 if (use_xterm_mouse() == 4
3920# ifdef FEAT_GUI
3921 && !gui.in_use
3922# endif
3923 )
3924 {
3925 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003926 ? IF_EB("\233<*M", CSI_STR "<*M")
3927 : IF_EB("\033[<*M", ESC_STR "[<*M")));
3928
3929 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
3930 ? IF_EB("\233<*m", CSI_STR "<*m")
3931 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003932
3933 if (*p_mouse != NUL)
3934 {
3935 mch_setmouse(FALSE);
3936 setmouse();
3937 }
3938 }
3939 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02003940 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003941 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02003942 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
3943 }
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003944# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945}
3946#endif
3947
3948/*
3949 * set screen mode, always fails.
3950 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003952mch_screenmode(char_u *arg UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953{
3954 EMSG(_(e_screenmode));
3955 return FAIL;
3956}
3957
3958#ifndef VMS
3959
3960/*
3961 * Try to get the current window size:
3962 * 1. with an ioctl(), most accurate method
3963 * 2. from the environment variables LINES and COLUMNS
3964 * 3. from the termcap
3965 * 4. keep using the old values
3966 * Return OK when size could be determined, FAIL otherwise.
3967 */
3968 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003969mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970{
3971 long rows = 0;
3972 long columns = 0;
3973 char_u *p;
3974
3975 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 * 1. try using an ioctl. It is the most accurate method.
3977 *
3978 * Try using TIOCGWINSZ first, some systems that have it also define
3979 * TIOCGSIZE but don't have a struct ttysize.
3980 */
3981# ifdef TIOCGWINSZ
3982 {
3983 struct winsize ws;
3984 int fd = 1;
3985
3986 /* When stdout is not a tty, use stdin for the ioctl(). */
3987 if (!isatty(fd) && isatty(read_cmd_fd))
3988 fd = read_cmd_fd;
3989 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3990 {
3991 columns = ws.ws_col;
3992 rows = ws.ws_row;
3993 }
3994 }
3995# else /* TIOCGWINSZ */
3996# ifdef TIOCGSIZE
3997 {
3998 struct ttysize ts;
3999 int fd = 1;
4000
4001 /* When stdout is not a tty, use stdin for the ioctl(). */
4002 if (!isatty(fd) && isatty(read_cmd_fd))
4003 fd = read_cmd_fd;
4004 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4005 {
4006 columns = ts.ts_cols;
4007 rows = ts.ts_lines;
4008 }
4009 }
4010# endif /* TIOCGSIZE */
4011# endif /* TIOCGWINSZ */
4012
4013 /*
4014 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004015 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4016 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004018 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019 {
4020 if ((p = (char_u *)getenv("LINES")))
4021 rows = atoi((char *)p);
4022 if ((p = (char_u *)getenv("COLUMNS")))
4023 columns = atoi((char *)p);
4024 }
4025
4026#ifdef HAVE_TGETENT
4027 /*
4028 * 3. try reading "co" and "li" entries from termcap
4029 */
4030 if (columns == 0 || rows == 0)
4031 getlinecol(&columns, &rows);
4032#endif
4033
4034 /*
4035 * 4. If everything fails, use the old values
4036 */
4037 if (columns <= 0 || rows <= 0)
4038 return FAIL;
4039
4040 Rows = rows;
4041 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004042 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 return OK;
4044}
4045
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004046#if defined(FEAT_TERMINAL) || defined(PROTO)
4047/*
4048 * Report the windows size "rows" and "cols" to tty "fd".
4049 */
4050 int
4051mch_report_winsize(int fd, int rows, int cols)
4052{
4053# ifdef TIOCSWINSZ
4054 struct winsize ws;
4055
4056 ws.ws_col = cols;
4057 ws.ws_row = rows;
4058 ws.ws_xpixel = cols * 5;
4059 ws.ws_ypixel = rows * 10;
4060 if (ioctl(fd, TIOCSWINSZ, &ws) == 0)
4061 {
4062 ch_log(NULL, "ioctl(TIOCSWINSZ) success");
4063 return OK;
4064 }
4065 ch_log(NULL, "ioctl(TIOCSWINSZ) failed");
4066# else
4067# ifdef TIOCSSIZE
4068 struct ttysize ts;
4069
4070 ts.ts_cols = cols;
4071 ts.ts_lines = rows;
4072 if (ioctl(fd, TIOCSSIZE, &ws) == 0)
4073 {
4074 ch_log(NULL, "ioctl(TIOCSSIZE) success");
4075 return OK;
4076 }
4077 ch_log(NULL, "ioctl(TIOCSSIZE) failed");
4078# endif
4079# endif
4080 return FAIL;
4081}
4082#endif
4083
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084/*
4085 * Try to set the window size to Rows and Columns.
4086 */
4087 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004088mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089{
4090 if (*T_CWS)
4091 {
4092 /*
4093 * NOTE: if you get an error here that term_set_winsize() is
4094 * undefined, check the output of configure. It could probably not
4095 * find a ncurses, termcap or termlib library.
4096 */
4097 term_set_winsize((int)Rows, (int)Columns);
4098 out_flush();
4099 screen_start(); /* don't know where cursor is now */
4100 }
4101}
4102
4103#endif /* VMS */
4104
4105/*
4106 * Rows and/or Columns has changed.
4107 */
4108 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004109mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110{
4111 /* Nothing to do. */
4112}
4113
Bram Moolenaar205b8862011-09-07 15:04:31 +02004114/*
4115 * Wait for process "child" to end.
4116 * Return "child" if it exited properly, <= 0 on error.
4117 */
4118 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004119wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004120{
4121 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004122 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004123
4124 while (wait_pid != child)
4125 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004126 /* When compiled with Python threads are probably used, in which case
4127 * wait() sometimes hangs for no obvious reason. Use waitpid()
4128 * instead and loop (like the GUI). Also needed for other interfaces,
4129 * they might call system(). */
4130# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004131 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004132# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004133 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004134# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004135 if (wait_pid == 0)
4136 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004137 /* Wait for 1 to 10 msec before trying again. */
4138 mch_delay(delay_msec, TRUE);
4139 if (++delay_msec > 10)
4140 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004141 continue;
4142 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004143 if (wait_pid <= 0
4144# ifdef ECHILD
4145 && errno == ECHILD
4146# endif
4147 )
4148 break;
4149 }
4150 return wait_pid;
4151}
4152
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004153#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004154/*
4155 * Set the environment for a child process.
4156 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004157 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004158set_child_environment(
4159 long rows,
4160 long columns,
4161 char *term,
4162 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004163{
4164# ifdef HAVE_SETENV
4165 char envbuf[50];
4166# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004167 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004168 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004169 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004170 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004171 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004172# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004173 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004174# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004175# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004176 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004177# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004178# endif
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004179 long colors =
4180# ifdef FEAT_GUI
4181 gui.in_use ? 256*256*256 :
4182# endif
4183 t_colors;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004184
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004185# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004186 setenv("TERM", term, 1);
4187 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004188 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004189 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004190 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004191 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004192 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004193 sprintf((char *)envbuf, "%ld", colors);
4194 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004195# ifdef FEAT_TERMINAL
4196 if (is_terminal)
4197 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004198 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004199 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4200 }
4201# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004202# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004203 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004204# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004205# else
4206 /*
4207 * Putenv does not copy the string, it has to remain valid.
4208 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004209 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004210 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004211 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4212 putenv(envbuf_Term);
4213 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004214 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004215 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4216 putenv(envbuf_Lines);
4217 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4218 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004219 putenv(envbuf_Columns);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004220 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors);
4221 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004222# ifdef FEAT_TERMINAL
4223 if (is_terminal)
4224 {
4225 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004226 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004227 putenv(envbuf_Version);
4228 }
4229# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004230# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004231 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4232 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4233 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004234# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004235# endif
4236}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004237
4238 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004239set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004240{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004241 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004242}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004243#endif
4244
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004245#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004246/*
4247 * Open a PTY, with FD for the master and slave side.
4248 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
4249 * When successful both file descriptors are stored.
4250 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004251 static void
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004252open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004253{
4254 char *tty_name;
4255
4256 *pty_master_fd = OpenPTY(&tty_name); /* open pty */
4257 if (*pty_master_fd >= 0)
4258 {
4259 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4260 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4261 * adding O_NOCTTY always works when defined. */
4262#ifdef O_NOCTTY
4263 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4264#else
4265 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4266#endif
4267 if (*pty_slave_fd < 0)
4268 {
4269 close(*pty_master_fd);
4270 *pty_master_fd = -1;
4271 }
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004272 else if (namep != NULL)
4273 *namep = vim_strsave((char_u *)tty_name);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004274 }
4275}
4276#endif
4277
Bram Moolenaarfae42832017-08-01 22:24:26 +02004278/*
4279 * Send SIGINT to a child process if "c" is an interrupt character.
4280 */
4281 void
4282may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4283{
4284# ifdef SIGINT
4285 if (c == Ctrl_C || c == intr_char)
4286 {
4287# ifdef HAVE_SETSID
4288 kill(-pid, SIGINT);
4289# else
4290 kill(0, SIGINT);
4291# endif
4292 if (wpid > 0)
4293 kill(wpid, SIGINT);
4294 }
4295# endif
4296}
4297
Bram Moolenaar13568252018-03-16 20:46:58 +01004298#if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL))
4299
4300 static int
4301build_argv(
4302 char_u *cmd,
4303 char ***argvp,
4304 char_u **sh_tofree,
4305 char_u **shcf_tofree)
4306{
4307 char **argv = NULL;
4308 int argc;
4309
4310 *sh_tofree = vim_strsave(p_sh);
4311 if (*sh_tofree == NULL) /* out of memory */
4312 return FAIL;
4313
4314 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4315 return FAIL;
4316 *argvp = argv;
4317
4318 if (cmd != NULL)
4319 {
4320 char_u *s;
4321 char_u *p;
4322
4323 if (extra_shell_arg != NULL)
4324 argv[argc++] = (char *)extra_shell_arg;
4325
4326 /* Break 'shellcmdflag' into white separated parts. This doesn't
4327 * handle quoted strings, they are very unlikely to appear. */
4328 *shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1);
4329 if (*shcf_tofree == NULL) /* out of memory */
4330 return FAIL;
4331 s = *shcf_tofree;
4332 p = p_shcf;
4333 while (*p != NUL)
4334 {
4335 argv[argc++] = (char *)s;
4336 while (*p && *p != ' ' && *p != TAB)
4337 *s++ = *p++;
4338 *s++ = NUL;
4339 p = skipwhite(p);
4340 }
4341
4342 argv[argc++] = (char *)cmd;
4343 }
4344 argv[argc] = NULL;
4345 return OK;
4346}
4347#endif
4348
4349#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4350/*
4351 * Use a terminal window to run a shell command in.
4352 */
4353 static int
4354mch_call_shell_terminal(
4355 char_u *cmd,
4356 int options UNUSED) /* SHELL_*, see vim.h */
4357{
4358 jobopt_T opt;
4359 char **argv = NULL;
4360 char_u *tofree1 = NULL;
4361 char_u *tofree2 = NULL;
4362 int retval = -1;
4363 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004364 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004365 aco_save_T aco;
4366 oparg_T oa; /* operator arguments */
4367
4368 if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
4369 goto theend;
4370
4371 init_job_options(&opt);
4372 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4373 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004374 if (buf == NULL)
4375 goto theend;
4376
4377 job = term_getjob(buf->b_term);
4378 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004379
4380 /* Find a window to make "buf" curbuf. */
4381 aucmd_prepbuf(&aco, buf);
4382
4383 clear_oparg(&oa);
4384 while (term_use_loop())
4385 {
4386 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4387 {
4388 /* If terminal_loop() returns OK we got a key that is handled
4389 * in Normal model. We don't do redrawing anyway. */
4390 if (terminal_loop(TRUE) == OK)
4391 normal_cmd(&oa, TRUE);
4392 }
4393 else
4394 normal_cmd(&oa, TRUE);
4395 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004396 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004397 ch_log(NULL, "system command finished");
4398
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004399 job_unref(job);
4400
Bram Moolenaar13568252018-03-16 20:46:58 +01004401 /* restore curwin/curbuf and a few other things */
4402 aucmd_restbuf(&aco);
4403
4404 wait_return(TRUE);
4405 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4406
4407theend:
4408 vim_free(argv);
4409 vim_free(tofree1);
4410 vim_free(tofree2);
4411 return retval;
4412}
4413#endif
4414
4415#ifdef USE_SYSTEM
4416/*
4417 * Use system() to start the shell: simple but slow.
4418 */
4419 static int
4420mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004421 char_u *cmd,
4422 int options) /* SHELL_*, see vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423{
4424#ifdef VMS
4425 char *ifn = NULL;
4426 char *ofn = NULL;
4427#endif
4428 int tmode = cur_tmode;
Bram Moolenaarb2b050a2016-07-16 21:52:46 +02004429 char_u *newcmd; /* only needed for unix */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004430 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431
4432 out_flush();
4433
4434 if (options & SHELL_COOKED)
4435 settmode(TMODE_COOK); /* set to normal mode */
4436
Bram Moolenaar62b42182010-09-21 22:09:37 +02004437# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004438 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004439 loose_clipboard();
4440# endif
4441
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442 if (cmd == NULL)
4443 x = system((char *)p_sh);
4444 else
4445 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004446# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 if (ofn = strchr((char *)cmd, '>'))
4448 *ofn++ = '\0';
4449 if (ifn = strchr((char *)cmd, '<'))
4450 {
4451 char *p;
4452
4453 *ifn++ = '\0';
4454 p = strchr(ifn,' '); /* chop off any trailing spaces */
4455 if (p)
4456 *p = '\0';
4457 }
4458 if (ofn)
4459 x = vms_sys((char *)cmd, ofn, ifn);
4460 else
4461 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004462# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463 newcmd = lalloc(STRLEN(p_sh)
4464 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
4465 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
4466 if (newcmd == NULL)
4467 x = 0;
4468 else
4469 {
4470 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4471 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4472 (char *)p_shcf,
4473 (char *)cmd);
4474 x = system((char *)newcmd);
4475 vim_free(newcmd);
4476 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004477# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 }
4479# ifdef VMS
4480 x = vms_sys_status(x);
4481# endif
4482 if (emsg_silent)
4483 ;
4484 else if (x == 127)
4485 MSG_PUTS(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 else if (x && !(options & SHELL_SILENT))
4487 {
4488 MSG_PUTS(_("\nshell returned "));
4489 msg_outnum((long)x);
4490 msg_putchar('\n');
4491 }
4492
4493 if (tmode == TMODE_RAW)
4494 settmode(TMODE_RAW); /* set to raw mode */
4495# ifdef FEAT_TITLE
4496 resettitle();
4497# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004498# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4499 restore_clipboard();
4500# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004502}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503
Bram Moolenaar13568252018-03-16 20:46:58 +01004504#else /* USE_SYSTEM */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505
Bram Moolenaardf177f62005-02-22 08:39:57 +00004506# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4507 127, some shells use that already */
Bram Moolenaarb109bb42017-08-21 21:07:29 +02004508# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509
Bram Moolenaar13568252018-03-16 20:46:58 +01004510/*
4511 * Don't use system(), use fork()/exec().
4512 */
4513 static int
4514mch_call_shell_fork(
4515 char_u *cmd,
4516 int options) /* SHELL_*, see vim.h */
4517{
4518 int tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004520 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 pid_t wait_pid = 0;
4522# ifdef HAVE_UNION_WAIT
4523 union wait status;
4524# else
4525 int status = -1;
4526# endif
4527 int retval = -1;
4528 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004529 char_u *tofree1 = NULL;
4530 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004533# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004535# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004536 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 int fd_fromshell[2];
4538 int pipe_error = FALSE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004539 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540
4541 out_flush();
4542 if (options & SHELL_COOKED)
4543 settmode(TMODE_COOK); /* set to normal mode */
4544
Bram Moolenaar13568252018-03-16 20:46:58 +01004545 if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004546 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004547
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004549 * For the GUI, when writing the output into the buffer and when reading
4550 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4551 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004553 if ((options & (SHELL_READ|SHELL_WRITE))
4554# ifdef FEAT_GUI
4555 || (gui.in_use && show_shell_mess)
4556# endif
4557 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004559# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 /*
4561 * Try to open a master pty.
4562 * If this works, open the slave pty.
4563 * If the slave can't be opened, close the master pty.
4564 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004565 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004566 open_pty(&pty_master_fd, &pty_slave_fd, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567 /*
4568 * If not opening a pty or it didn't work, try using pipes.
4569 */
4570 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004571# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 {
4573 pipe_error = (pipe(fd_toshell) < 0);
4574 if (!pipe_error) /* pipe create OK */
4575 {
4576 pipe_error = (pipe(fd_fromshell) < 0);
4577 if (pipe_error) /* pipe create failed */
4578 {
4579 close(fd_toshell[0]);
4580 close(fd_toshell[1]);
4581 }
4582 }
4583 if (pipe_error)
4584 {
4585 MSG_PUTS(_("\nCannot create pipes\n"));
4586 out_flush();
4587 }
4588 }
4589 }
4590
4591 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004593 SIGSET_DECL(curset)
4594
Bram Moolenaar071d4272004-06-13 20:20:40 +00004595# ifdef __BEOS__
4596 beos_cleanup_read_thread();
4597# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004598
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004599 BLOCK_SIGNALS(&curset);
4600 pid = fork(); /* maybe we should use vfork() */
4601 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004603 UNBLOCK_SIGNALS(&curset);
4604
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004606 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004608 || (gui.in_use && show_shell_mess)
4609# endif
4610 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004612# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613 if (pty_master_fd >= 0) /* close the pseudo tty */
4614 {
4615 close(pty_master_fd);
4616 close(pty_slave_fd);
4617 }
4618 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 {
4621 close(fd_toshell[0]);
4622 close(fd_toshell[1]);
4623 close(fd_fromshell[0]);
4624 close(fd_fromshell[1]);
4625 }
4626 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 }
4628 else if (pid == 0) /* child */
4629 {
4630 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004631 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632
Bram Moolenaar819524702018-02-27 19:10:00 +01004633# ifdef FEAT_JOB_CHANNEL
4634 if (ch_log_active())
4635 /* close the log file in the child */
4636 ch_logfile((char_u *)"", (char_u *)"");
4637# endif
4638
Bram Moolenaar071d4272004-06-13 20:20:40 +00004639 if (!show_shell_mess || (options & SHELL_EXPAND))
4640 {
4641 int fd;
4642
4643 /*
4644 * Don't want to show any message from the shell. Can't just
4645 * close stdout and stderr though, because some systems will
4646 * break if you try to write to them after that, so we must
4647 * use dup() to replace them with something else -- webb
4648 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4649 * waiting for input.
4650 */
4651 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4652 fclose(stdin);
4653 fclose(stdout);
4654 fclose(stderr);
4655
4656 /*
4657 * If any of these open()'s and dup()'s fail, we just continue
4658 * anyway. It's not fatal, and on most systems it will make
4659 * no difference at all. On a few it will cause the execvp()
4660 * to exit with a non-zero status even when the completion
4661 * could be done, which is nothing too serious. If the open()
4662 * or dup() failed we'd just do the same thing ourselves
4663 * anyway -- webb
4664 */
4665 if (fd >= 0)
4666 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02004667 vim_ignored = dup(fd); /* To replace stdin (fd 0) */
4668 vim_ignored = dup(fd); /* To replace stdout (fd 1) */
4669 vim_ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670
4671 /* Don't need this now that we've duplicated it */
4672 close(fd);
4673 }
4674 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004675 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004677 || gui.in_use
4678# endif
4679 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 {
4681
Bram Moolenaardf177f62005-02-22 08:39:57 +00004682# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004683 /* Create our own process group, so that the child and all its
4684 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004685 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004686 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004687 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004688 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004689# if defined(SIGHUP)
4690 /* When doing "!xterm&" and 'shell' is bash: the shell
4691 * will exit and send SIGHUP to all processes in its
4692 * group, killing the just started process. Ignore SIGHUP
4693 * to avoid that. (suggested by Simon Schubert)
4694 */
4695 signal(SIGHUP, SIG_IGN);
4696# endif
4697 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004698# endif
4699# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004700 if (pty_slave_fd >= 0)
4701 {
4702 /* push stream discipline modules */
4703 if (options & SHELL_COOKED)
4704 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004706 /* Try to become controlling tty (probably doesn't work,
4707 * unless run by root) */
4708 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004710 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004711# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004712 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713
Bram Moolenaara5792f52005-11-23 21:25:05 +00004714 /*
4715 * stderr is only redirected when using the GUI, so that a
4716 * program like gpg can still access the terminal to get a
4717 * passphrase using stderr.
4718 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004719# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720 if (pty_master_fd >= 0)
4721 {
4722 close(pty_master_fd); /* close master side of pty */
4723
4724 /* set up stdin/stdout/stderr for the child */
4725 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004726 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004728 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004729 if (gui.in_use)
4730 {
4731 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004732 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734
4735 close(pty_slave_fd); /* has been dupped, close it now */
4736 }
4737 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004738# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 {
4740 /* set up stdin for the child */
4741 close(fd_toshell[1]);
4742 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004743 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 close(fd_toshell[0]);
4745
4746 /* set up stdout for the child */
4747 close(fd_fromshell[0]);
4748 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004749 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 close(fd_fromshell[1]);
4751
Bram Moolenaara5792f52005-11-23 21:25:05 +00004752# ifdef FEAT_GUI
4753 if (gui.in_use)
4754 {
4755 /* set up stderr for the child */
4756 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004757 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004758 }
4759# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 }
4761 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004762
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763 /*
4764 * There is no type cast for the argv, because the type may be
4765 * different on different machines. This may cause a warning
4766 * message with strict compilers, don't worry about it.
4767 * Call _exit() instead of exit() to avoid closing the connection
4768 * to the X server (esp. with GTK, which uses atexit()).
4769 */
4770 execvp(argv[0], argv);
4771 _exit(EXEC_FAILED); /* exec failed, return failure code */
4772 }
4773 else /* parent */
4774 {
4775 /*
4776 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004777 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 */
4779 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004780 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004781 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004782# ifdef FEAT_JOB_CHANNEL
4783 ++dont_check_job_ended;
4784# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 /*
4786 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004787 * This is also used to pipe stdin/stdout to/from the external
4788 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004790 if ((options & (SHELL_READ|SHELL_WRITE))
4791# ifdef FEAT_GUI
4792 || (gui.in_use && show_shell_mess)
4793# endif
4794 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004796# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004798# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004800# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4802 int ta_len = 0; /* valid bytes in ta_buf[] */
4803 int len;
4804 int p_more_save;
4805 int old_State;
4806 int c;
4807 int toshell_fd;
4808 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004809 garray_T ga;
4810 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004811# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4812 struct timeval start_tv;
4813# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814
Bram Moolenaardf177f62005-02-22 08:39:57 +00004815# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816 if (pty_master_fd >= 0)
4817 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818 fromshell_fd = pty_master_fd;
4819 toshell_fd = dup(pty_master_fd);
4820 }
4821 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004822# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 {
4824 close(fd_toshell[0]);
4825 close(fd_fromshell[1]);
4826 toshell_fd = fd_toshell[1];
4827 fromshell_fd = fd_fromshell[0];
4828 }
4829
4830 /*
4831 * Write to the child if there are typed characters.
4832 * Read from the child if there are characters available.
4833 * Repeat the reading a few times if more characters are
4834 * available. Need to check for typed keys now and then, but
4835 * not too often (delays when no chars are available).
4836 * This loop is quit if no characters can be read from the pty
4837 * (WaitForChar detected special condition), or there are no
4838 * characters available and the child has exited.
4839 * Only check if the child has exited when there is no more
4840 * output. The child may exit before all the output has
4841 * been printed.
4842 *
4843 * Currently this busy loops!
4844 * This can probably dead-lock when the write blocks!
4845 */
4846 p_more_save = p_more;
4847 p_more = FALSE;
4848 old_State = State;
4849 State = EXTERNCMD; /* don't redraw at window resize */
4850
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004851 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004852 {
4853 /* Fork a process that will write the lines to the
4854 * external program. */
4855 if ((wpid = fork()) == -1)
4856 {
4857 MSG_PUTS(_("\nCannot fork\n"));
4858 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004859 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004860 {
4861 linenr_T lnum = curbuf->b_op_start.lnum;
4862 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004863 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004864 size_t l;
4865
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004866 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004867 for (;;)
4868 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004869 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004870 if (l == 0)
4871 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004872 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004873 /* NL -> NUL translation */
4874 len = write(toshell_fd, "", (size_t)1);
4875 else
4876 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004877 char_u *s = vim_strchr(lp + written, NL);
4878
Bram Moolenaar89d40322006-08-29 15:30:07 +00004879 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004880 s == NULL ? l
4881 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004882 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004883 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004884 {
4885 /* Finished a line, add a NL, unless this line
4886 * should not have one. */
4887 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004888 || (!curbuf->b_p_bin
4889 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004890 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004891 && (lnum !=
4892 curbuf->b_ml.ml_line_count
4893 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02004894 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004895 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004896 ++lnum;
4897 if (lnum > curbuf->b_op_end.lnum)
4898 {
4899 /* finished all the lines, close pipe */
4900 close(toshell_fd);
4901 toshell_fd = -1;
4902 break;
4903 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004904 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004905 written = 0;
4906 }
4907 else if (len > 0)
4908 written += len;
4909 }
4910 _exit(0);
4911 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004912 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004913 {
4914 close(toshell_fd);
4915 toshell_fd = -1;
4916 }
4917 }
4918
4919 if (options & SHELL_READ)
4920 ga_init2(&ga, 1, BUFLEN);
4921
4922 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004923# ifdef ELAPSED_FUNC
4924 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004925# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926 for (;;)
4927 {
4928 /*
4929 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004930 * if there are any.
4931 * Don't do this if we are expanding wild cards (would eat
4932 * typeahead).
4933 * Don't do this when filtering and terminal is in cooked
4934 * mode, the shell command will handle the I/O. Avoids
4935 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004936 * Don't get characters when the child has already
4937 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004938 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004939 * while (noread_cnt > 4), avoids that ":r !ls" eats
4940 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941 */
4942 len = 0;
4943 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004944 && ((options &
4945 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4946 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004947# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004948 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004949# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004950 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004951 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004952 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004954 if (ta_len == 0)
4955 {
4956 /* Get extra characters when we don't have any.
4957 * Reset the counter and timer. */
4958 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004959# ifdef ELAPSED_FUNC
4960 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004961# endif
4962 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4963 }
4964 if (ta_len > 0 || len > 0)
4965 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 /*
4967 * For pipes:
4968 * Check for CTRL-C: send interrupt signal to child.
4969 * Check for CTRL-D: EOF, close pipe to child.
4970 */
4971 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4972 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973 /*
4974 * Send SIGINT to the child's group or all
4975 * processes in our group.
4976 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02004977 may_send_sigint(ta_buf[ta_len], pid, wpid);
4978
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979 if (pty_master_fd < 0 && toshell_fd >= 0
4980 && ta_buf[ta_len] == Ctrl_D)
4981 {
4982 close(toshell_fd);
4983 toshell_fd = -1;
4984 }
4985 }
4986
4987 /* replace K_BS by <BS> and K_DEL by <DEL> */
4988 for (i = ta_len; i < ta_len + len; ++i)
4989 {
4990 if (ta_buf[i] == CSI && len - i > 2)
4991 {
4992 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4993 if (c == K_DEL || c == K_KDEL || c == K_BS)
4994 {
4995 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4996 (size_t)(len - i - 2));
4997 if (c == K_DEL || c == K_KDEL)
4998 ta_buf[i] = DEL;
4999 else
5000 ta_buf[i] = Ctrl_H;
5001 len -= 2;
5002 }
5003 }
5004 else if (ta_buf[i] == '\r')
5005 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00005006# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00005008 i += (*mb_ptr2len_len)(ta_buf + i,
5009 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005010# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005011 }
5012
5013 /*
5014 * For pipes: echo the typed characters.
5015 * For a pty this does not seem to work.
5016 */
5017 if (pty_master_fd < 0)
5018 {
5019 for (i = ta_len; i < ta_len + len; ++i)
5020 {
5021 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5022 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005023# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024 else if (has_mbyte)
5025 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005026 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027
5028 msg_outtrans_len(ta_buf + i, l);
5029 i += l - 1;
5030 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005031# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032 else
5033 msg_outtrans_len(ta_buf + i, 1);
5034 }
5035 windgoto(msg_row, msg_col);
5036 out_flush();
5037 }
5038
5039 ta_len += len;
5040
5041 /*
5042 * Write the characters to the child, unless EOF has
5043 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005044 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005045 * When writing buffer lines, drop the typed
5046 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005048 if (options & SHELL_WRITE)
5049 ta_len = 0;
5050 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 {
5052 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5053 if (len > 0)
5054 {
5055 ta_len -= len;
5056 mch_memmove(ta_buf, ta_buf + len, ta_len);
5057 }
5058 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005059 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060 }
5061
Bram Moolenaardf177f62005-02-22 08:39:57 +00005062 if (got_int)
5063 {
5064 /* CTRL-C sends a signal to the child, we ignore it
5065 * ourselves */
5066# ifdef HAVE_SETSID
5067 kill(-pid, SIGINT);
5068# else
5069 kill(0, SIGINT);
5070# endif
5071 if (wpid > 0)
5072 kill(wpid, SIGINT);
5073 got_int = FALSE;
5074 }
5075
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076 /*
5077 * Check if the child has any characters to be printed.
5078 * Read them and write them to our window. Repeat this as
5079 * long as there is something to do, avoid the 10ms wait
5080 * for mch_inchar(), or sending typeahead characters to
5081 * the external process.
5082 * TODO: This should handle escape sequences, compatible
5083 * to some terminal (vt52?).
5084 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005085 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005086 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005088 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00005089# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00005091# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00005093# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094 );
5095 if (len <= 0) /* end of file or error */
5096 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005097
5098 noread_cnt = 0;
5099 if (options & SHELL_READ)
5100 {
5101 /* Do NUL -> NL translation, append NL separated
5102 * lines to the current buffer. */
5103 for (i = 0; i < len; ++i)
5104 {
5105 if (buffer[i] == NL)
5106 append_ga_line(&ga);
5107 else if (buffer[i] == NUL)
5108 ga_append(&ga, NL);
5109 else
5110 ga_append(&ga, buffer[i]);
5111 }
5112 }
5113# ifdef FEAT_MBYTE
5114 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115 {
5116 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005117 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118
Bram Moolenaardf177f62005-02-22 08:39:57 +00005119 len += buffer_off;
5120 buffer[len] = NUL;
5121
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122 /* Check if the last character in buffer[] is
5123 * incomplete, keep these bytes for the next
5124 * round. */
5125 for (p = buffer; p < buffer + len; p += l)
5126 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005127 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005128 if (l == 0)
5129 l = 1; /* NUL byte? */
5130 else if (MB_BYTE2LEN(*p) != l)
5131 break;
5132 }
5133 if (p == buffer) /* no complete character */
5134 {
5135 /* avoid getting stuck at an illegal byte */
5136 if (len >= 12)
5137 ++p;
5138 else
5139 {
5140 buffer_off = len;
5141 continue;
5142 }
5143 }
5144 c = *p;
5145 *p = NUL;
5146 msg_puts(buffer);
5147 if (p < buffer + len)
5148 {
5149 *p = c;
5150 buffer_off = (buffer + len) - p;
5151 mch_memmove(buffer, p, buffer_off);
5152 continue;
5153 }
5154 buffer_off = 0;
5155 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005156# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158 {
5159 buffer[len] = NUL;
5160 msg_puts(buffer);
5161 }
5162
5163 windgoto(msg_row, msg_col);
5164 cursor_on();
5165 out_flush();
5166 if (got_int)
5167 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005168
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005169# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005170 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005171 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005172 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005173
5174 /* Avoid that we keep looping here without
5175 * checking for a CTRL-C for a long time. Don't
5176 * break out too often to avoid losing typeahead. */
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005177 if (msec > 2000)
5178 {
5179 noread_cnt = 5;
5180 break;
5181 }
5182 }
5183# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184 }
5185
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005186 /* If we already detected the child has finished, continue
5187 * reading output for a short while. Some text may be
5188 * buffered. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005189 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005190 {
5191 if (noread_cnt < 5)
5192 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005193 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005194 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005195
Bram Moolenaar071d4272004-06-13 20:20:40 +00005196 /*
5197 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005198 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005200# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005201 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005202# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005204# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5206 || (wait_pid == pid && WIFEXITED(status)))
5207 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005208 /* Don't break the loop yet, try reading more
5209 * characters from "fromshell_fd" first. When using
5210 * pipes there might still be something to read and
5211 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005212 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005213 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005214 else
5215 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005216
Bram Moolenaar95a51352013-03-21 22:53:50 +01005217# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005218 /* Handle any X events, e.g. serving the clipboard. */
5219 clip_update();
5220# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 }
5222finished:
5223 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005224 if (options & SHELL_READ)
5225 {
5226 if (ga.ga_len > 0)
5227 {
5228 append_ga_line(&ga);
5229 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005230 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005231 }
5232 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005233 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005234 ga_clear(&ga);
5235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005236
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 /*
5238 * Give all typeahead that wasn't used back to ui_inchar().
5239 */
5240 if (ta_len)
5241 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242 State = old_State;
5243 if (toshell_fd >= 0)
5244 close(toshell_fd);
5245 close(fromshell_fd);
5246 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005247# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005248 else
5249 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005250 long delay_msec = 1;
5251
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005252 /*
5253 * Similar to the loop above, but only handle X events, no
5254 * I/O.
5255 */
5256 for (;;)
5257 {
5258 if (got_int)
5259 {
5260 /* CTRL-C sends a signal to the child, we ignore it
5261 * ourselves */
5262# ifdef HAVE_SETSID
5263 kill(-pid, SIGINT);
5264# else
5265 kill(0, SIGINT);
5266# endif
5267 got_int = FALSE;
5268 }
5269# ifdef __NeXT__
5270 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5271# else
5272 wait_pid = waitpid(pid, &status, WNOHANG);
5273# endif
5274 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5275 || (wait_pid == pid && WIFEXITED(status)))
5276 {
5277 wait_pid = pid;
5278 break;
5279 }
5280
5281 /* Handle any X events, e.g. serving the clipboard. */
5282 clip_update();
5283
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005284 /* Wait for 1 to 10 msec. 1 is faster but gives the child
5285 * less time. */
5286 mch_delay(delay_msec, TRUE);
5287 if (++delay_msec > 10)
5288 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005289 }
5290 }
5291# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005292
5293 /*
5294 * Wait until our child has exited.
5295 * Ignore wait() returning pids of other children and returning
5296 * because of some signal like SIGWINCH.
5297 * Don't wait if wait_pid was already set above, indicating the
5298 * child already exited.
5299 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005300 if (wait_pid != pid)
5301 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005302
Bram Moolenaar624891f2010-10-13 16:22:09 +02005303# ifdef FEAT_GUI
5304 /* Close slave side of pty. Only do this after the child has
5305 * exited, otherwise the child may hang when it tries to write on
5306 * the pty. */
5307 if (pty_master_fd >= 0)
5308 close(pty_slave_fd);
5309# endif
5310
Bram Moolenaardf177f62005-02-22 08:39:57 +00005311 /* Make sure the child that writes to the external program is
5312 * dead. */
5313 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005314 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005315 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005316 wait4pid(wpid, NULL);
5317 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005318
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005319# ifdef FEAT_JOB_CHANNEL
5320 --dont_check_job_ended;
5321# endif
5322
Bram Moolenaar071d4272004-06-13 20:20:40 +00005323 /*
5324 * Set to raw mode right now, otherwise a CTRL-C after
5325 * catch_signals() will kill Vim.
5326 */
5327 if (tmode == TMODE_RAW)
5328 settmode(TMODE_RAW);
5329 did_settmode = TRUE;
5330 set_signals();
5331
5332 if (WIFEXITED(status))
5333 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00005334 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005335 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005336 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005337 {
5338 if (retval == EXEC_FAILED)
5339 {
5340 MSG_PUTS(_("\nCannot execute shell "));
5341 msg_outtrans(p_sh);
5342 msg_putchar('\n');
5343 }
5344 else if (!(options & SHELL_SILENT))
5345 {
5346 MSG_PUTS(_("\nshell returned "));
5347 msg_outnum((long)retval);
5348 msg_putchar('\n');
5349 }
5350 }
5351 }
5352 else
5353 MSG_PUTS(_("\nCommand terminated\n"));
5354 }
5355 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005356
5357error:
5358 if (!did_settmode)
5359 if (tmode == TMODE_RAW)
5360 settmode(TMODE_RAW); /* set to raw mode */
5361# ifdef FEAT_TITLE
5362 resettitle();
5363# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005364 vim_free(argv);
5365 vim_free(tofree1);
5366 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005367
5368 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005369}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005370#endif /* USE_SYSTEM */
Bram Moolenaar13568252018-03-16 20:46:58 +01005371
5372 int
5373mch_call_shell(
5374 char_u *cmd,
5375 int options) /* SHELL_*, see vim.h */
5376{
5377#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5378 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5379 return mch_call_shell_terminal(cmd, options);
5380#endif
5381#ifdef USE_SYSTEM
5382 return mch_call_shell_system(cmd, options);
5383#else
5384 return mch_call_shell_fork(cmd, options);
5385#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005386}
5387
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005388#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005389 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005390mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005391{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005392 pid_t pid;
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02005393 int fd_in[2] = {-1, -1}; /* for stdin */
5394 int fd_out[2] = {-1, -1}; /* for stdout */
5395 int fd_err[2] = {-1, -1}; /* for stderr */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005396 int pty_master_fd = -1;
5397 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005398 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005399 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5400 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5401 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005402 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005403 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5404 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005405 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005406 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005407 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005408
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005409 if (use_out_for_err && use_null_for_out)
5410 use_null_for_err = TRUE;
5411
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005412 /* default is to fail */
5413 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005414
Bram Moolenaarb2412082017-08-20 18:09:14 +02005415 if (options->jo_pty
5416 && (!(use_file_for_in || use_null_for_in)
5417 || !(use_file_for_in || use_null_for_out)
5418 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005419 {
5420 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5421 if (job->jv_tty_out != NULL)
5422 job->jv_tty_in = vim_strsave(job->jv_tty_out);
5423 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005424
Bram Moolenaar12dcf022016-02-15 23:09:04 +01005425 /* TODO: without the channel feature connect the child to /dev/null? */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005426 /* Open pipes for stdin, stdout, stderr. */
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005427 if (use_file_for_in)
5428 {
5429 char_u *fname = options->jo_io_name[PART_IN];
5430
5431 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5432 if (fd_in[0] < 0)
5433 {
5434 EMSG2(_(e_notopen), fname);
5435 goto failed;
5436 }
5437 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005438 else
5439 /* When writing buffer lines to the input don't use the pty, so that
5440 * the pipe can be closed when all lines were written. */
5441 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5442 && pipe(fd_in) < 0)
5443 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005444
5445 if (use_file_for_out)
5446 {
5447 char_u *fname = options->jo_io_name[PART_OUT];
5448
5449 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5450 if (fd_out[1] < 0)
5451 {
5452 EMSG2(_(e_notopen), fname);
5453 goto failed;
5454 }
5455 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005456 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005457 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005458
5459 if (use_file_for_err)
5460 {
5461 char_u *fname = options->jo_io_name[PART_ERR];
5462
5463 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5464 if (fd_err[1] < 0)
5465 {
5466 EMSG2(_(e_notopen), fname);
5467 goto failed;
5468 }
5469 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005470 else if (!use_out_for_err && !use_null_for_err
5471 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005472 goto failed;
5473
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005474 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5475 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005476 if (options->jo_set & JO_CHANNEL)
5477 {
5478 channel = options->jo_channel;
5479 if (channel != NULL)
5480 ++channel->ch_refcount;
5481 }
5482 else
5483 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005484 if (channel == NULL)
5485 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005486 if (job->jv_tty_out != NULL)
5487 ch_log(channel, "using pty %s on fd %d",
5488 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005489 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005490
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005491 BLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005492 pid = fork(); /* maybe we should use vfork() */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005493 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005494 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005495 /* failed to fork */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005496 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005497 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005498 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005499 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005500 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005501 int null_fd = -1;
5502 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005503
Bram Moolenaar835dc632016-02-07 14:27:38 +01005504 /* child */
5505 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005506 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005507
Bram Moolenaar819524702018-02-27 19:10:00 +01005508# ifdef FEAT_JOB_CHANNEL
5509 if (ch_log_active())
5510 /* close the log file in the child */
5511 ch_logfile((char_u *)"", (char_u *)"");
5512# endif
5513
Bram Moolenaar835dc632016-02-07 14:27:38 +01005514# ifdef HAVE_SETSID
5515 /* Create our own process group, so that the child and all its
5516 * children can be kill()ed. Don't do this when using pipes,
5517 * because stdin is not a tty, we would lose /dev/tty. */
5518 (void)setsid();
5519# endif
5520
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005521# ifdef FEAT_TERMINAL
5522 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005523 {
5524 char *term = (char *)T_NAME;
5525
5526#ifdef FEAT_GUI
5527 if (term_is_gui(T_NAME))
5528 /* In the GUI 'term' is not what we want, use $TERM. */
5529 term = getenv("TERM");
5530#endif
5531 /* Use 'term' or $TERM if it starts with "xterm", otherwise fall
5532 * back to "xterm". */
5533 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
5534 term = "xterm";
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005535 set_child_environment(
5536 (long)options->jo_term_rows,
5537 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005538 term,
5539 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005540 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005541 else
5542# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005543 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005544
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005545 if (options->jo_env != NULL)
5546 {
5547 dict_T *dict = options->jo_env;
5548 hashitem_T *hi;
5549 int todo = (int)dict->dv_hashtab.ht_used;
5550
5551 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5552 if (!HASHITEM_EMPTY(hi))
5553 {
5554 typval_T *item = &dict_lookup(hi)->di_tv;
5555
5556 vim_setenv((char_u*)hi->hi_key, get_tv_string(item));
5557 --todo;
5558 }
5559 }
5560
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005561 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005562 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005563 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005564 if (null_fd < 0)
5565 {
5566 perror("opening /dev/null failed");
5567 _exit(OPEN_NULL_FAILED);
5568 }
5569 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005570
Bram Moolenaar223896d2017-08-02 22:33:28 +02005571 if (pty_slave_fd >= 0)
5572 {
5573 /* push stream discipline modules */
5574 SetupSlavePTY(pty_slave_fd);
5575# ifdef TIOCSCTTY
5576 /* Try to become controlling tty (probably doesn't work,
5577 * unless run by root) */
5578 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5579# endif
5580 }
5581
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005582 /* set up stdin for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005583 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005584 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005585 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005586 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005587 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005588 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005589 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005590
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005591 /* set up stderr for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005592 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005593 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005594 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005595 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005596 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005597 }
5598 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005599 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005600 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005601 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005602 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005603 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005604
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005605 /* set up stdout for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005606 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005607 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005608 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005609 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005610 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005611 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005612 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005613
5614 if (fd_in[0] >= 0)
5615 close(fd_in[0]);
5616 if (fd_in[1] >= 0)
5617 close(fd_in[1]);
5618 if (fd_out[0] >= 0)
5619 close(fd_out[0]);
5620 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005621 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005622 if (fd_err[0] >= 0)
5623 close(fd_err[0]);
5624 if (fd_err[1] >= 0)
5625 close(fd_err[1]);
5626 if (pty_master_fd >= 0)
5627 {
Bram Moolenaar223896d2017-08-02 22:33:28 +02005628 close(pty_master_fd); /* not used in the child */
5629 close(pty_slave_fd); /* was duped above */
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005630 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005631
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005632 if (null_fd >= 0)
5633 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005634
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005635 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5636 _exit(EXEC_FAILED);
5637
Bram Moolenaar835dc632016-02-07 14:27:38 +01005638 /* See above for type of argv. */
5639 execvp(argv[0], argv);
5640
Bram Moolenaar4694a172016-04-21 14:05:23 +02005641 if (stderr_works)
5642 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005643# ifdef EXITFREE
Bram Moolenaarcda77642016-06-04 13:32:35 +02005644 /* calling free_all_mem() here causes problems. Ignore valgrind
5645 * reporting possibly leaked memory. */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005646# endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005647 _exit(EXEC_FAILED); /* exec failed, return failure code */
5648 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005649
5650 /* parent */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005651 UNBLOCK_SIGNALS(&curset);
5652
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005653 job->jv_pid = pid;
5654 job->jv_status = JOB_STARTED;
Bram Moolenaarde279892016-03-11 22:19:44 +01005655 job->jv_channel = channel; /* ch_refcount was set above */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005656
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005657 if (pty_master_fd >= 0)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005658 close(pty_slave_fd); /* not used in the parent */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005659 /* close child stdin, stdout and stderr */
Bram Moolenaar819524702018-02-27 19:10:00 +01005660 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005661 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005662 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005663 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005664 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005665 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005666 if (channel != NULL)
5667 {
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005668 int in_fd = use_file_for_in || use_null_for_in
5669 ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1];
5670 int out_fd = use_file_for_out || use_null_for_out
5671 ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0];
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005672 /* When using pty_master_fd only set it for stdout, do not duplicate it
5673 * for stderr, it only needs to be read once. */
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005674 int err_fd = use_out_for_err || use_file_for_err || use_null_for_err
Bram Moolenaarcd8fb442018-05-12 17:42:42 +02005675 ? INVALID_FD
5676 : fd_err[0] >= 0
5677 ? fd_err[0]
5678 : (out_fd == pty_master_fd
5679 ? INVALID_FD
5680 : pty_master_fd);
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005681
5682 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005683 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005684 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005685 else
5686 {
5687 if (fd_in[1] >= 0)
5688 close(fd_in[1]);
5689 if (fd_out[0] >= 0)
5690 close(fd_out[0]);
5691 if (fd_err[0] >= 0)
5692 close(fd_err[0]);
5693 if (pty_master_fd >= 0)
5694 close(pty_master_fd);
5695 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005696
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005697 /* success! */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005698 return;
5699
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005700failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005701 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005702 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005703 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005704 if (fd_in[1] >= 0)
5705 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005706 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005707 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005708 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005709 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005710 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005711 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005712 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005713 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005714 if (pty_master_fd >= 0)
5715 close(pty_master_fd);
5716 if (pty_slave_fd >= 0)
5717 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005718}
5719
5720 char *
5721mch_job_status(job_T *job)
5722{
5723# ifdef HAVE_UNION_WAIT
5724 union wait status;
5725# else
5726 int status = -1;
5727# endif
5728 pid_t wait_pid = 0;
5729
5730# ifdef __NeXT__
5731 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5732# else
5733 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5734# endif
5735 if (wait_pid == -1)
5736 {
5737 /* process must have exited */
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005738 if (job->jv_status < JOB_ENDED)
5739 ch_log(job->jv_channel, "Job no longer exists: %s",
5740 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005741 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005742 }
5743 if (wait_pid == 0)
5744 return "run";
5745 if (WIFEXITED(status))
5746 {
5747 /* LINTED avoid "bitwise operation on signed value" */
5748 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005749 if (job->jv_status < JOB_ENDED)
5750 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005751 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005752 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005753 if (WIFSIGNALED(status))
5754 {
5755 job->jv_exitval = -1;
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005756 if (job->jv_status < JOB_ENDED)
5757 ch_log(job->jv_channel, "Job terminated by a signal");
Bram Moolenaar97792de2016-10-15 18:36:49 +02005758 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005759 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005760 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005761
5762return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005763 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005764 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005765 return "dead";
5766}
5767
5768 job_T *
5769mch_detect_ended_job(job_T *job_list)
5770{
5771# ifdef HAVE_UNION_WAIT
5772 union wait status;
5773# else
5774 int status = -1;
5775# endif
5776 pid_t wait_pid = 0;
5777 job_T *job;
5778
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005779# ifndef USE_SYSTEM
5780 /* Do not do this when waiting for a shell command to finish, we would get
5781 * the exit value here (and discard it), the exit value obtained there
5782 * would then be wrong. */
5783 if (dont_check_job_ended > 0)
5784 return NULL;
5785# endif
5786
Bram Moolenaar97792de2016-10-15 18:36:49 +02005787# ifdef __NeXT__
5788 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5789# else
5790 wait_pid = waitpid(-1, &status, WNOHANG);
5791# endif
5792 if (wait_pid <= 0)
5793 /* no process ended */
5794 return NULL;
5795 for (job = job_list; job != NULL; job = job->jv_next)
5796 {
5797 if (job->jv_pid == wait_pid)
5798 {
5799 if (WIFEXITED(status))
5800 /* LINTED avoid "bitwise operation on signed value" */
5801 job->jv_exitval = WEXITSTATUS(status);
5802 else if (WIFSIGNALED(status))
5803 job->jv_exitval = -1;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005804 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005805 {
5806 ch_log(job->jv_channel, "Job ended");
5807 job->jv_status = JOB_ENDED;
5808 }
5809 return job;
5810 }
5811 }
5812 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005813}
5814
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005815/*
5816 * Send a (deadly) signal to "job".
5817 * Return FAIL if "how" is not a valid name.
5818 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005819 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005820mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005821{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005822 int sig = -1;
5823 pid_t job_pid;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005824
Bram Moolenaar923d9262016-02-25 20:56:01 +01005825 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005826 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005827 else if (STRCMP(how, "hup") == 0)
5828 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005829 else if (STRCMP(how, "quit") == 0)
5830 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005831 else if (STRCMP(how, "int") == 0)
5832 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005833 else if (STRCMP(how, "kill") == 0)
5834 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005835#ifdef SIGWINCH
5836 else if (STRCMP(how, "winch") == 0)
5837 sig = SIGWINCH;
5838#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005839 else if (isdigit(*how))
5840 sig = atoi((char *)how);
5841 else
5842 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005843
Bram Moolenaar72801402016-02-09 11:37:50 +01005844 /* TODO: have an option to only kill the process, not the group? */
Bram Moolenaar76467df2016-02-12 19:30:26 +01005845 job_pid = job->jv_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005846#ifdef HAVE_GETPGID
Bram Moolenaar76467df2016-02-12 19:30:26 +01005847 if (job_pid == getpgid(job_pid))
5848 job_pid = -job_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005849#endif
Bram Moolenaar76467df2016-02-12 19:30:26 +01005850
Bram Moolenaar61a66052017-07-22 18:39:00 +02005851 /* Never kill ourselves! */
5852 if (job_pid != 0)
5853 kill(job_pid, sig);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005854
Bram Moolenaar835dc632016-02-07 14:27:38 +01005855 return OK;
5856}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005857
5858/*
5859 * Clear the data related to "job".
5860 */
5861 void
5862mch_clear_job(job_T *job)
5863{
5864 /* call waitpid because child process may become zombie */
5865# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005866 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005867# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005868 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005869# endif
5870}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005871#endif
5872
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005873#if defined(FEAT_TERMINAL) || defined(PROTO)
5874 int
5875mch_create_pty_channel(job_T *job, jobopt_T *options)
5876{
5877 int pty_master_fd = -1;
5878 int pty_slave_fd = -1;
5879 channel_T *channel;
5880
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005881 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5882 if (job->jv_tty_out != NULL)
5883 job->jv_tty_in = vim_strsave(job->jv_tty_out);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005884 close(pty_slave_fd);
5885
5886 channel = add_channel();
5887 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005888 {
5889 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005890 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005891 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005892 if (job->jv_tty_out != NULL)
5893 ch_log(channel, "using pty %s on fd %d",
5894 job->jv_tty_out, pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005895 job->jv_channel = channel; /* ch_refcount was set by add_channel() */
5896 channel->ch_keep_open = TRUE;
5897
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005898 /* Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5899 * it only needs to be read once. */
5900 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005901 channel_set_job(channel, job, options);
5902 return OK;
5903}
5904#endif
5905
Bram Moolenaar071d4272004-06-13 20:20:40 +00005906/*
5907 * Check for CTRL-C typed by reading all available characters.
5908 * In cooked mode we should get SIGINT, no need to check.
5909 */
5910 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005911mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912{
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005913 if ((curr_tmode == TMODE_RAW || force)
5914 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 fill_input_buf(FALSE);
5916}
5917
5918/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005919 * Wait "msec" msec until a character is available from the mouse, keyboard,
5920 * from inbuf[].
5921 * "msec" == -1 will block forever.
5922 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005923 * When "ignore_input" is TRUE even check for pending input when input is
5924 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005925 * "interrupted" (if not NULL) is set to TRUE when no character is available
5926 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005927 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005928 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 */
5930 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005931WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005933#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01005934 return ui_wait_for_chars_or_timer(
5935 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005936#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005937 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005938#endif
5939}
5940
5941/*
5942 * Wait "msec" msec until a character is available from the mouse or keyboard
5943 * or from inbuf[].
5944 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005945 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02005946 * "interrupted" (if not NULL) is set to TRUE when no character is available
5947 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005948 * When a GUI is being used, this will never get called -- webb
5949 */
5950 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005951WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005952{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953#ifdef FEAT_MOUSE_GPM
5954 int gpm_process_wanted;
5955#endif
5956#ifdef FEAT_XCLIPBOARD
5957 int rest;
5958#endif
5959 int avail;
5960
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005961 if (!ignore_input && input_available()) /* something in inbuf[] */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 return 1;
5963
5964#if defined(FEAT_MOUSE_DEC)
5965 /* May need to query the mouse position. */
5966 if (WantQueryMouse)
5967 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00005968 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
5970 }
5971#endif
5972
5973 /*
5974 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
5975 * events. This is a bit complicated, because they might both be defined.
5976 */
5977#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
5978# ifdef FEAT_XCLIPBOARD
5979 rest = 0;
5980 if (do_xterm_trace())
5981 rest = msec;
5982# endif
5983 do
5984 {
5985# ifdef FEAT_XCLIPBOARD
5986 if (rest != 0)
5987 {
5988 msec = XT_TRACE_DELAY;
5989 if (rest >= 0 && rest < XT_TRACE_DELAY)
5990 msec = rest;
5991 if (rest >= 0)
5992 rest -= msec;
5993 }
5994# endif
5995# ifdef FEAT_MOUSE_GPM
5996 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005997 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02005998 &gpm_process_wanted, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005999# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006000 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001# endif
6002 if (!avail)
6003 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006004 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005 return 1;
6006# ifdef FEAT_XCLIPBOARD
6007 if (rest == 0 || !do_xterm_trace())
6008# endif
6009 break;
6010 }
6011 }
6012 while (FALSE
6013# ifdef FEAT_MOUSE_GPM
6014 || (gpm_process_wanted && mch_gpm_process() == 0)
6015# endif
6016# ifdef FEAT_XCLIPBOARD
6017 || (!avail && rest != 0)
6018# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006019 )
6020 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006021
6022#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006023 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024#endif
6025 return avail;
6026}
6027
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006028#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006029/*
6030 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006031 * "msec" == 0 will check for characters once.
6032 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006034 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006035 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006036 * "interrupted" (if not NULL) is set to TRUE when no character is available
6037 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006039#if defined(__BEOS__)
6040 int
6041#else
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006042 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00006043#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006044RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006045{
6046 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006047 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006048#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006049 static int busy = FALSE;
6050
6051 /* May retry getting characters after an event was handled. */
6052# define MAY_LOOP
6053
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006054# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006055 /* Remember at what time we started, so that we know how much longer we
6056 * should wait after being interrupted. */
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006057 long start_msec = msec;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006058 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006060 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006061 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062# endif
6063
6064 /* Handle being called recursively. This may happen for the session
6065 * manager stuff, it may save the file, which does a breakcheck. */
6066 if (busy)
6067 return 0;
6068#endif
6069
6070#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006071 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072#endif
6073 {
6074#ifdef MAY_LOOP
6075 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006076# ifdef FEAT_MZSCHEME
6077 int mzquantum_used = FALSE;
6078# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079#endif
6080#ifndef HAVE_SELECT
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006081 /* each channel may use in, out and err */
6082 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083 int nfd;
6084# ifdef FEAT_XCLIPBOARD
6085 int xterm_idx = -1;
6086# endif
6087# ifdef FEAT_MOUSE_GPM
6088 int gpm_idx = -1;
6089# endif
6090# ifdef USE_XSMP
6091 int xsmp_idx = -1;
6092# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006093 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006095# ifdef FEAT_MZSCHEME
6096 mzvim_check_threads();
6097 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6098 {
6099 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
6100 mzquantum_used = TRUE;
6101 }
6102# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 fds[0].fd = fd;
6104 fds[0].events = POLLIN;
6105 nfd = 1;
6106
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006108 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006109 if (xterm_Shell != (Widget)0)
6110 {
6111 xterm_idx = nfd;
6112 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6113 fds[nfd].events = POLLIN;
6114 nfd++;
6115 }
6116# endif
6117# ifdef FEAT_MOUSE_GPM
6118 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6119 {
6120 gpm_idx = nfd;
6121 fds[nfd].fd = gpm_fd;
6122 fds[nfd].events = POLLIN;
6123 nfd++;
6124 }
6125# endif
6126# ifdef USE_XSMP
6127 if (xsmp_icefd != -1)
6128 {
6129 xsmp_idx = nfd;
6130 fds[nfd].fd = xsmp_icefd;
6131 fds[nfd].events = POLLIN;
6132 nfd++;
6133 }
6134# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006135#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006136 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006137#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006138 if (interrupted != NULL)
6139 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006141 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006142
6143 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006144 if (result == 0 && interrupted != NULL && ret > 0)
6145 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006146
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006147# ifdef FEAT_MZSCHEME
6148 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006149 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006150 finished = FALSE;
6151# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006152
Bram Moolenaar071d4272004-06-13 20:20:40 +00006153# ifdef FEAT_XCLIPBOARD
6154 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6155 {
6156 xterm_update(); /* Maybe we should hand out clipboard */
6157 if (--ret == 0 && !input_available())
6158 /* Try again */
6159 finished = FALSE;
6160 }
6161# endif
6162# ifdef FEAT_MOUSE_GPM
6163 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
6164 {
6165 *check_for_gpm = 1;
6166 }
6167# endif
6168# ifdef USE_XSMP
6169 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6170 {
6171 if (fds[xsmp_idx].revents & POLLIN)
6172 {
6173 busy = TRUE;
6174 xsmp_handle_requests();
6175 busy = FALSE;
6176 }
6177 else if (fds[xsmp_idx].revents & POLLHUP)
6178 {
6179 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006180 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181 xsmp_close();
6182 }
6183 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006184 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185 }
6186# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006187#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006188 /* also call when ret == 0, we may be polling a keep-open channel */
6189 if (ret >= 0)
Bram Moolenaare0874f82016-01-24 20:36:41 +01006190 ret = channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006191#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193#else /* HAVE_SELECT */
6194
6195 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006196 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006197 // These are static because they can take 8 Kbyte each and cause the
6198 // signal stack to run out with -O3.
6199 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006201 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006202
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006203# ifdef FEAT_MZSCHEME
6204 mzvim_check_threads();
6205 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6206 {
6207 towait = p_mzq; /* don't wait longer than 'mzquantum' */
6208 mzquantum_used = TRUE;
6209 }
6210# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006212 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006213 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006214 tv.tv_sec = towait / 1000;
6215 tv.tv_usec = (towait % 1000) * (1000000/1000);
6216 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006217 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006218 else
6219 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006220
6221 /*
6222 * Select on ready for reading and exceptional condition (end of file).
6223 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006224select_eintr:
6225 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006226 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006227 FD_ZERO(&efds);
6228 FD_SET(fd, &rfds);
6229# if !defined(__QNX__) && !defined(__CYGWIN32__)
6230 /* For QNX select() always returns 1 if this is set. Why? */
6231 FD_SET(fd, &efds);
6232# endif
6233 maxfd = fd;
6234
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006236 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237 if (xterm_Shell != (Widget)0)
6238 {
6239 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6240 if (maxfd < ConnectionNumber(xterm_dpy))
6241 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006242
6243 /* An event may have already been read but not handled. In
6244 * particulary, XFlush may cause this. */
6245 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 }
6247# endif
6248# ifdef FEAT_MOUSE_GPM
6249 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6250 {
6251 FD_SET(gpm_fd, &rfds);
6252 FD_SET(gpm_fd, &efds);
6253 if (maxfd < gpm_fd)
6254 maxfd = gpm_fd;
6255 }
6256# endif
6257# ifdef USE_XSMP
6258 if (xsmp_icefd != -1)
6259 {
6260 FD_SET(xsmp_icefd, &rfds);
6261 FD_SET(xsmp_icefd, &efds);
6262 if (maxfd < xsmp_icefd)
6263 maxfd = xsmp_icefd;
6264 }
6265# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006266# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006267 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006268# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006269 if (interrupted != NULL)
6270 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271
Bram Moolenaar643b6142018-09-12 20:29:09 +02006272 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6273 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006274 result = ret > 0 && FD_ISSET(fd, &rfds);
6275 if (result)
6276 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006277 else if (interrupted != NULL && ret > 0)
6278 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006279
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006280# ifdef EINTR
6281 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006282 {
6283 /* Check whether window has been resized, EINTR may be caused by
6284 * SIGWINCH. */
6285 if (do_resize)
6286 handle_resize();
6287
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006288 /* Interrupted by a signal, need to try again. We ignore msec
6289 * here, because we do want to check even after a timeout if
6290 * characters are available. Needed for reading output of an
6291 * external command after the process has finished. */
6292 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006293 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006294# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006295# ifdef __TANDEM
6296 if (ret == -1 && errno == ENOTSUP)
6297 {
6298 FD_ZERO(&rfds);
6299 FD_ZERO(&efds);
6300 ret = 0;
6301 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006302# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006303# ifdef FEAT_MZSCHEME
6304 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006305 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006306 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006307# endif
6308
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309# ifdef FEAT_XCLIPBOARD
6310 if (ret > 0 && xterm_Shell != (Widget)0
6311 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6312 {
6313 xterm_update(); /* Maybe we should hand out clipboard */
6314 /* continue looping when we only got the X event and the input
6315 * buffer is empty */
6316 if (--ret == 0 && !input_available())
6317 {
6318 /* Try again */
6319 finished = FALSE;
6320 }
6321 }
6322# endif
6323# ifdef FEAT_MOUSE_GPM
6324 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6325 {
6326 if (FD_ISSET(gpm_fd, &efds))
6327 gpm_close();
6328 else if (FD_ISSET(gpm_fd, &rfds))
6329 *check_for_gpm = 1;
6330 }
6331# endif
6332# ifdef USE_XSMP
6333 if (ret > 0 && xsmp_icefd != -1)
6334 {
6335 if (FD_ISSET(xsmp_icefd, &efds))
6336 {
6337 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006338 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006339 xsmp_close();
6340 if (--ret == 0)
6341 finished = FALSE; /* keep going if event was only one */
6342 }
6343 else if (FD_ISSET(xsmp_icefd, &rfds))
6344 {
6345 busy = TRUE;
6346 xsmp_handle_requests();
6347 busy = FALSE;
6348 if (--ret == 0)
6349 finished = FALSE; /* keep going if event was only one */
6350 }
6351 }
6352# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006353#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006354 /* also call when ret == 0, we may be polling a keep-open channel */
6355 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006356 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006357#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006358
6359#endif /* HAVE_SELECT */
6360
6361#ifdef MAY_LOOP
6362 if (finished || msec == 0)
6363 break;
6364
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006365# ifdef FEAT_CLIENTSERVER
6366 if (server_waiting())
6367 break;
6368# endif
6369
Bram Moolenaar071d4272004-06-13 20:20:40 +00006370 /* We're going to loop around again, find out for how long */
6371 if (msec > 0)
6372 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006373# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006374 /* Compute remaining wait time. */
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006375 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376# else
6377 /* Guess we got interrupted halfway. */
6378 msec = msec / 2;
6379# endif
6380 if (msec <= 0)
6381 break; /* waited long enough */
6382 }
6383#endif
6384 }
6385
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006386 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006387}
6388
Bram Moolenaar071d4272004-06-13 20:20:40 +00006389#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006391 * Expand a path into all matching files and/or directories. Handles "*",
6392 * "?", "[a-z]", "**", etc.
6393 * "path" has backslashes before chars that are not to be expanded.
6394 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006395 */
6396 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006397mch_expandpath(
6398 garray_T *gap,
6399 char_u *path,
6400 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006401{
Bram Moolenaar02743632005-07-25 20:42:36 +00006402 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006403}
6404#endif
6405
6406/*
6407 * mch_expand_wildcards() - this code does wild-card pattern matching using
6408 * the shell
6409 *
6410 * return OK for success, FAIL for error (you may lose some memory) and put
6411 * an error message in *file.
6412 *
6413 * num_pat is number of input patterns
6414 * pat is array of pointers to input patterns
6415 * num_file is pointer to number of matched file names
6416 * file is pointer to array of pointers to matched file names
6417 */
6418
6419#ifndef SEEK_SET
6420# define SEEK_SET 0
6421#endif
6422#ifndef SEEK_END
6423# define SEEK_END 2
6424#endif
6425
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006426#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006427
Bram Moolenaar071d4272004-06-13 20:20:40 +00006428 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006429mch_expand_wildcards(
6430 int num_pat,
6431 char_u **pat,
6432 int *num_file,
6433 char_u ***file,
6434 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435{
6436 int i;
6437 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006438 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439 char_u *p;
6440 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441
Bram Moolenaarc7247912008-01-13 12:54:11 +00006442 /*
6443 * This is the non-OS/2 implementation (really Unix).
6444 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006445 int j;
6446 char_u *tempname;
6447 char_u *command;
6448 FILE *fd;
6449 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006450#define STYLE_ECHO 0 /* use "echo", the default */
6451#define STYLE_GLOB 1 /* use "glob", for csh */
6452#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
6453#define STYLE_PRINT 3 /* use "print -N", for zsh */
6454#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
6455 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006456 int shell_style = STYLE_ECHO;
6457 int check_spaces;
6458 static int did_find_nul = FALSE;
6459 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006460 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006461 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006462
6463 *num_file = 0; /* default: no files found */
6464 *file = NULL;
6465
6466 /*
6467 * If there are no wildcards, just copy the names to allocated memory.
6468 * Saves a lot of time, because we don't have to start a new shell.
6469 */
6470 if (!have_wildcard(num_pat, pat))
6471 return save_patterns(num_pat, pat, num_file, file);
6472
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006473# ifdef HAVE_SANDBOX
6474 /* Don't allow any shell command in the sandbox. */
6475 if (sandbox != 0 && check_secure())
6476 return FAIL;
6477# endif
6478
Bram Moolenaar071d4272004-06-13 20:20:40 +00006479 /*
6480 * Don't allow the use of backticks in secure and restricted mode.
6481 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006482 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006483 for (i = 0; i < num_pat; ++i)
6484 if (vim_strchr(pat[i], '`') != NULL
6485 && (check_restricted() || check_secure()))
6486 return FAIL;
6487
6488 /*
6489 * get a name for the temp file
6490 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006491 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006492 {
6493 EMSG(_(e_notmp));
6494 return FAIL;
6495 }
6496
6497 /*
6498 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006499 * file.
6500 * STYLE_BT: NL separated
6501 * If expanding `cmd` execute it directly.
6502 * STYLE_GLOB: NUL separated
6503 * If we use *csh, "glob" will work better than "echo".
6504 * STYLE_PRINT: NL or NUL separated
6505 * If we use *zsh, "print -N" will work better than "glob".
6506 * STYLE_VIMGLOB: NL separated
6507 * If we use *sh*, we define "vimglob()".
6508 * STYLE_ECHO: space separated.
6509 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510 */
6511 if (num_pat == 1 && *pat[0] == '`'
6512 && (len = STRLEN(pat[0])) > 2
6513 && *(pat[0] + len - 1) == '`')
6514 shell_style = STYLE_BT;
6515 else if ((len = STRLEN(p_sh)) >= 3)
6516 {
6517 if (STRCMP(p_sh + len - 3, "csh") == 0)
6518 shell_style = STYLE_GLOB;
6519 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6520 shell_style = STYLE_PRINT;
6521 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006522 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6523 "sh") != NULL)
6524 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525
Bram Moolenaarc7247912008-01-13 12:54:11 +00006526 /* Compute the length of the command. We need 2 extra bytes: for the
6527 * optional '&' and for the NUL.
6528 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006529 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006530 if (shell_style == STYLE_VIMGLOB)
6531 len += STRLEN(sh_vimglob_func);
6532
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006533 for (i = 0; i < num_pat; ++i)
6534 {
6535 /* Count the length of the patterns in the same way as they are put in
6536 * "command" below. */
6537#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006539#else
6540 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006541 for (j = 0; pat[i][j] != NUL; ++j)
6542 {
6543 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
6544 ++len; /* may add a backslash */
6545 ++len;
6546 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006547#endif
6548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006549 command = alloc(len);
6550 if (command == NULL)
6551 {
6552 /* out of memory */
6553 vim_free(tempname);
6554 return FAIL;
6555 }
6556
6557 /*
6558 * Build the shell command:
6559 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6560 * recognizes this).
6561 * - Add the shell command to print the expanded names.
6562 * - Add the temp file name.
6563 * - Add the file name patterns.
6564 */
6565 if (shell_style == STYLE_BT)
6566 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00006567 /* change `command; command& ` to (command; command ) */
6568 STRCPY(command, "(");
6569 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006570 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006571 *p-- = ')'; /* remove last backtick */
Bram Moolenaar1c465442017-03-12 20:10:05 +01006572 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006573 --p;
6574 if (*p == '&') /* remove trailing '&' */
6575 {
6576 ampersent = TRUE;
6577 *p = ' ';
6578 }
6579 STRCAT(command, ">");
6580 }
6581 else
6582 {
6583 if (flags & EW_NOTFOUND)
6584 STRCPY(command, "set nonomatch; ");
6585 else
6586 STRCPY(command, "unset nonomatch; ");
6587 if (shell_style == STYLE_GLOB)
6588 STRCAT(command, "glob >");
6589 else if (shell_style == STYLE_PRINT)
6590 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006591 else if (shell_style == STYLE_VIMGLOB)
6592 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006593 else
6594 STRCAT(command, "echo >");
6595 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006596
Bram Moolenaar071d4272004-06-13 20:20:40 +00006597 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006598
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599 if (shell_style != STYLE_BT)
6600 for (i = 0; i < num_pat; ++i)
6601 {
6602 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00006603 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006604 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605#ifdef USE_SYSTEM
6606 STRCAT(command, " \"");
6607 STRCAT(command, pat[i]);
6608 STRCAT(command, "\"");
6609#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006610 int intick = FALSE;
6611
Bram Moolenaar071d4272004-06-13 20:20:40 +00006612 p = command + STRLEN(command);
6613 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006614 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006615 {
6616 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006617 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006618 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6619 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006620 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00006621 * backslash inside backticks, before a special character
6622 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006623 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006624 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6625 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006626 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006627 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006628 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006629 else if (!intick
6630 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6631 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00006632 /* Put a backslash before a special character, but not
Bram Moolenaare4df1642014-08-29 12:58:44 +02006633 * when inside ``. And not for $var when EW_KEEPDOLLAR is
6634 * set. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006635 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006636
6637 /* Copy one character. */
6638 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006639 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006640 *p = NUL;
6641#endif
6642 }
6643 if (flags & EW_SILENT)
6644 show_shell_mess = FALSE;
6645 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00006646 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647
6648 /*
6649 * Using zsh -G: If a pattern has no matches, it is just deleted from
6650 * the argument list, otherwise zsh gives an error message and doesn't
6651 * expand any other pattern.
6652 */
6653 if (shell_style == STYLE_PRINT)
6654 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
6655
6656 /*
6657 * If we use -f then shell variables set in .cshrc won't get expanded.
6658 * vi can do it, so we will too, but it is only necessary if there is a "$"
6659 * in one of the patterns, otherwise we can still use the fast option.
6660 */
6661 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
6662 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
6663
6664 /*
6665 * execute the shell command
6666 */
6667 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6668
6669 /* When running in the background, give it some time to create the temp
6670 * file, but don't wait for it to finish. */
6671 if (ampersent)
6672 mch_delay(10L, TRUE);
6673
6674 extra_shell_arg = NULL; /* cleanup */
6675 show_shell_mess = TRUE;
6676 vim_free(command);
6677
Bram Moolenaarc7247912008-01-13 12:54:11 +00006678 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006679 {
6680 mch_remove(tempname);
6681 vim_free(tempname);
6682 /*
6683 * With interactive completion, the error message is not printed.
6684 * However with USE_SYSTEM, I don't know how to turn off error messages
6685 * from the shell, so screen may still get messed up -- webb.
6686 */
6687#ifndef USE_SYSTEM
6688 if (!(flags & EW_SILENT))
6689#endif
6690 {
6691 redraw_later_clear(); /* probably messed up screen */
6692 msg_putchar('\n'); /* clear bottom line quickly */
6693 cmdline_row = Rows - 1; /* continue on last line */
6694#ifdef USE_SYSTEM
6695 if (!(flags & EW_SILENT))
6696#endif
6697 {
6698 MSG(_(e_wildexpand));
6699 msg_start(); /* don't overwrite this message */
6700 }
6701 }
6702 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
6703 * EW_NOTFOUND is given */
6704 if (shell_style == STYLE_BT)
6705 return FAIL;
6706 goto notfound;
6707 }
6708
6709 /*
6710 * read the names from the file into memory
6711 */
6712 fd = fopen((char *)tempname, READBIN);
6713 if (fd == NULL)
6714 {
6715 /* Something went wrong, perhaps a file name with a special char. */
6716 if (!(flags & EW_SILENT))
6717 {
6718 MSG(_(e_wildexpand));
6719 msg_start(); /* don't overwrite this message */
6720 }
6721 vim_free(tempname);
6722 goto notfound;
6723 }
6724 fseek(fd, 0L, SEEK_END);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006725 llen = ftell(fd); /* get size of temp file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006726 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006727 if (llen < 0)
6728 /* just in case ftell() would fail */
6729 buffer = NULL;
6730 else
6731 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006732 if (buffer == NULL)
6733 {
6734 /* out of memory */
6735 mch_remove(tempname);
6736 vim_free(tempname);
6737 fclose(fd);
6738 return FAIL;
6739 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006740 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006741 i = fread((char *)buffer, 1, len, fd);
6742 fclose(fd);
6743 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006744 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006745 {
6746 /* unexpected read error */
6747 EMSG2(_(e_notread), tempname);
6748 vim_free(tempname);
6749 vim_free(buffer);
6750 return FAIL;
6751 }
6752 vim_free(tempname);
6753
Bram Moolenaarc7247912008-01-13 12:54:11 +00006754# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006755 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
6756 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006757 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006758 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6759 *p++ = buffer[i];
6760 len = p - buffer;
6761# endif
6762
6763
6764 /* file names are separated with Space */
6765 if (shell_style == STYLE_ECHO)
6766 {
6767 buffer[len] = '\n'; /* make sure the buffer ends in NL */
6768 p = buffer;
6769 for (i = 0; *p != '\n'; ++i) /* count number of entries */
6770 {
6771 while (*p != ' ' && *p != '\n')
6772 ++p;
6773 p = skipwhite(p); /* skip to next entry */
6774 }
6775 }
6776 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006777 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006778 {
6779 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6780 p = buffer;
6781 for (i = 0; *p != NUL; ++i) /* count number of entries */
6782 {
6783 while (*p != '\n' && *p != NUL)
6784 ++p;
6785 if (*p != NUL)
6786 ++p;
6787 p = skipwhite(p); /* skip leading white space */
6788 }
6789 }
6790 /* file names are separated with NUL */
6791 else
6792 {
6793 /*
6794 * Some versions of zsh use spaces instead of NULs to separate
6795 * results. Only do this when there is no NUL before the end of the
6796 * buffer, otherwise we would never be able to use file names with
6797 * embedded spaces when zsh does use NULs.
6798 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6799 * don't check for spaces again.
6800 */
6801 check_spaces = FALSE;
6802 if (shell_style == STYLE_PRINT && !did_find_nul)
6803 {
6804 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006805 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006806 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006807 did_find_nul = TRUE;
6808 else
6809 check_spaces = TRUE;
6810 }
6811
6812 /*
6813 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6814 * already is one, for STYLE_GLOB it needs to be added.
6815 */
6816 if (len && buffer[len - 1] == NUL)
6817 --len;
6818 else
6819 buffer[len] = NUL;
6820 i = 0;
6821 for (p = buffer; p < buffer + len; ++p)
6822 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6823 {
6824 ++i;
6825 *p = NUL;
6826 }
6827 if (len)
6828 ++i; /* count last entry */
6829 }
6830 if (i == 0)
6831 {
6832 /*
6833 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6834 * /bin/sh will happily expand it to nothing rather than returning an
6835 * error; and hey, it's good to check anyway -- webb.
6836 */
6837 vim_free(buffer);
6838 goto notfound;
6839 }
6840 *num_file = i;
6841 *file = (char_u **)alloc(sizeof(char_u *) * i);
6842 if (*file == NULL)
6843 {
6844 /* out of memory */
6845 vim_free(buffer);
6846 return FAIL;
6847 }
6848
6849 /*
6850 * Isolate the individual file names.
6851 */
6852 p = buffer;
6853 for (i = 0; i < *num_file; ++i)
6854 {
6855 (*file)[i] = p;
6856 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006857 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6858 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006859 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006860 while (!(shell_style == STYLE_ECHO && *p == ' ')
6861 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006862 ++p;
6863 if (p == buffer + len) /* last entry */
6864 *p = NUL;
6865 else
6866 {
6867 *p++ = NUL;
6868 p = skipwhite(p); /* skip to next entry */
6869 }
6870 }
6871 else /* NUL separates */
6872 {
6873 while (*p && p < buffer + len) /* skip entry */
6874 ++p;
6875 ++p; /* skip NUL */
6876 }
6877 }
6878
6879 /*
6880 * Move the file names to allocated memory.
6881 */
6882 for (j = 0, i = 0; i < *num_file; ++i)
6883 {
6884 /* Require the files to exist. Helps when using /bin/sh */
6885 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6886 continue;
6887
6888 /* check if this entry should be included */
6889 dir = (mch_isdir((*file)[i]));
6890 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6891 continue;
6892
Bram Moolenaara2031822006-03-07 22:29:51 +00006893 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01006894 if (!dir && (flags & EW_EXEC)
6895 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006896 continue;
6897
Bram Moolenaar071d4272004-06-13 20:20:40 +00006898 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6899 if (p)
6900 {
6901 STRCPY(p, (*file)[i]);
6902 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006903 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006904 (*file)[j++] = p;
6905 }
6906 }
6907 vim_free(buffer);
6908 *num_file = j;
6909
6910 if (*num_file == 0) /* rejected all entries */
6911 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006912 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 goto notfound;
6914 }
6915
6916 return OK;
6917
6918notfound:
6919 if (flags & EW_NOTFOUND)
6920 return save_patterns(num_pat, pat, num_file, file);
6921 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922}
6923
6924#endif /* VMS */
6925
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006927save_patterns(
6928 int num_pat,
6929 char_u **pat,
6930 int *num_file,
6931 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006932{
6933 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006934 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006935
6936 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6937 if (*file == NULL)
6938 return FAIL;
6939 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006940 {
6941 s = vim_strsave(pat[i]);
6942 if (s != NULL)
6943 /* Be compatible with expand_filename(): halve the number of
6944 * backslashes. */
6945 backslash_halve(s);
6946 (*file)[i] = s;
6947 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006948 *num_file = num_pat;
6949 return OK;
6950}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006951
Bram Moolenaar071d4272004-06-13 20:20:40 +00006952/*
6953 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6954 * expand.
6955 */
6956 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006957mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006958{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006959 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006960 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 if (*p == '\\' && p[1] != NUL)
6962 ++p;
6963 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006964 if (vim_strchr((char_u *)
6965#ifdef VMS
6966 "*?%"
6967#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006968 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006969#endif
6970 , *p) != NULL)
6971 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006972 }
6973 return FALSE;
6974}
6975
6976/*
6977 * Return TRUE if the string "p" contains a wildcard.
6978 * Don't recognize '~' at the end as a wildcard.
6979 */
6980 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006981mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006982{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006983 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006984 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006985 if (*p == '\\' && p[1] != NUL)
6986 ++p;
6987 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006988 if (vim_strchr((char_u *)
6989#ifdef VMS
6990 "*?%$"
6991#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006992 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006993#endif
6994 , *p) != NULL
6995 || (*p == '~' && p[1] != NUL))
6996 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006997 }
6998 return FALSE;
6999}
7000
Bram Moolenaar071d4272004-06-13 20:20:40 +00007001 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007002have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003{
7004 int i;
7005
7006 for (i = 0; i < num; i++)
7007 if (mch_has_wildcard(file[i]))
7008 return 1;
7009 return 0;
7010}
7011
7012 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007013have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007014{
7015 int i;
7016
7017 for (i = 0; i < num; i++)
7018 if (vim_strchr(file[i], '$') != NULL)
7019 return TRUE;
7020 return FALSE;
7021}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007022
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007023#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007024/*
7025 * Scaled-down version of rename(), which is missing in Xenix.
7026 * This version can only move regular files and will fail if the
7027 * destination exists.
7028 */
7029 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007030mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007031{
7032 struct stat st;
7033
7034 if (stat(dest, &st) >= 0) /* fail if destination exists */
7035 return -1;
7036 if (link(src, dest) != 0) /* link file to new name */
7037 return -1;
7038 if (mch_remove(src) == 0) /* delete link to old name */
7039 return 0;
7040 return -1;
7041}
7042#endif /* !HAVE_RENAME */
7043
7044#ifdef FEAT_MOUSE_GPM
7045/*
7046 * Initializes connection with gpm (if it isn't already opened)
7047 * Return 1 if succeeded (or connection already opened), 0 if failed
7048 */
7049 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007050gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007051{
7052 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
7053
7054 if (!gpm_flag)
7055 {
7056 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7057 gpm_connect.defaultMask = ~GPM_HARD;
7058 /* Default handling for mouse move*/
7059 gpm_connect.minMod = 0; /* Handle any modifier keys */
7060 gpm_connect.maxMod = 0xffff;
7061 if (Gpm_Open(&gpm_connect, 0) > 0)
7062 {
7063 /* gpm library tries to handling TSTP causes
7064 * problems. Anyways, we close connection to Gpm whenever
7065 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00007066 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007068# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007070# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007071 return 1; /* succeed */
7072 }
7073 if (gpm_fd == -2)
7074 Gpm_Close(); /* We don't want to talk to xterm via gpm */
7075 return 0;
7076 }
7077 return 1; /* already open */
7078}
7079
7080/*
7081 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007082 */
7083 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007084gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085{
7086 if (gpm_flag && gpm_fd >= 0) /* if Open */
7087 Gpm_Close();
7088}
7089
7090/* Reads gpm event and adds special keys to input buf. Returns length of
7091 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007092 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007093 */
7094 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007095mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007096{
7097 int button;
7098 static Gpm_Event gpm_event;
7099 char_u string[6];
7100 int_u vim_modifiers;
7101 int row,col;
7102 unsigned char buttons_mask;
7103 unsigned char gpm_modifiers;
7104 static unsigned char old_buttons = 0;
7105
7106 Gpm_GetEvent(&gpm_event);
7107
7108#ifdef FEAT_GUI
7109 /* Don't put events in the input queue now. */
7110 if (hold_gui_events)
7111 return 0;
7112#endif
7113
7114 row = gpm_event.y - 1;
7115 col = gpm_event.x - 1;
7116
7117 string[0] = ESC; /* Our termcode */
7118 string[1] = 'M';
7119 string[2] = 'G';
7120 switch (GPM_BARE_EVENTS(gpm_event.type))
7121 {
7122 case GPM_DRAG:
7123 string[3] = MOUSE_DRAG;
7124 break;
7125 case GPM_DOWN:
7126 buttons_mask = gpm_event.buttons & ~old_buttons;
7127 old_buttons = gpm_event.buttons;
7128 switch (buttons_mask)
7129 {
7130 case GPM_B_LEFT:
7131 button = MOUSE_LEFT;
7132 break;
7133 case GPM_B_MIDDLE:
7134 button = MOUSE_MIDDLE;
7135 break;
7136 case GPM_B_RIGHT:
7137 button = MOUSE_RIGHT;
7138 break;
7139 default:
7140 return 0;
7141 /*Don't know what to do. Can more than one button be
7142 * reported in one event? */
7143 }
7144 string[3] = (char_u)(button | 0x20);
7145 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7146 break;
7147 case GPM_UP:
7148 string[3] = MOUSE_RELEASE;
7149 old_buttons &= ~gpm_event.buttons;
7150 break;
7151 default:
7152 return 0;
7153 }
7154 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
7155 gpm_modifiers = gpm_event.modifiers;
7156 vim_modifiers = 0x0;
7157 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
7158 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7159 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
7160 */
7161 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7162 vim_modifiers |= MOUSE_SHIFT;
7163
7164 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7165 vim_modifiers |= MOUSE_CTRL;
7166 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7167 vim_modifiers |= MOUSE_ALT;
7168 string[3] |= vim_modifiers;
7169 string[4] = (char_u)(col + ' ' + 1);
7170 string[5] = (char_u)(row + ' ' + 1);
7171 add_to_input_buf(string, 6);
7172 return 6;
7173}
7174#endif /* FEAT_MOUSE_GPM */
7175
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007176#ifdef FEAT_SYSMOUSE
7177/*
7178 * Initialize connection with sysmouse.
7179 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7180 * output, any sysmouse output than will be processed via sig_sysmouse().
7181 * Return OK if succeeded, FAIL if failed.
7182 */
7183 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007184sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007185{
7186 struct mouse_info mouse;
7187
7188 mouse.operation = MOUSE_MODE;
7189 mouse.u.mode.mode = 0;
7190 mouse.u.mode.signal = SIGUSR2;
7191 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7192 {
7193 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7194 mouse.operation = MOUSE_SHOW;
7195 ioctl(1, CONS_MOUSECTL, &mouse);
7196 return OK;
7197 }
7198 return FAIL;
7199}
7200
7201/*
7202 * Stop processing SIGUSR2 signals, and also make sure that
7203 * virtual console do not send us any sysmouse related signal.
7204 */
7205 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007206sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007207{
7208 struct mouse_info mouse;
7209
7210 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7211 mouse.operation = MOUSE_MODE;
7212 mouse.u.mode.mode = 0;
7213 mouse.u.mode.signal = 0;
7214 ioctl(1, CONS_MOUSECTL, &mouse);
7215}
7216
7217/*
7218 * Gets info from sysmouse and adds special keys to input buf.
7219 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007220 static RETSIGTYPE
7221sig_sysmouse SIGDEFARG(sigarg)
7222{
7223 struct mouse_info mouse;
7224 struct video_info video;
7225 char_u string[6];
7226 int row, col;
7227 int button;
7228 int buttons;
7229 static int oldbuttons = 0;
7230
7231#ifdef FEAT_GUI
7232 /* Don't put events in the input queue now. */
7233 if (hold_gui_events)
7234 return;
7235#endif
7236
7237 mouse.operation = MOUSE_GETINFO;
7238 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7239 && ioctl(1, FBIO_MODEINFO, &video) != -1
7240 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7241 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7242 {
7243 row = mouse.u.data.y / video.vi_cheight;
7244 col = mouse.u.data.x / video.vi_cwidth;
7245 buttons = mouse.u.data.buttons;
7246 string[0] = ESC; /* Our termcode */
7247 string[1] = 'M';
7248 string[2] = 'S';
7249 if (oldbuttons == buttons && buttons != 0)
7250 {
7251 button = MOUSE_DRAG;
7252 }
7253 else
7254 {
7255 switch (buttons)
7256 {
7257 case 0:
7258 button = MOUSE_RELEASE;
7259 break;
7260 case 1:
7261 button = MOUSE_LEFT;
7262 break;
7263 case 2:
7264 button = MOUSE_MIDDLE;
7265 break;
7266 case 4:
7267 button = MOUSE_RIGHT;
7268 break;
7269 default:
7270 return;
7271 }
7272 oldbuttons = buttons;
7273 }
7274 string[3] = (char_u)(button);
7275 string[4] = (char_u)(col + ' ' + 1);
7276 string[5] = (char_u)(row + ' ' + 1);
7277 add_to_input_buf(string, 6);
7278 }
7279 return;
7280}
7281#endif /* FEAT_SYSMOUSE */
7282
Bram Moolenaar071d4272004-06-13 20:20:40 +00007283#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007284typedef char_u * (*STRPROCSTR)(char_u *);
7285typedef char_u * (*INTPROCSTR)(int);
7286typedef int (*STRPROCINT)(char_u *);
7287typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007288
7289/*
7290 * Call a DLL routine which takes either a string or int param
7291 * and returns an allocated string.
7292 */
7293 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007294mch_libcall(
7295 char_u *libname,
7296 char_u *funcname,
7297 char_u *argstring, /* NULL when using a argint */
7298 int argint,
7299 char_u **string_result,/* NULL when using number_result */
7300 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007301{
7302# if defined(USE_DLOPEN)
7303 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007304 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007305# else
7306 shl_t hinstLib;
7307# endif
7308 STRPROCSTR ProcAdd;
7309 INTPROCSTR ProcAddI;
7310 char_u *retval_str = NULL;
7311 int retval_int = 0;
7312 int success = FALSE;
7313
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007314 /*
7315 * Get a handle to the DLL module.
7316 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007317# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007318 /* First clear any error, it's not cleared by the dlopen() call. */
7319 (void)dlerror();
7320
Bram Moolenaar071d4272004-06-13 20:20:40 +00007321 hinstLib = dlopen((char *)libname, RTLD_LAZY
7322# ifdef RTLD_LOCAL
7323 | RTLD_LOCAL
7324# endif
7325 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007326 if (hinstLib == NULL)
7327 {
7328 /* "dlerr" must be used before dlclose() */
7329 dlerr = (char *)dlerror();
7330 if (dlerr != NULL)
7331 EMSG2(_("dlerror = \"%s\""), dlerr);
7332 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007333# else
7334 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7335# endif
7336
7337 /* If the handle is valid, try to get the function address. */
7338 if (hinstLib != NULL)
7339 {
7340# ifdef HAVE_SETJMP_H
7341 /*
7342 * Catch a crash when calling the library function. For example when
7343 * using a number where a string pointer is expected.
7344 */
7345 mch_startjmp();
7346 if (SETJMP(lc_jump_env) != 0)
7347 {
7348 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007349# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007350 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007351# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007352 mch_didjmp();
7353 }
7354 else
7355# endif
7356 {
7357 retval_str = NULL;
7358 retval_int = 0;
7359
7360 if (argstring != NULL)
7361 {
7362# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007363 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007364 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365# else
7366 if (shl_findsym(&hinstLib, (const char *)funcname,
7367 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7368 ProcAdd = NULL;
7369# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007370 if ((success = (ProcAdd != NULL
7371# if defined(USE_DLOPEN)
7372 && dlerr == NULL
7373# endif
7374 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007375 {
7376 if (string_result == NULL)
7377 retval_int = ((STRPROCINT)ProcAdd)(argstring);
7378 else
7379 retval_str = (ProcAdd)(argstring);
7380 }
7381 }
7382 else
7383 {
7384# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007385 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007386 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007387# else
7388 if (shl_findsym(&hinstLib, (const char *)funcname,
7389 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7390 ProcAddI = NULL;
7391# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007392 if ((success = (ProcAddI != NULL
7393# if defined(USE_DLOPEN)
7394 && dlerr == NULL
7395# endif
7396 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397 {
7398 if (string_result == NULL)
7399 retval_int = ((INTPROCINT)ProcAddI)(argint);
7400 else
7401 retval_str = (ProcAddI)(argint);
7402 }
7403 }
7404
7405 /* Save the string before we free the library. */
7406 /* Assume that a "1" or "-1" result is an illegal pointer. */
7407 if (string_result == NULL)
7408 *number_result = retval_int;
7409 else if (retval_str != NULL
7410 && retval_str != (char_u *)1
7411 && retval_str != (char_u *)-1)
7412 *string_result = vim_strsave(retval_str);
7413 }
7414
7415# ifdef HAVE_SETJMP_H
7416 mch_endjmp();
7417# ifdef SIGHASARG
7418 if (lc_signal != 0)
7419 {
7420 int i;
7421
7422 /* try to find the name of this signal */
7423 for (i = 0; signal_info[i].sig != -1; i++)
7424 if (lc_signal == signal_info[i].sig)
7425 break;
7426 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
7427 }
7428# endif
7429# endif
7430
Bram Moolenaar071d4272004-06-13 20:20:40 +00007431# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007432 /* "dlerr" must be used before dlclose() */
7433 if (dlerr != NULL)
7434 EMSG2(_("dlerror = \"%s\""), dlerr);
7435
7436 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007437 (void)dlclose(hinstLib);
7438# else
7439 (void)shl_unload(hinstLib);
7440# endif
7441 }
7442
7443 if (!success)
7444 {
7445 EMSG2(_(e_libcall), funcname);
7446 return FAIL;
7447 }
7448
7449 return OK;
7450}
7451#endif
7452
7453#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
7454static int xterm_trace = -1; /* default: disabled */
7455static int xterm_button;
7456
7457/*
7458 * Setup a dummy window for X selections in a terminal.
7459 */
7460 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007461setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007462{
7463 int z = 0;
7464 char *strp = "";
7465 Widget AppShell;
7466
7467 if (!x_connect_to_server())
7468 return;
7469
7470 open_app_context();
7471 if (app_context != NULL && xterm_Shell == (Widget)0)
7472 {
7473 int (*oldhandler)();
7474#if defined(HAVE_SETJMP_H)
7475 int (*oldIOhandler)();
7476#endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007477# ifdef ELAPSED_FUNC
7478 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007479
7480 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007481 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007482# endif
7483
7484 /* Ignore X errors while opening the display */
7485 oldhandler = XSetErrorHandler(x_error_check);
7486
7487#if defined(HAVE_SETJMP_H)
7488 /* Ignore X IO errors while opening the display */
7489 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7490 mch_startjmp();
7491 if (SETJMP(lc_jump_env) != 0)
7492 {
7493 mch_didjmp();
7494 xterm_dpy = NULL;
7495 }
7496 else
7497#endif
7498 {
7499 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7500 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
7501#if defined(HAVE_SETJMP_H)
7502 mch_endjmp();
7503#endif
7504 }
7505
7506#if defined(HAVE_SETJMP_H)
7507 /* Now handle X IO errors normally. */
7508 (void)XSetIOErrorHandler(oldIOhandler);
7509#endif
7510 /* Now handle X errors normally. */
7511 (void)XSetErrorHandler(oldhandler);
7512
7513 if (xterm_dpy == NULL)
7514 {
7515 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007516 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007517 return;
7518 }
7519
7520 /* Catch terminating error of the X server connection. */
7521 (void)XSetIOErrorHandler(x_IOerror_handler);
7522
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007523# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007524 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007525 {
7526 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007527 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007528 verbose_leave();
7529 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007530# endif
7531
7532 /* Create a Shell to make converters work. */
7533 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7534 applicationShellWidgetClass, xterm_dpy,
7535 NULL);
7536 if (AppShell == (Widget)0)
7537 return;
7538 xterm_Shell = XtVaCreatePopupShell("VIM",
7539 topLevelShellWidgetClass, AppShell,
7540 XtNmappedWhenManaged, 0,
7541 XtNwidth, 1,
7542 XtNheight, 1,
7543 NULL);
7544 if (xterm_Shell == (Widget)0)
7545 return;
7546
7547 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007548 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007549 if (x11_display == NULL)
7550 x11_display = xterm_dpy;
7551
7552 XtRealizeWidget(xterm_Shell);
7553 XSync(xterm_dpy, False);
7554 xterm_update();
7555 }
7556 if (xterm_Shell != (Widget)0)
7557 {
7558 clip_init(TRUE);
7559 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7560 x11_window = (Window)atol(strp);
7561 /* Check if $WINDOWID is valid. */
7562 if (test_x11_window(xterm_dpy) == FAIL)
7563 x11_window = 0;
7564 if (x11_window != 0)
7565 xterm_trace = 0;
7566 }
7567}
7568
7569 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007570start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007571{
7572 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7573 return;
7574 xterm_trace = 1;
7575 xterm_button = button;
7576 do_xterm_trace();
7577}
7578
7579
7580 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007581stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007582{
7583 if (xterm_trace < 0)
7584 return;
7585 xterm_trace = 0;
7586}
7587
7588/*
7589 * Query the xterm pointer and generate mouse termcodes if necessary
7590 * return TRUE if dragging is active, else FALSE
7591 */
7592 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007593do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007594{
7595 Window root, child;
7596 int root_x, root_y;
7597 int win_x, win_y;
7598 int row, col;
7599 int_u mask_return;
7600 char_u buf[50];
7601 char_u *strp;
7602 long got_hints;
7603 static char_u *mouse_code;
7604 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7605 static int prev_row = 0, prev_col = 0;
7606 static XSizeHints xterm_hints;
7607
7608 if (xterm_trace <= 0)
7609 return FALSE;
7610
7611 if (xterm_trace == 1)
7612 {
7613 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007614 * have changed recently. */
7615 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7616 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007617 || xterm_hints.width_inc <= 1
7618 || xterm_hints.height_inc <= 1)
7619 {
7620 xterm_trace = -1; /* Not enough data -- disable tracing */
7621 return FALSE;
7622 }
7623
7624 /* Rely on the same mouse code for the duration of this */
7625 mouse_code = find_termcode(mouse_name);
7626 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007627 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007628 xterm_trace = 2;
7629
7630 /* Find the offset of the chars, there might be a scrollbar on the
7631 * left of the window and/or a menu on the top (eterm etc.) */
7632 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7633 &win_x, &win_y, &mask_return);
7634 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7635 - (xterm_hints.height_inc / 2);
7636 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7637 xterm_hints.y = 2;
7638 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7639 - (xterm_hints.width_inc / 2);
7640 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7641 xterm_hints.x = 2;
7642 return TRUE;
7643 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007644 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007645 {
7646 xterm_trace = 0;
7647 return FALSE;
7648 }
7649
7650 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7651 &win_x, &win_y, &mask_return);
7652
7653 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7654 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7655 if (row == prev_row && col == prev_col)
7656 return TRUE;
7657
7658 STRCPY(buf, mouse_code);
7659 strp = buf + STRLEN(buf);
7660 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7661 *strp++ = (char_u)(col + ' ' + 1);
7662 *strp++ = (char_u)(row + ' ' + 1);
7663 *strp = 0;
7664 add_to_input_buf(buf, STRLEN(buf));
7665
7666 prev_row = row;
7667 prev_col = col;
7668 return TRUE;
7669}
7670
7671# if defined(FEAT_GUI) || defined(PROTO)
7672/*
7673 * Destroy the display, window and app_context. Required for GTK.
7674 */
7675 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007676clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007677{
7678 if (xterm_Shell != (Widget)0)
7679 {
7680 XtDestroyWidget(xterm_Shell);
7681 xterm_Shell = (Widget)0;
7682 }
7683 if (xterm_dpy != NULL)
7684 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007685# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007686 /* Lesstif and Solaris crash here, lose some memory */
7687 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007688# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007689 if (x11_display == xterm_dpy)
7690 x11_display = NULL;
7691 xterm_dpy = NULL;
7692 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007693# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007694 if (app_context != (XtAppContext)NULL)
7695 {
7696 /* Lesstif and Solaris crash here, lose some memory */
7697 XtDestroyApplicationContext(app_context);
7698 app_context = (XtAppContext)NULL;
7699 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007700# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007701}
7702# endif
7703
7704/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007705 * Catch up with GUI or X events.
7706 */
7707 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007708clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007709{
7710# ifdef FEAT_GUI
7711 if (gui.in_use)
7712 gui_mch_update();
7713 else
7714# endif
7715 if (xterm_Shell != (Widget)0)
7716 xterm_update();
7717}
7718
7719/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007720 * Catch up with any queued X events. This may put keyboard input into the
7721 * input buffer, call resize call-backs, trigger timers etc. If there is
7722 * nothing in the X event queue (& no timers pending), then we return
7723 * immediately.
7724 */
7725 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007726xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007727{
7728 XEvent event;
7729
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007730 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007731 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007732 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007733
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007734 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007735 break;
7736
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007737 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007738 {
7739 /* There is an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007740 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007741#ifdef FEAT_CLIENTSERVER
7742 {
7743 XPropertyEvent *e = (XPropertyEvent *)&event;
7744
7745 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007746 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007747 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007749#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007750 XtDispatchEvent(&event);
7751 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007752 else
7753 {
7754 /* There is something else than an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007755 XtAppProcessEvent(app_context, mask);
7756 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007757 }
7758}
7759
7760 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007761clip_xterm_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007762{
7763 if (xterm_Shell != (Widget)0)
7764 return clip_x11_own_selection(xterm_Shell, cbd);
7765 return FAIL;
7766}
7767
7768 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007769clip_xterm_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007770{
7771 if (xterm_Shell != (Widget)0)
7772 clip_x11_lose_selection(xterm_Shell, cbd);
7773}
7774
7775 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007776clip_xterm_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007777{
7778 if (xterm_Shell != (Widget)0)
7779 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7780}
7781
7782 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007783clip_xterm_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007784{
7785 clip_x11_set_selection(cbd);
7786}
7787#endif
7788
7789
7790#if defined(USE_XSMP) || defined(PROTO)
7791/*
7792 * Code for X Session Management Protocol.
7793 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007794
7795# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007796/*
7797 * This is our chance to ask the user if they want to save,
7798 * or abort the logout
7799 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007800 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007801xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007802{
7803 cmdmod_T save_cmdmod;
7804 int cancel_shutdown = False;
7805
7806 save_cmdmod = cmdmod;
7807 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007808 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007809 /* Mustn't logout */
7810 cancel_shutdown = True;
7811 cmdmod = save_cmdmod;
7812 setcursor(); /* position cursor */
7813 out_flush();
7814
7815 /* Done interaction */
7816 SmcInteractDone(smc_conn, cancel_shutdown);
7817
7818 /* Finish off
7819 * Only end save-yourself here if we're not cancelling shutdown;
7820 * we'll get a cancelled callback later in which we'll end it.
7821 * Hopefully get around glitchy SMs (like GNOME-1)
7822 */
7823 if (!cancel_shutdown)
7824 {
7825 xsmp.save_yourself = False;
7826 SmcSaveYourselfDone(smc_conn, True);
7827 }
7828}
7829# endif
7830
7831/*
7832 * Callback that starts save-yourself.
7833 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007834 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007835xsmp_handle_save_yourself(
7836 SmcConn smc_conn,
7837 SmPointer client_data UNUSED,
7838 int save_type UNUSED,
7839 Bool shutdown,
7840 int interact_style UNUSED,
7841 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007842{
7843 /* Handle already being in saveyourself */
7844 if (xsmp.save_yourself)
7845 SmcSaveYourselfDone(smc_conn, True);
7846 xsmp.save_yourself = True;
7847 xsmp.shutdown = shutdown;
7848
7849 /* First up, preserve all files */
7850 out_flush();
7851 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7852
7853 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007854 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855
7856# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7857 /* Now see if we can ask about unsaved files */
7858 if (shutdown && !fast && gui.in_use)
7859 /* Need to interact with user, but need SM's permission */
7860 SmcInteractRequest(smc_conn, SmDialogError,
7861 xsmp_handle_interaction, client_data);
7862 else
7863# endif
7864 {
7865 /* Can stop the cycle here */
7866 SmcSaveYourselfDone(smc_conn, True);
7867 xsmp.save_yourself = False;
7868 }
7869}
7870
7871
7872/*
7873 * Callback to warn us of imminent death.
7874 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007875 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007876xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007877{
7878 xsmp_close();
7879
7880 /* quit quickly leaving swapfiles for modified buffers behind */
7881 getout_preserve_modified(0);
7882}
7883
7884
7885/*
7886 * Callback to tell us that save-yourself has completed.
7887 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007888 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007889xsmp_save_complete(
7890 SmcConn smc_conn UNUSED,
7891 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007892{
7893 xsmp.save_yourself = False;
7894}
7895
7896
7897/*
7898 * Callback to tell us that an instigated shutdown was cancelled
7899 * (maybe even by us)
7900 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007901 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007902xsmp_shutdown_cancelled(
7903 SmcConn smc_conn,
7904 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007905{
7906 if (xsmp.save_yourself)
7907 SmcSaveYourselfDone(smc_conn, True);
7908 xsmp.save_yourself = False;
7909 xsmp.shutdown = False;
7910}
7911
7912
7913/*
7914 * Callback to tell us that a new ICE connection has been established.
7915 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007916 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007917xsmp_ice_connection(
7918 IceConn iceConn,
7919 IcePointer clientData UNUSED,
7920 Bool opening,
7921 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007922{
7923 /* Intercept creation of ICE connection fd */
7924 if (opening)
7925 {
7926 xsmp_icefd = IceConnectionNumber(iceConn);
7927 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7928 }
7929}
7930
7931
7932/* Handle any ICE processing that's required; return FAIL if SM lost */
7933 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007934xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007935{
7936 Bool rep;
7937
7938 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7939 == IceProcessMessagesIOError)
7940 {
7941 /* Lost ICE */
7942 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007943 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007944 xsmp_close();
7945 return FAIL;
7946 }
7947 else
7948 return OK;
7949}
7950
7951static int dummy;
7952
7953/* Set up X Session Management Protocol */
7954 void
7955xsmp_init(void)
7956{
7957 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007958 SmcCallbacks smcallbacks;
7959#if 0
7960 SmPropValue smname;
7961 SmProp smnameprop;
7962 SmProp *smprops[1];
7963#endif
7964
7965 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007966 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007967
7968 xsmp.save_yourself = xsmp.shutdown = False;
7969
7970 /* Set up SM callbacks - must have all, even if they're not used */
7971 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7972 smcallbacks.save_yourself.client_data = NULL;
7973 smcallbacks.die.callback = xsmp_die;
7974 smcallbacks.die.client_data = NULL;
7975 smcallbacks.save_complete.callback = xsmp_save_complete;
7976 smcallbacks.save_complete.client_data = NULL;
7977 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7978 smcallbacks.shutdown_cancelled.client_data = NULL;
7979
7980 /* Set up a watch on ICE connection creations. The "dummy" argument is
7981 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7982 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7983 {
7984 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007985 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007986 return;
7987 }
7988
7989 /* Create an SM connection */
7990 xsmp.smcconn = SmcOpenConnection(
7991 NULL,
7992 NULL,
7993 SmProtoMajor,
7994 SmProtoMinor,
7995 SmcSaveYourselfProcMask | SmcDieProcMask
7996 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7997 &smcallbacks,
7998 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007999 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008000 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008001 errorstring);
8002 if (xsmp.smcconn == NULL)
8003 {
8004 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00008005
Bram Moolenaar071d4272004-06-13 20:20:40 +00008006 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008007 {
8008 vim_snprintf(errorreport, sizeof(errorreport),
8009 _("XSMP SmcOpenConnection failed: %s"), errorstring);
8010 verb_msg((char_u *)errorreport);
8011 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008012 return;
8013 }
8014 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8015
8016#if 0
8017 /* ID ourselves */
8018 smname.value = "vim";
8019 smname.length = 3;
8020 smnameprop.name = "SmProgram";
8021 smnameprop.type = "SmARRAY8";
8022 smnameprop.num_vals = 1;
8023 smnameprop.vals = &smname;
8024
8025 smprops[0] = &smnameprop;
8026 SmcSetProperties(xsmp.smcconn, 1, smprops);
8027#endif
8028}
8029
8030
8031/* Shut down XSMP comms. */
8032 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008033xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008034{
8035 if (xsmp_icefd != -1)
8036 {
8037 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008038 if (xsmp.clientid != NULL)
8039 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008040 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008041 xsmp_icefd = -1;
8042 }
8043}
8044#endif /* USE_XSMP */
8045
8046
8047#ifdef EBCDIC
8048/* Translate character to its CTRL- value */
8049char CtrlTable[] =
8050{
8051/* 00 - 5E */
8052 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8053 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8054 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8055 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8056 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8057 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8058/* ^ */ 0x1E,
8059/* - */ 0x1F,
8060/* 61 - 6C */
8061 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8062/* _ */ 0x1F,
8063/* 6E - 80 */
8064 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8065/* a */ 0x01,
8066/* b */ 0x02,
8067/* c */ 0x03,
8068/* d */ 0x37,
8069/* e */ 0x2D,
8070/* f */ 0x2E,
8071/* g */ 0x2F,
8072/* h */ 0x16,
8073/* i */ 0x05,
8074/* 8A - 90 */
8075 0, 0, 0, 0, 0, 0, 0,
8076/* j */ 0x15,
8077/* k */ 0x0B,
8078/* l */ 0x0C,
8079/* m */ 0x0D,
8080/* n */ 0x0E,
8081/* o */ 0x0F,
8082/* p */ 0x10,
8083/* q */ 0x11,
8084/* r */ 0x12,
8085/* 9A - A1 */
8086 0, 0, 0, 0, 0, 0, 0, 0,
8087/* s */ 0x13,
8088/* t */ 0x3C,
8089/* u */ 0x3D,
8090/* v */ 0x32,
8091/* w */ 0x26,
8092/* x */ 0x18,
8093/* y */ 0x19,
8094/* z */ 0x3F,
8095/* AA - AC */
8096 0, 0, 0,
8097/* [ */ 0x27,
8098/* AE - BC */
8099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8100/* ] */ 0x1D,
8101/* BE - C0 */ 0, 0, 0,
8102/* A */ 0x01,
8103/* B */ 0x02,
8104/* C */ 0x03,
8105/* D */ 0x37,
8106/* E */ 0x2D,
8107/* F */ 0x2E,
8108/* G */ 0x2F,
8109/* H */ 0x16,
8110/* I */ 0x05,
8111/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8112/* J */ 0x15,
8113/* K */ 0x0B,
8114/* L */ 0x0C,
8115/* M */ 0x0D,
8116/* N */ 0x0E,
8117/* O */ 0x0F,
8118/* P */ 0x10,
8119/* Q */ 0x11,
8120/* R */ 0x12,
8121/* DA - DF */ 0, 0, 0, 0, 0, 0,
8122/* \ */ 0x1C,
8123/* E1 */ 0,
8124/* S */ 0x13,
8125/* T */ 0x3C,
8126/* U */ 0x3D,
8127/* V */ 0x32,
8128/* W */ 0x26,
8129/* X */ 0x18,
8130/* Y */ 0x19,
8131/* Z */ 0x3F,
8132/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8134};
8135
8136char MetaCharTable[]=
8137{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
8138 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8139 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8140 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8141 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8142};
8143
8144
8145/* TODO: Use characters NOT numbers!!! */
8146char CtrlCharTable[]=
8147{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
8148 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8149 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8150 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8151 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8152};
8153
8154
8155#endif