blob: b044df27f7044751c2243276311bc7766e3335d6 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
15 * Also for BeOS and Atari MiNT.
16 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
21/*
22 * Some systems have a prototype for select() that has (int *) instead of
23 * (fd_set *), which is wrong. This define removes that prototype. We define
24 * our own prototype below.
25 * Don't use it for the Mac, it causes a warning for precompiled headers.
26 * TODO: use a configure check for precompiled headers?
27 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000028#if !defined(__APPLE__) && !defined(__TANDEM)
Bram Moolenaar071d4272004-06-13 20:20:40 +000029# define select select_declared_wrong
30#endif
31
32#include "vim.h"
33
Bram Moolenaar325b7a22004-07-05 15:58:32 +000034#ifdef FEAT_MZSCHEME
35# include "if_mzsch.h"
36#endif
37
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#include "os_unixx.h" /* unix includes for os_unix.c only */
39
40#ifdef USE_XSMP
41# include <X11/SM/SMlib.h>
42#endif
43
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000044#ifdef HAVE_SELINUX
45# include <selinux/selinux.h>
46static int selinux_enabled = -1;
47#endif
48
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020049#ifdef HAVE_SMACK
50# include <attr/xattr.h>
51# include <linux/xattr.h>
52# ifndef SMACK_LABEL_LEN
53# define SMACK_LABEL_LEN 1024
54# endif
55#endif
56
Bram Moolenaar071d4272004-06-13 20:20:40 +000057/*
58 * Use this prototype for select, some include files have a wrong prototype
59 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000060#ifndef __TANDEM
61# undef select
62# ifdef __BEOS__
63# define select beos_select
64# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#endif
66
Bram Moolenaara2442432007-04-26 14:26:37 +000067#ifdef __CYGWIN__
68# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000069# include <cygwin/version.h>
70# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
71 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010072# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
73# define WIN32_LEAN_AND_MEAN
74# include <windows.h>
75# include "winclip.pro"
76# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000077# endif
78#endif
79
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#if defined(HAVE_SELECT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010081extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
Bram Moolenaar071d4272004-06-13 20:20:40 +000082#endif
83
84#ifdef FEAT_MOUSE_GPM
85# include <gpm.h>
86/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
87 * I just copied relevant defines here. A cleaner solution would be to put gpm
88 * code into separate file and include there linux/keyboard.h
89 */
90/* #include <linux/keyboard.h> */
91# define KG_SHIFT 0
92# define KG_CTRL 2
93# define KG_ALT 3
94# define KG_ALTGR 1
95# define KG_SHIFTL 4
96# define KG_SHIFTR 5
97# define KG_CTRLL 6
98# define KG_CTRLR 7
99# define KG_CAPSSHIFT 8
100
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100101static void gpm_close(void);
102static int gpm_open(void);
103static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104#endif
105
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000106#ifdef FEAT_SYSMOUSE
107# include <sys/consio.h>
108# include <sys/fbio.h>
109
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100110static int sysmouse_open(void);
111static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +0100112static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000113#endif
114
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115/*
116 * end of autoconf section. To be extended...
117 */
118
119/* Are the following #ifdefs still required? And why? Is that for X11? */
120
121#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
122# ifdef SIGWINCH
123# undef SIGWINCH
124# endif
125# ifdef TIOCGWINSZ
126# undef TIOCGWINSZ
127# endif
128#endif
129
130#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
131# define SIGWINCH SIGWINDOW
132#endif
133
134#ifdef FEAT_X11
135# include <X11/Xlib.h>
136# include <X11/Xutil.h>
137# include <X11/Xatom.h>
138# ifdef FEAT_XCLIPBOARD
139# include <X11/Intrinsic.h>
140# include <X11/Shell.h>
141# include <X11/StringDefs.h>
142static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void clip_update(void);
144static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145# endif
146
147# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
148Window x11_window = 0;
149# endif
150Display *x11_display = NULL;
151
152# ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100153static int get_x11_windis(void);
154static void set_x11_title(char_u *);
155static void set_x11_icon(char_u *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156# endif
157#endif
158
159#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100160static int get_x11_title(int);
161static int get_x11_icon(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162
163static char_u *oldtitle = NULL;
Bram Moolenaard8f0cef2018-08-19 22:20:16 +0200164static volatile int oldtitle_outdated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165static int did_set_title = FALSE;
166static char_u *oldicon = NULL;
167static int did_set_icon = FALSE;
168#endif
169
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100170static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaar205b8862011-09-07 15:04:31 +0200172#ifdef HAVE_UNION_WAIT
173typedef union wait waitstatus;
174#else
175typedef int waitstatus;
176#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100177static pid_t wait4pid(pid_t, waitstatus *);
Bram Moolenaar205b8862011-09-07 15:04:31 +0200178
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200179static int WaitForChar(long msec, int *interrupted, int ignore_input);
180static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100181#if defined(__BEOS__) || defined(VMS)
Bram Moolenaarcda77642016-06-04 13:32:35 +0200182int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200184static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185#endif
186
187#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100188static int do_xterm_trace(void);
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000189# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190#endif
191
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100192static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000193
194#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100195static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196#endif
197#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100198static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199#endif
200#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100201static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202#endif
203#if defined(SIGALRM) && defined(FEAT_X11) \
204 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
205# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100206static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000207/* volatile because it is used in signal handler sig_alarm(). */
208static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100210static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100212static void catch_int_signal(void);
213static void set_signals(void);
214static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200215#ifdef HAVE_SIGPROCMASK
216# define SIGSET_DECL(set) sigset_t set;
217# define BLOCK_SIGNALS(set) block_signals(set)
218# define UNBLOCK_SIGNALS(set) unblock_signals(set)
219#else
220# define SIGSET_DECL(set)
221# define BLOCK_SIGNALS(set) do { /**/ } while (0)
222# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
223#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100224static int have_wildcard(int, char_u **);
225static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100227static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228
229#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000230# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231#endif
232
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000233/* volatile because it is used in signal handler sig_winch(). */
234static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235static char_u *extra_shell_arg = NULL;
236static int show_shell_mess = TRUE;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000237/* volatile because it is used in signal handler deathtrap(). */
238static volatile int deadly_signal = 0; /* The signal we caught */
239/* volatile because it is used in signal handler deathtrap(). */
240static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100242#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
243static int dont_check_job_ended = 0;
244#endif
245
Bram Moolenaar071d4272004-06-13 20:20:40 +0000246static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
247
248#ifdef USE_XSMP
249typedef struct
250{
251 SmcConn smcconn; /* The SM connection ID */
252 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200253 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 Bool save_yourself; /* If we're in the middle of a save_yourself */
255 Bool shutdown; /* If we're in shutdown mode */
256} xsmp_config_T;
257
258static xsmp_config_T xsmp;
259#endif
260
261#ifdef SYS_SIGLIST_DECLARED
262/*
263 * I have seen
264 * extern char *_sys_siglist[NSIG];
265 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
266 * that describe the signals. That is nearly what we want here. But
267 * autoconf does only check for sys_siglist (without the underscore), I
268 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100269 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270 */
271#endif
272
273static struct signalinfo
274{
275 int sig; /* Signal number, eg. SIGSEGV etc */
276 char *name; /* Signal name (not char_u!). */
277 char deadly; /* Catch as a deadly signal? */
278} signal_info[] =
279{
280#ifdef SIGHUP
281 {SIGHUP, "HUP", TRUE},
282#endif
283#ifdef SIGQUIT
284 {SIGQUIT, "QUIT", TRUE},
285#endif
286#ifdef SIGILL
287 {SIGILL, "ILL", TRUE},
288#endif
289#ifdef SIGTRAP
290 {SIGTRAP, "TRAP", TRUE},
291#endif
292#ifdef SIGABRT
293 {SIGABRT, "ABRT", TRUE},
294#endif
295#ifdef SIGEMT
296 {SIGEMT, "EMT", TRUE},
297#endif
298#ifdef SIGFPE
299 {SIGFPE, "FPE", TRUE},
300#endif
301#ifdef SIGBUS
302 {SIGBUS, "BUS", TRUE},
303#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100304#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
305 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 {SIGSEGV, "SEGV", TRUE},
307#endif
308#ifdef SIGSYS
309 {SIGSYS, "SYS", TRUE},
310#endif
311#ifdef SIGALRM
312 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
313#endif
314#ifdef SIGTERM
315 {SIGTERM, "TERM", TRUE},
316#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100317#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318 {SIGVTALRM, "VTALRM", TRUE},
319#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000320#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
321 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
322 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323 {SIGPROF, "PROF", TRUE},
324#endif
325#ifdef SIGXCPU
326 {SIGXCPU, "XCPU", TRUE},
327#endif
328#ifdef SIGXFSZ
329 {SIGXFSZ, "XFSZ", TRUE},
330#endif
331#ifdef SIGUSR1
332 {SIGUSR1, "USR1", TRUE},
333#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000334#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
335 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336 {SIGUSR2, "USR2", TRUE},
337#endif
338#ifdef SIGINT
339 {SIGINT, "INT", FALSE},
340#endif
341#ifdef SIGWINCH
342 {SIGWINCH, "WINCH", FALSE},
343#endif
344#ifdef SIGTSTP
345 {SIGTSTP, "TSTP", FALSE},
346#endif
347#ifdef SIGPIPE
348 {SIGPIPE, "PIPE", FALSE},
349#endif
350 {-1, "Unknown!", FALSE}
351};
352
Bram Moolenaar25724922009-07-14 15:38:41 +0000353 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100354mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000355{
356 if (p_verbose >= 5)
357 {
358 verbose_enter();
359 smsg((char_u *)"chdir(%s)", path);
360 verbose_leave();
361 }
362# ifdef VMS
363 return chdir(vms_fixfilename(path));
364# else
365 return chdir(path);
366# endif
367}
368
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200369/* Why is NeXT excluded here (and not in os_unixx.h)? */
370#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
371# define NEW_TTY_SYSTEM
372#endif
373
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000374/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100375 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000376 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100378mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000380 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381 if (p_wd) /* Unix is too fast, slow down a bit more */
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100382 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383}
384
385/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000386 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 * Get a characters from the keyboard.
388 * Return the number of characters that are available.
389 * If wtime == 0 do not wait for characters.
390 * If wtime == n wait a short time for characters.
391 * If wtime == -1 wait forever for characters.
392 */
393 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100394mch_inchar(
395 char_u *buf,
396 int maxlen,
397 long wtime, /* don't use "time", MIPS cannot handle it */
398 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399{
400 int len;
Bram Moolenaarcda77642016-06-04 13:32:35 +0200401 int interrupted = FALSE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200402 int did_start_blocking = FALSE;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200403 long wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200404 long elapsed_time = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100405#ifdef ELAPSED_FUNC
406 ELAPSED_TYPE start_tv;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200407
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100408 ELAPSED_INIT(start_tv);
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200409#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200411 /* repeat until we got a character or waited long enough */
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200412 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200414 /* Check if window changed size while we were busy, perhaps the ":set
415 * columns=99" command was used. */
416 while (do_resize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200418
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200419#ifdef MESSAGE_QUEUE
420 parse_queued_messages();
Bram Moolenaard85f2712017-07-28 21:51:57 +0200421 /* If input was put directly in typeahead buffer bail out here. */
422 if (typebuf_changed(tb_change_cnt))
423 return 0;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200424#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200425 if (wtime < 0 && did_start_blocking)
426 /* blocking and already waited for p_ut */
427 wait_time = -1;
428 else
429 {
430 if (wtime >= 0)
431 wait_time = wtime;
432 else
433 /* going to block after p_ut */
434 wait_time = p_ut;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +0100435#ifdef ELAPSED_FUNC
436 elapsed_time = ELAPSED_FUNC(start_tv);
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200437#endif
438 wait_time -= elapsed_time;
439 if (wait_time < 0)
440 {
441 if (wtime >= 0)
442 /* no character available within "wtime" */
443 return 0;
444
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200445 else
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200446 {
447 /* no character available within 'updatetime' */
448 did_start_blocking = TRUE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200449 if (trigger_cursorhold() && maxlen >= 3
450 && !typebuf_changed(tb_change_cnt))
451 {
452 buf[0] = K_SPECIAL;
453 buf[1] = KS_EXTRA;
454 buf[2] = (int)KE_CURSORHOLD;
455 return 3;
456 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200457 /*
458 * If there is no character available within 'updatetime'
459 * seconds flush all the swap files to disk.
460 * Also done when interrupted by SIGWINCH.
461 */
462 before_blocking();
463 continue;
464 }
465 }
466 }
467
468#ifdef FEAT_JOB_CHANNEL
469 /* Checking if a job ended requires polling. Do this every 100 msec. */
470 if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
471 wait_time = 100L;
Bram Moolenaar8a8199e2016-11-26 15:13:33 +0100472 /* If there is readahead then parse_queued_messages() timed out and we
473 * should call it again soon. */
474 if ((wait_time < 0 || wait_time > 100L) && channel_any_readahead())
475 wait_time = 10L;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200476#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100477#ifdef FEAT_BEVAL_GUI
Bram Moolenaar59716a22017-03-01 20:32:44 +0100478 if (p_beval && wait_time > 100L)
479 /* The 'balloonexpr' may indirectly invoke a callback while waiting
480 * for a character, need to check often. */
481 wait_time = 100L;
482#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200483
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200485 * We want to be interrupted by the winch signal
486 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000487 */
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200488 if (WaitForChar(wait_time, &interrupted, FALSE))
Bram Moolenaar67c53842010-05-22 18:28:27 +0200489 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200490 /* If input was put directly in typeahead buffer bail out here. */
491 if (typebuf_changed(tb_change_cnt))
492 return 0;
493
494 /*
495 * For some terminals we only get one character at a time.
496 * We want the get all available characters, so we could keep on
497 * trying until none is available
498 * For some other terminals this is quite slow, that's why we don't
499 * do it.
500 */
501 len = read_from_input_buf(buf, (long)maxlen);
502 if (len > 0)
503 return len;
504 continue;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200505 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200507 /* no character available */
508#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
509 /* estimate the elapsed time */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +0100510 elapsed_time += wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200511#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200513 if (do_resize /* interrupted by SIGWINCH signal */
514#ifdef FEAT_CLIENTSERVER
515 || server_waiting()
516#endif
517#ifdef MESSAGE_QUEUE
518 || interrupted
519#endif
520 || wait_time > 0
Bram Moolenaar1572e302017-03-25 20:16:28 +0100521 || (wtime < 0 && !did_start_blocking))
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200522 continue;
523
524 /* no character available or interrupted */
525 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200527 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528}
529
530 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100531handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532{
533 do_resize = FALSE;
534 shell_resized();
535}
536
537/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200538 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539 */
540 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100541mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200543 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544}
545
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200546#if defined(FEAT_TERMINAL) || defined(PROTO)
547/*
548 * Check for any pending input or messages.
549 */
550 int
551mch_check_messages(void)
552{
553 return WaitForChar(0L, NULL, TRUE);
554}
555#endif
556
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
558# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000559# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560# endif
561# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
562# include <sys/sysctl.h>
563# endif
564# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
565# include <sys/sysinfo.h>
566# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100567# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100568# include <mach/mach_host.h>
569# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100570# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571
572/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000573 * Return total amount of memory available in Kbyte.
574 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100577mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000580 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581
Bram Moolenaar362dc332018-03-05 21:59:37 +0100582# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100583 {
584 /* Mac (Darwin) way of getting the amount of RAM available */
585 mach_port_t host = mach_host_self();
586 kern_return_t kret;
587# ifdef HOST_VM_INFO64
588 struct vm_statistics64 vm_stat;
589 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590
Bram Moolenaar988615f2018-02-27 17:58:20 +0100591 kret = host_statistics64(host, HOST_VM_INFO64,
592 (host_info64_t)&vm_stat, &count);
593# else
594 struct vm_statistics vm_stat;
595 natural_t count = HOST_VM_INFO_COUNT;
596
597 kret = host_statistics(host, HOST_VM_INFO,
598 (host_info_t)&vm_stat, &count);
599# endif
600 if (kret == KERN_SUCCESS)
601 /* get the amount of user memory by summing each usage */
602 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
603 + vm_stat.inactive_count
604# ifdef MAC_OS_X_VERSION_10_9
605 + vm_stat.compressor_page_count
606# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100607 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100608 mach_port_deallocate(mach_task_self(), host);
609 }
610# endif
611
612# ifdef HAVE_SYSCTL
613 if (mem == 0)
614 {
615 /* BSD way of getting the amount of RAM available. */
616 int mib[2];
617 size_t len = sizeof(long_u);
618# ifdef HW_USERMEM64
619 long_u physmem;
620# else
621 /* sysctl() may return 32 bit or 64 bit, accept both */
622 union {
623 int_u u32;
624 long_u u64;
625 } physmem;
626# endif
627
628 mib[0] = CTL_HW;
629# ifdef HW_USERMEM64
630 mib[1] = HW_USERMEM64;
631# else
632 mib[1] = HW_USERMEM;
633# endif
634 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
635 {
636# ifdef HW_USERMEM64
637 mem = (long_u)physmem;
638# else
639 if (len == sizeof(physmem.u64))
640 mem = (long_u)physmem.u64;
641 else
642 mem = (long_u)physmem.u32;
643# endif
644 }
645 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200646# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200648# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 if (mem == 0)
650 {
651 struct sysinfo sinfo;
652
653 /* Linux way of getting amount of RAM available */
654 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000655 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200656# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar914572a2007-05-01 11:37:47 +0000657 /* avoid overflow as much as possible */
658 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
659 {
660 sinfo.mem_unit = sinfo.mem_unit >> 1;
661 --shiftright;
662 }
663 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200664# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200666# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000667 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200669# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200671# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 if (mem == 0)
673 {
674 long pagesize, pagecount;
675
676 /* Solaris way of getting amount of RAM available */
677 pagesize = sysconf(_SC_PAGESIZE);
678 pagecount = sysconf(_SC_PHYS_PAGES);
679 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000680 {
681 /* avoid overflow as much as possible */
682 while (shiftright > 0 && (pagesize & 1) == 0)
683 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000684 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000685 --shiftright;
686 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200690# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691
692 /* Return the minimum of the physical memory and the user limit, because
693 * using more than the user limit may cause Vim to be terminated. */
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200694# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695 {
696 struct rlimit rlp;
697
698 if (getrlimit(RLIMIT_DATA, &rlp) == 0
699 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200700# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200702# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000703 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000705 {
706 mem = (long_u)rlp.rlim_cur;
707 shiftright = 10;
708 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200710# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711
712 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000713 return mem >> shiftright;
714 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715}
716#endif
717
718 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100719mch_delay(long msec, int ignoreinput)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720{
721 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000722#ifdef FEAT_MZSCHEME
723 long total = msec; /* remember original value */
724#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725
726 if (ignoreinput)
727 {
728 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000729 * here. But we don't want QUIT to kill us (CTRL-\ used in a
730 * shell may produce SIGQUIT). */
731 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732 old_tmode = curr_tmode;
733 if (curr_tmode == TMODE_RAW)
734 settmode(TMODE_SLEEP);
735
736 /*
737 * Everybody sleeps in a different way...
738 * Prefer nanosleep(), some versions of usleep() can only sleep up to
739 * one second.
740 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000741#ifdef FEAT_MZSCHEME
742 do
743 {
744 /* if total is large enough, wait by portions in p_mzq */
745 if (total > p_mzq)
746 msec = p_mzq;
747 else
748 msec = total;
749 total -= msec;
750#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751#ifdef HAVE_NANOSLEEP
752 {
753 struct timespec ts;
754
755 ts.tv_sec = msec / 1000;
756 ts.tv_nsec = (msec % 1000) * 1000000;
757 (void)nanosleep(&ts, NULL);
758 }
759#else
760# ifdef HAVE_USLEEP
761 while (msec >= 1000)
762 {
763 usleep((unsigned int)(999 * 1000));
764 msec -= 999;
765 }
766 usleep((unsigned int)(msec * 1000));
767# else
768# ifndef HAVE_SELECT
769 poll(NULL, 0, (int)msec);
770# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 {
772 struct timeval tv;
773
774 tv.tv_sec = msec / 1000;
775 tv.tv_usec = (msec % 1000) * 1000;
776 /*
777 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
778 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
779 */
780 select(0, NULL, NULL, NULL, &tv);
781 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782# endif /* HAVE_SELECT */
783# endif /* HAVE_NANOSLEEP */
784#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000785#ifdef FEAT_MZSCHEME
786 }
787 while (total > 0);
788#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789
790 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000791 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 }
793 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200794 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795}
796
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000797#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
799# define HAVE_CHECK_STACK_GROWTH
800/*
801 * Support for checking for an almost-out-of-stack-space situation.
802 */
803
804/*
805 * Return a pointer to an item on the stack. Used to find out if the stack
806 * grows up or down.
807 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100808static void check_stack_growth(char *p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809static int stack_grows_downwards;
810
811/*
812 * Find out if the stack grows upwards or downwards.
813 * "p" points to a variable on the stack of the caller.
814 */
815 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100816check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817{
818 int i;
819
820 stack_grows_downwards = (p > (char *)&i);
821}
822#endif
823
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000824#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825static char *stack_limit = NULL;
826
827#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
828# include <pthread.h>
829# include <pthread_np.h>
830#endif
831
832/*
833 * Find out until how var the stack can grow without getting into trouble.
834 * Called when starting up and when switching to the signal stack in
835 * deathtrap().
836 */
837 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100838get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839{
840 struct rlimit rlp;
841 int i;
842 long lim;
843
844 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
845 * limit doesn't fit in a long (rlim_cur might be "long long"). */
846 if (getrlimit(RLIMIT_STACK, &rlp) == 0
847 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
848# ifdef RLIM_INFINITY
849 && rlp.rlim_cur != RLIM_INFINITY
850# endif
851 )
852 {
853 lim = (long)rlp.rlim_cur;
854#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
855 {
856 pthread_attr_t attr;
857 size_t size;
858
859 /* On FreeBSD the initial thread always has a fixed stack size, no
860 * matter what the limits are set to. Normally it's 1 Mbyte. */
861 pthread_attr_init(&attr);
862 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
863 {
864 pthread_attr_getstacksize(&attr, &size);
865 if (lim > (long)size)
866 lim = (long)size;
867 }
868 pthread_attr_destroy(&attr);
869 }
870#endif
871 if (stack_grows_downwards)
872 {
873 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
874 if (stack_limit >= (char *)&i)
875 /* overflow, set to 1/16 of current stack position */
876 stack_limit = (char *)((long)&i / 16L);
877 }
878 else
879 {
880 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
881 if (stack_limit <= (char *)&i)
882 stack_limit = NULL; /* overflow */
883 }
884 }
885}
886
887/*
888 * Return FAIL when running out of stack space.
889 * "p" must point to any variable local to the caller that's on the stack.
890 */
891 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100892mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893{
894 if (stack_limit != NULL)
895 {
896 if (stack_grows_downwards)
897 {
898 if (p < stack_limit)
899 return FAIL;
900 }
901 else if (p > stack_limit)
902 return FAIL;
903 }
904 return OK;
905}
906#endif
907
908#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
909/*
910 * Support for using the signal stack.
911 * This helps when we run out of stack space, which causes a SIGSEGV. The
912 * signal handler then must run on another stack, since the normal stack is
913 * completely full.
914 */
915
916#ifndef SIGSTKSZ
917# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
918#endif
919
920# ifdef HAVE_SIGALTSTACK
921static stack_t sigstk; /* for sigaltstack() */
922# else
923static struct sigstack sigstk; /* for sigstack() */
924# endif
925
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100926static void init_signal_stack(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927static char *signal_stack;
928
929 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100930init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931{
932 if (signal_stack != NULL)
933 {
934# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935# ifdef HAVE_SS_BASE
936 sigstk.ss_base = signal_stack;
937# else
938 sigstk.ss_sp = signal_stack;
939# endif
940 sigstk.ss_size = SIGSTKSZ;
941 sigstk.ss_flags = 0;
942 (void)sigaltstack(&sigstk, NULL);
943# else
944 sigstk.ss_sp = signal_stack;
945 if (stack_grows_downwards)
946 sigstk.ss_sp += SIGSTKSZ - 1;
947 sigstk.ss_onstack = 0;
948 (void)sigstack(&sigstk, NULL);
949# endif
950 }
951}
952#endif
953
954/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000955 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 * will barf when the second argument to signal() is ``wrong''.
957 * Let me try it with a few tricky defines from my own osdef.h (jw).
958 */
959#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 static RETSIGTYPE
961sig_winch SIGDEFARG(sigarg)
962{
963 /* this is not required on all systems, but it doesn't hurt anybody */
964 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
965 do_resize = TRUE;
966 SIGRETURN;
967}
968#endif
969
970#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 static RETSIGTYPE
972catch_sigint SIGDEFARG(sigarg)
973{
974 /* this is not required on all systems, but it doesn't hurt anybody */
975 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
976 got_int = TRUE;
977 SIGRETURN;
978}
979#endif
980
981#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982 static RETSIGTYPE
983catch_sigpwr SIGDEFARG(sigarg)
984{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000985 /* this is not required on all systems, but it doesn't hurt anybody */
986 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 /*
988 * I'm not sure we get the SIGPWR signal when the system is really going
989 * down or when the batteries are almost empty. Just preserve the swap
990 * files and don't exit, that can't do any harm.
991 */
992 ml_sync_all(FALSE, FALSE);
993 SIGRETURN;
994}
995#endif
996
997#ifdef SET_SIG_ALARM
998/*
999 * signal function for alarm().
1000 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 static RETSIGTYPE
1002sig_alarm SIGDEFARG(sigarg)
1003{
1004 /* doesn't do anything, just to break a system call */
1005 sig_alarm_called = TRUE;
1006 SIGRETURN;
1007}
1008#endif
1009
Bram Moolenaar44ecf652005-03-07 23:09:59 +00001010#if (defined(HAVE_SETJMP_H) \
1011 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
1012 || defined(FEAT_LIBCALL))) \
1013 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014/*
1015 * A simplistic version of setjmp() that only allows one level of using.
1016 * Don't call twice before calling mch_endjmp()!.
1017 * Usage:
1018 * mch_startjmp();
1019 * if (SETJMP(lc_jump_env) != 0)
1020 * {
1021 * mch_didjmp();
1022 * EMSG("crash!");
1023 * }
1024 * else
1025 * {
1026 * do_the_work;
1027 * mch_endjmp();
1028 * }
1029 * Note: Can't move SETJMP() here, because a function calling setjmp() must
1030 * not return before the saved environment is used.
1031 * Returns OK for normal return, FAIL when the protected code caused a
1032 * problem and LONGJMP() was used.
1033 */
1034 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001035mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036{
1037#ifdef SIGHASARG
1038 lc_signal = 0;
1039#endif
1040 lc_active = TRUE;
1041}
1042
1043 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001044mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045{
1046 lc_active = FALSE;
1047}
1048
1049 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001050mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051{
1052# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
1053 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
1054 * otherwise catching the signal only works once. */
1055 init_signal_stack();
1056# endif
1057}
1058#endif
1059
1060/*
1061 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001062 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001064 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1065 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 */
1067 static RETSIGTYPE
1068deathtrap SIGDEFARG(sigarg)
1069{
1070 static int entered = 0; /* count the number of times we got here.
1071 Note: when memory has been corrupted
1072 this may get an arbitrary value! */
1073#ifdef SIGHASARG
1074 int i;
1075#endif
1076
1077#if defined(HAVE_SETJMP_H)
1078 /*
1079 * Catch a crash in protected code.
1080 * Restores the environment saved in lc_jump_env, which looks like
1081 * SETJMP() returns 1.
1082 */
1083 if (lc_active)
1084 {
1085# if defined(SIGHASARG)
1086 lc_signal = sigarg;
1087# endif
1088 lc_active = FALSE; /* don't jump again */
1089 LONGJMP(lc_jump_env, 1);
1090 /* NOTREACHED */
1091 }
1092#endif
1093
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001094#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001095# ifdef SIGQUIT
1096 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
1097 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1098 * pressing CTRL-\, but we don't want Vim to exit then. */
1099 if (in_mch_delay && sigarg == SIGQUIT)
1100 SIGRETURN;
1101# endif
1102
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001103 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1104 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1105 * free(). Calling free() again may then cause a crash. */
1106 if (entered == 0
1107 && (0
1108# ifdef SIGHUP
1109 || sigarg == SIGHUP
1110# endif
1111# ifdef SIGQUIT
1112 || sigarg == SIGQUIT
1113# endif
1114# ifdef SIGTERM
1115 || sigarg == SIGTERM
1116# endif
1117# ifdef SIGPWR
1118 || sigarg == SIGPWR
1119# endif
1120# ifdef SIGUSR1
1121 || sigarg == SIGUSR1
1122# endif
1123# ifdef SIGUSR2
1124 || sigarg == SIGUSR2
1125# endif
1126 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001127 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001128 SIGRETURN;
1129#endif
1130
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 /* Remember how often we have been called. */
1132 ++entered;
1133
Bram Moolenaare429e702016-06-10 19:49:14 +02001134 /* Executing autocommands is likely to use more stack space than we have
1135 * available in the signal stack. */
1136 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001137
Bram Moolenaar071d4272004-06-13 20:20:40 +00001138#ifdef FEAT_EVAL
1139 /* Set the v:dying variable. */
1140 set_vim_var_nr(VV_DYING, (long)entered);
1141#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001142 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001144#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145 /* Since we are now using the signal stack, need to reset the stack
1146 * limit. Otherwise using a regexp will fail. */
1147 get_stack_limit();
1148#endif
1149
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001150#if 0
1151 /* This is for opening gdb the moment Vim crashes.
1152 * You need to manually adjust the file name and Vim executable name.
1153 * Suggested by SungHyun Nam. */
1154 {
1155# define VI_GDB_FILE "/tmp/vimgdb"
1156# define VIM_NAME "/usr/bin/vim"
1157 FILE *fp = fopen(VI_GDB_FILE, "w");
1158 if (fp)
1159 {
1160 fprintf(fp,
1161 "file %s\n"
1162 "attach %d\n"
1163 "set height 1000\n"
1164 "bt full\n"
1165 , VIM_NAME, getpid());
1166 fclose(fp);
1167 system("xterm -e gdb -x "VI_GDB_FILE);
1168 unlink(VI_GDB_FILE);
1169 }
1170 }
1171#endif
1172
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173#ifdef SIGHASARG
1174 /* try to find the name of this signal */
1175 for (i = 0; signal_info[i].sig != -1; i++)
1176 if (sigarg == signal_info[i].sig)
1177 break;
1178 deadly_signal = sigarg;
1179#endif
1180
1181 full_screen = FALSE; /* don't write message to the GUI, it might be
1182 * part of the problem... */
1183 /*
1184 * If something goes wrong after entering here, we may get here again.
1185 * When this happens, give a message and try to exit nicely (resetting the
1186 * terminal mode, etc.)
1187 * When this happens twice, just exit, don't even try to give a message,
1188 * stack may be corrupt or something weird.
1189 * When this still happens again (or memory was corrupted in such a way
1190 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1191 */
1192 if (entered >= 3)
1193 {
1194 reset_signals(); /* don't catch any signals anymore */
1195 may_core_dump();
1196 if (entered >= 4)
1197 _exit(8);
1198 exit(7);
1199 }
1200 if (entered == 2)
1201 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001202 /* No translation, it may call malloc(). */
1203 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 out_flush();
1205 getout(1);
1206 }
1207
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001208 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001210 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211 signal_info[i].name);
1212#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001213 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001215
1216 /* Preserve files and exit. This sets the really_exiting flag to prevent
1217 * calling free(). */
1218 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219
Bram Moolenaare429e702016-06-10 19:49:14 +02001220 /* NOTREACHED */
1221
Bram Moolenaar009b2592004-10-24 19:18:58 +00001222#ifdef NBDEBUG
1223 reset_signals();
1224 may_core_dump();
1225 abort();
1226#endif
1227
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228 SIGRETURN;
1229}
1230
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001231 static void
1232after_sigcont(void)
1233{
1234# ifdef FEAT_TITLE
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02001235 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1236 // again later.
1237 oldtitle_outdated = TRUE;
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001238# endif
1239 settmode(TMODE_RAW);
1240 need_check_timestamps = TRUE;
1241 did_check_timestamps = FALSE;
1242}
1243
1244#if defined(SIGCONT)
1245static RETSIGTYPE sigcont_handler SIGPROTOARG;
1246static int in_mch_suspend = FALSE;
1247
1248# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249/*
1250 * On Solaris with multi-threading, suspending might not work immediately.
1251 * Catch the SIGCONT signal, which will be used as an indication whether the
1252 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001253 *
1254 * On Linux, signal is not always handled immediately either.
1255 * See https://bugs.launchpad.net/bugs/291373
1256 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001257 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001259static volatile int sigcont_received;
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001260# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261
1262/*
1263 * signal handler for SIGCONT
1264 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 static RETSIGTYPE
1266sigcont_handler SIGDEFARG(sigarg)
1267{
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001268 if (in_mch_suspend)
1269 {
1270# if defined(_REENTRANT) && defined(SIGCONT)
1271 sigcont_received = TRUE;
1272# endif
1273 }
1274 else
1275 {
1276 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1277 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1278 // back to a sane mode and redraw.
1279 after_sigcont();
1280
1281 update_screen(CLEAR);
1282 if (State & CMDLINE)
1283 redrawcmdline();
1284 else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
1285 || State == EXTERNCMD || State == CONFIRM || exmode_active)
1286 repeat_message();
1287 else if (redrawing())
1288 setcursor();
1289#if defined(FEAT_INS_EXPAND)
1290 if (pum_visible())
1291 {
1292 redraw_later(NOT_VALID);
1293 ins_compl_show_pum();
1294 }
1295#endif
1296 cursor_on_force();
1297 out_flush();
1298 }
1299
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 SIGRETURN;
1301}
1302#endif
1303
Bram Moolenaar62b42182010-09-21 22:09:37 +02001304# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001305static void loose_clipboard(void);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001306# ifdef USE_SYSTEM
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001307static void save_clipboard(void);
1308static void restore_clipboard(void);
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001309
1310static void *clip_star_save = NULL;
1311static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001312# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001313
1314/*
1315 * Called when Vim is going to sleep or execute a shell command.
1316 * We can't respond to requests for the X selections. Lose them, otherwise
1317 * other applications will hang. But first copy the text to cut buffer 0.
1318 */
1319 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001320loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001321{
1322 if (clip_star.owned || clip_plus.owned)
1323 {
1324 x11_export_final_selection();
1325 if (clip_star.owned)
1326 clip_lose_selection(&clip_star);
1327 if (clip_plus.owned)
1328 clip_lose_selection(&clip_plus);
1329 if (x11_display != NULL)
1330 XFlush(x11_display);
1331 }
1332}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001333
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001334# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001335/*
1336 * Save clipboard text to restore later.
1337 */
1338 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001339save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001340{
1341 if (clip_star.owned)
1342 clip_star_save = get_register('*', TRUE);
1343 if (clip_plus.owned)
1344 clip_plus_save = get_register('+', TRUE);
1345}
1346
1347/*
1348 * Restore clipboard text if no one own the X selection.
1349 */
1350 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001351restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001352{
1353 if (clip_star_save != NULL)
1354 {
1355 if (!clip_gen_owner_exists(&clip_star))
1356 put_register('*', clip_star_save);
1357 else
1358 free_register(clip_star_save);
1359 clip_star_save = NULL;
1360 }
1361 if (clip_plus_save != NULL)
1362 {
1363 if (!clip_gen_owner_exists(&clip_plus))
1364 put_register('+', clip_plus_save);
1365 else
1366 free_register(clip_plus_save);
1367 clip_plus_save = NULL;
1368 }
1369}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001370# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001371#endif
1372
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373/*
1374 * If the machine has job control, use it to suspend the program,
1375 * otherwise fake it by starting a new shell.
1376 */
1377 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001378mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379{
1380 /* BeOS does have SIGTSTP, but it doesn't work. */
1381#if defined(SIGTSTP) && !defined(__BEOS__)
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001382 in_mch_suspend = TRUE;
1383
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 out_flush(); /* needed to make cursor visible on some systems */
1385 settmode(TMODE_COOK);
1386 out_flush(); /* needed to disable mouse on some systems */
1387
1388# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001389 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390# endif
1391
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001392# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001393 sigcont_received = FALSE;
1394# endif
1395 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001396# if defined(_REENTRANT) && defined(SIGCONT)
1397 /*
1398 * Wait for the SIGCONT signal to be handled. It generally happens
1399 * immediately, but somehow not all the time. Do not call pause()
1400 * because there would be race condition which would hang Vim if
1401 * signal happened in between the test of sigcont_received and the
1402 * call to pause(). If signal is not yet received, call sleep(0)
1403 * to just yield CPU. Signal should then be received. If somehow
1404 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1405 * further if signal is not received after 1+2+3+4 ms (not expected
1406 * to happen).
1407 */
1408 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001409 long wait_time;
1410 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001411 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001412 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001413 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414# endif
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001415 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001417 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418#else
1419 suspend_shell();
1420#endif
1421}
1422
1423 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001424mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425{
1426 Columns = 80;
1427 Rows = 24;
1428
1429 out_flush();
1430 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001431
Bram Moolenaar56718732006-03-15 22:53:57 +00001432#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001433 mac_conv_init();
1434#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001435#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1436 win_clip_init();
1437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438}
1439
1440 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001441set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001442{
1443#if defined(SIGWINCH)
1444 /*
1445 * WINDOW CHANGE signal is handled with sig_winch().
1446 */
1447 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1448#endif
1449
1450 /*
1451 * We want the STOP signal to work, to make mch_suspend() work.
1452 * For "rvim" the STOP signal is ignored.
1453 */
1454#ifdef SIGTSTP
1455 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1456#endif
Bram Moolenaar917e32b2018-08-07 17:38:41 +02001457#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458 signal(SIGCONT, sigcont_handler);
1459#endif
1460
1461 /*
1462 * We want to ignore breaking of PIPEs.
1463 */
1464#ifdef SIGPIPE
1465 signal(SIGPIPE, SIG_IGN);
1466#endif
1467
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001469 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470#endif
1471
1472 /*
1473 * Ignore alarm signals (Perl's alarm() generates it).
1474 */
1475#ifdef SIGALRM
1476 signal(SIGALRM, SIG_IGN);
1477#endif
1478
1479 /*
1480 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1481 * work will be lost.
1482 */
1483#ifdef SIGPWR
1484 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1485#endif
1486
1487 /*
1488 * Arrange for other signals to gracefully shutdown Vim.
1489 */
1490 catch_signals(deathtrap, SIG_ERR);
1491
1492#if defined(FEAT_GUI) && defined(SIGHUP)
1493 /*
1494 * When the GUI is running, ignore the hangup signal.
1495 */
1496 if (gui.in_use)
1497 signal(SIGHUP, SIG_IGN);
1498#endif
1499}
1500
Bram Moolenaardf177f62005-02-22 08:39:57 +00001501#if defined(SIGINT) || defined(PROTO)
1502/*
1503 * Catch CTRL-C (only works while in Cooked mode).
1504 */
1505 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001506catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001507{
1508 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1509}
1510#endif
1511
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001513reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514{
1515 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001516#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517 /* SIGCONT isn't in the list, because its default action is ignore */
1518 signal(SIGCONT, SIG_DFL);
1519#endif
1520}
1521
1522 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001523catch_signals(
1524 RETSIGTYPE (*func_deadly)(),
1525 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526{
1527 int i;
1528
1529 for (i = 0; signal_info[i].sig != -1; i++)
1530 if (signal_info[i].deadly)
1531 {
1532#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1533 struct sigaction sa;
1534
1535 /* Setup to use the alternate stack for the signal function. */
1536 sa.sa_handler = func_deadly;
1537 sigemptyset(&sa.sa_mask);
1538# if defined(__linux__) && defined(_REENTRANT)
1539 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1540 * thread handling in combination with using the alternate stack:
1541 * pthread library functions try to use the stack pointer to
1542 * identify the current thread, causing a SEGV signal, which
1543 * recursively calls deathtrap() and hangs. */
1544 sa.sa_flags = 0;
1545# else
1546 sa.sa_flags = SA_ONSTACK;
1547# endif
1548 sigaction(signal_info[i].sig, &sa, NULL);
1549#else
1550# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1551 struct sigvec sv;
1552
1553 /* Setup to use the alternate stack for the signal function. */
1554 sv.sv_handler = func_deadly;
1555 sv.sv_mask = 0;
1556 sv.sv_flags = SV_ONSTACK;
1557 sigvec(signal_info[i].sig, &sv, NULL);
1558# else
1559 signal(signal_info[i].sig, func_deadly);
1560# endif
1561#endif
1562 }
1563 else if (func_other != SIG_ERR)
1564 signal(signal_info[i].sig, func_other);
1565}
1566
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001567#ifdef HAVE_SIGPROCMASK
1568 static void
1569block_signals(sigset_t *set)
1570{
1571 sigset_t newset;
1572 int i;
1573
1574 sigemptyset(&newset);
1575
1576 for (i = 0; signal_info[i].sig != -1; i++)
1577 sigaddset(&newset, signal_info[i].sig);
1578
1579# if defined(_REENTRANT) && defined(SIGCONT)
1580 /* SIGCONT isn't in the list, because its default action is ignore */
1581 sigaddset(&newset, SIGCONT);
1582# endif
1583
1584 sigprocmask(SIG_BLOCK, &newset, set);
1585}
1586
1587 static void
1588unblock_signals(sigset_t *set)
1589{
1590 sigprocmask(SIG_SETMASK, set, NULL);
1591}
1592#endif
1593
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001595 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001596 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1597 * return TRUE
1598 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1599 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001600 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001601 * Returns TRUE when Vim should exit.
1602 */
1603 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001604vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001605{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001606 static int got_signal = 0;
1607 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001608
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001609 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001610 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001611 case SIGNAL_BLOCK: blocked = TRUE;
1612 break;
1613
1614 case SIGNAL_UNBLOCK: blocked = FALSE;
1615 if (got_signal != 0)
1616 {
1617 kill(getpid(), got_signal);
1618 got_signal = 0;
1619 }
1620 break;
1621
1622 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001623 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001624 got_signal = sig;
1625#ifdef SIGPWR
1626 if (sig != SIGPWR)
1627#endif
1628 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001629 break;
1630 }
1631 return FALSE;
1632}
1633
1634/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635 * Check_win checks whether we have an interactive stdout.
1636 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001638mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640 if (isatty(1))
1641 return OK;
1642 return FAIL;
1643}
1644
1645/*
1646 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1647 */
1648 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001649mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650{
1651 if (isatty(read_cmd_fd))
1652 return TRUE;
1653 return FALSE;
1654}
1655
1656#ifdef FEAT_X11
1657
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001658# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001659 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1660
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661/*
1662 * Give a message about the elapsed time for opening the X window.
1663 */
1664 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001665xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666{
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001667 smsg((char_u *)_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668}
1669# endif
1670#endif
1671
1672#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1673/*
1674 * A few functions shared by X11 title and clipboard code.
1675 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001676static int x_error_handler(Display *dpy, XErrorEvent *error_event);
1677static int x_error_check(Display *dpy, XErrorEvent *error_event);
1678static int x_connect_to_server(void);
1679static int test_x11_window(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680
1681static int got_x_error = FALSE;
1682
1683/*
1684 * X Error handler, otherwise X just exits! (very rude) -- webb
1685 */
1686 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001687x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001689 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 STRCAT(IObuff, _("\nVim: Got X error\n"));
1691
1692 /* We cannot print a message and continue, because no X calls are allowed
1693 * here (causes my system to hang). Silently continuing might be an
1694 * alternative... */
1695 preserve_exit(); /* preserve files and exit */
1696
1697 return 0; /* NOTREACHED */
1698}
1699
1700/*
1701 * Another X Error handler, just used to check for errors.
1702 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001704x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705{
1706 got_x_error = TRUE;
1707 return 0;
1708}
1709
1710#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1711# if defined(HAVE_SETJMP_H)
1712/*
1713 * An X IO Error handler, used to catch error while opening the display.
1714 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001715static int x_IOerror_check(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001718x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719{
1720 /* This function should not return, it causes exit(). Longjump instead. */
1721 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001722# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001723 return 0; /* avoid the compiler complains about missing return value */
1724# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725}
1726# endif
1727
1728/*
1729 * An X IO Error handler, used to catch terminal errors.
1730 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001731static int x_IOerror_handler(Display *dpy);
1732static void may_restore_clipboard(void);
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001733static int xterm_dpy_was_reset = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001736x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737{
1738 xterm_dpy = NULL;
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001739 xterm_dpy_was_reset = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 x11_window = 0;
1741 x11_display = NULL;
1742 xterm_Shell = (Widget)0;
1743
1744 /* This function should not return, it causes exit(). Longjump instead. */
1745 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001746# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001747 return 0; /* avoid the compiler complains about missing return value */
1748# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001750
1751/*
1752 * If the X11 connection was lost try to restore it.
1753 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001754 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001755 */
1756 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001757may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001758{
1759 if (xterm_dpy_was_reset)
1760 {
1761 xterm_dpy_was_reset = FALSE;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001762
1763# ifndef LESSTIF_VERSION
1764 /* This has been reported to avoid Vim getting stuck. */
1765 if (app_context != (XtAppContext)NULL)
1766 {
1767 XtDestroyApplicationContext(app_context);
1768 app_context = (XtAppContext)NULL;
1769 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
1770 }
1771# endif
1772
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001773 setup_term_clip();
1774 get_x11_title(FALSE);
1775 }
1776}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777#endif
1778
1779/*
1780 * Return TRUE when connection to the X server is desired.
1781 */
1782 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001783x_connect_to_server(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785#if defined(FEAT_CLIENTSERVER)
1786 if (x_force_connect)
1787 return TRUE;
1788#endif
1789 if (x_no_connect)
1790 return FALSE;
1791
1792 /* Check for a match with "exclude:" from 'clipboard'. */
1793 if (clip_exclude_prog != NULL)
1794 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01001795 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 return FALSE;
1797 }
1798 return TRUE;
1799}
1800
1801/*
1802 * Test if "dpy" and x11_window are valid by getting the window title.
1803 * I don't actually want it yet, so there may be a simpler call to use, but
1804 * this will cause the error handler x_error_check() to be called if anything
1805 * is wrong, such as the window pointer being invalid (as can happen when the
1806 * user changes his DISPLAY, but not his WINDOWID) -- webb
1807 */
1808 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001809test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810{
1811 int (*old_handler)();
1812 XTextProperty text_prop;
1813
1814 old_handler = XSetErrorHandler(x_error_check);
1815 got_x_error = FALSE;
1816 if (XGetWMName(dpy, x11_window, &text_prop))
1817 XFree((void *)text_prop.value);
1818 XSync(dpy, False);
1819 (void)XSetErrorHandler(old_handler);
1820
1821 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001822 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823
1824 return (got_x_error ? FAIL : OK);
1825}
1826#endif
1827
1828#ifdef FEAT_TITLE
1829
1830#ifdef FEAT_X11
1831
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001832static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833
1834/*
1835 * try to get x11 window and display
1836 *
1837 * return FAIL for failure, OK otherwise
1838 */
1839 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001840get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841{
1842 char *winid;
1843 static int result = -1;
1844#define XD_NONE 0 /* x11_display not set here */
1845#define XD_HERE 1 /* x11_display opened here */
1846#define XD_GUI 2 /* x11_display used from gui.dpy */
1847#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1848 static int x11_display_from = XD_NONE;
1849 static int did_set_error_handler = FALSE;
1850
1851 if (!did_set_error_handler)
1852 {
1853 /* X just exits if it finds an error otherwise! */
1854 (void)XSetErrorHandler(x_error_handler);
1855 did_set_error_handler = TRUE;
1856 }
1857
Bram Moolenaar9372a112005-12-06 19:59:18 +00001858#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 if (gui.in_use)
1860 {
1861 /*
1862 * If the X11 display was opened here before, for the window where Vim
1863 * was started, close that one now to avoid a memory leak.
1864 */
1865 if (x11_display_from == XD_HERE && x11_display != NULL)
1866 {
1867 XCloseDisplay(x11_display);
1868 x11_display_from = XD_NONE;
1869 }
1870 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1871 {
1872 x11_display_from = XD_GUI;
1873 return OK;
1874 }
1875 x11_display = NULL;
1876 return FAIL;
1877 }
1878 else if (x11_display_from == XD_GUI)
1879 {
1880 /* GUI must have stopped somehow, clear x11_display */
1881 x11_window = 0;
1882 x11_display = NULL;
1883 x11_display_from = XD_NONE;
1884 }
1885#endif
1886
1887 /* When started with the "-X" argument, don't try connecting. */
1888 if (!x_connect_to_server())
1889 return FAIL;
1890
1891 /*
1892 * If WINDOWID not set, should try another method to find out
1893 * what the current window number is. The only code I know for
1894 * this is very complicated.
1895 * We assume that zero is invalid for WINDOWID.
1896 */
1897 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1898 x11_window = (Window)atol(winid);
1899
1900#ifdef FEAT_XCLIPBOARD
1901 if (xterm_dpy != NULL && x11_window != 0)
1902 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001903 /* We may have checked it already, but Gnome terminal can move us to
1904 * another window, so we need to check every time. */
1905 if (x11_display_from != XD_XTERM)
1906 {
1907 /*
1908 * If the X11 display was opened here before, for the window where
1909 * Vim was started, close that one now to avoid a memory leak.
1910 */
1911 if (x11_display_from == XD_HERE && x11_display != NULL)
1912 XCloseDisplay(x11_display);
1913 x11_display = xterm_dpy;
1914 x11_display_from = XD_XTERM;
1915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 if (test_x11_window(x11_display) == FAIL)
1917 {
1918 /* probably bad $WINDOWID */
1919 x11_window = 0;
1920 x11_display = NULL;
1921 x11_display_from = XD_NONE;
1922 return FAIL;
1923 }
1924 return OK;
1925 }
1926#endif
1927
1928 if (x11_window == 0 || x11_display == NULL)
1929 result = -1;
1930
1931 if (result != -1) /* Have already been here and set this */
1932 return result; /* Don't do all these X calls again */
1933
1934 if (x11_window != 0 && x11_display == NULL)
1935 {
1936#ifdef SET_SIG_ALARM
1937 RETSIGTYPE (*sig_save)();
1938#endif
1939#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1940 struct timeval start_tv;
1941
1942 if (p_verbose > 0)
1943 gettimeofday(&start_tv, NULL);
1944#endif
1945
1946#ifdef SET_SIG_ALARM
1947 /*
1948 * Opening the Display may hang if the DISPLAY setting is wrong, or
1949 * the network connection is bad. Set an alarm timer to get out.
1950 */
1951 sig_alarm_called = FALSE;
1952 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1953 (RETSIGTYPE (*)())sig_alarm);
1954 alarm(2);
1955#endif
1956 x11_display = XOpenDisplay(NULL);
1957
1958#ifdef SET_SIG_ALARM
1959 alarm(0);
1960 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1961 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001962 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963#endif
1964 if (x11_display != NULL)
1965 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001966# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001968 {
1969 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001970 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001971 verbose_leave();
1972 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973# endif
1974 if (test_x11_window(x11_display) == FAIL)
1975 {
1976 /* Maybe window id is bad */
1977 x11_window = 0;
1978 XCloseDisplay(x11_display);
1979 x11_display = NULL;
1980 }
1981 else
1982 x11_display_from = XD_HERE;
1983 }
1984 }
1985 if (x11_window == 0 || x11_display == NULL)
1986 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001987
1988# ifdef FEAT_EVAL
1989 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1990# endif
1991
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 return (result = OK);
1993}
1994
1995/*
1996 * Determine original x11 Window Title
1997 */
1998 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001999get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000{
Bram Moolenaar47136d72004-10-12 20:02:24 +00002001 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002}
2003
2004/*
2005 * Determine original x11 Window icon
2006 */
2007 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002008get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009{
2010 int retval = FALSE;
2011
2012 retval = get_x11_thing(FALSE, test_only);
2013
2014 /* could not get old icon, use terminal name */
2015 if (oldicon == NULL && !test_only)
2016 {
2017 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002018 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002020 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021 }
2022
2023 return retval;
2024}
2025
2026 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002027get_x11_thing(
2028 int get_title, /* get title string */
2029 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030{
2031 XTextProperty text_prop;
2032 int retval = FALSE;
2033 Status status;
2034
2035 if (get_x11_windis() == OK)
2036 {
2037 /* Get window/icon name if any */
2038 if (get_title)
2039 status = XGetWMName(x11_display, x11_window, &text_prop);
2040 else
2041 status = XGetWMIconName(x11_display, x11_window, &text_prop);
2042
2043 /*
2044 * If terminal is xterm, then x11_window may be a child window of the
2045 * outer xterm window that actually contains the window/icon name, so
2046 * keep traversing up the tree until a window with a title/icon is
2047 * found.
2048 */
2049 /* Previously this was only done for xterm and alikes. I don't see a
2050 * reason why it would fail for other terminal emulators.
2051 * if (term_is_xterm) */
2052 {
2053 Window root;
2054 Window parent;
2055 Window win = x11_window;
2056 Window *children;
2057 unsigned int num_children;
2058
2059 while (!status || text_prop.value == NULL)
2060 {
2061 if (!XQueryTree(x11_display, win, &root, &parent, &children,
2062 &num_children))
2063 break;
2064 if (children)
2065 XFree((void *)children);
2066 if (parent == root || parent == 0)
2067 break;
2068
2069 win = parent;
2070 if (get_title)
2071 status = XGetWMName(x11_display, win, &text_prop);
2072 else
2073 status = XGetWMIconName(x11_display, win, &text_prop);
2074 }
2075 }
2076 if (status && text_prop.value != NULL)
2077 {
2078 retval = TRUE;
2079 if (!test_only)
2080 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002081#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
2082 if (text_prop.encoding == XA_STRING
2083# ifdef FEAT_MBYTE
2084 && !has_mbyte
2085# endif
2086 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002087 {
2088#endif
2089 if (get_title)
2090 oldtitle = vim_strsave((char_u *)text_prop.value);
2091 else
2092 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002093#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 }
2095 else
2096 {
2097 char **cl;
2098 Status transform_status;
2099 int n = 0;
2100
2101 transform_status = XmbTextPropertyToTextList(x11_display,
2102 &text_prop,
2103 &cl, &n);
2104 if (transform_status >= Success && n > 0 && cl[0])
2105 {
2106 if (get_title)
2107 oldtitle = vim_strsave((char_u *) cl[0]);
2108 else
2109 oldicon = vim_strsave((char_u *) cl[0]);
2110 XFreeStringList(cl);
2111 }
2112 else
2113 {
2114 if (get_title)
2115 oldtitle = vim_strsave((char_u *)text_prop.value);
2116 else
2117 oldicon = vim_strsave((char_u *)text_prop.value);
2118 }
2119 }
2120#endif
2121 }
2122 XFree((void *)text_prop.value);
2123 }
2124 }
2125 return retval;
2126}
2127
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002128/* Xutf8 functions are not avaialble on older systems. Note that on some
2129 * systems X_HAVE_UTF8_STRING may be defined in a header file but
2130 * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2131 * that and defines HAVE_XUTF8SETWMPROPERTIES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002133# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134# define USE_UTF8_STRING
2135# endif
2136#endif
2137
2138/*
2139 * Set x11 Window Title
2140 *
2141 * get_x11_windis() must be called before this and have returned OK
2142 */
2143 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002144set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145{
2146 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2147 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2148 * supported everywhere and STRING doesn't work for multi-byte titles.
2149 */
2150#ifdef USE_UTF8_STRING
2151 if (enc_utf8)
2152 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2153 NULL, NULL, 0, NULL, NULL, NULL);
2154 else
2155#endif
2156 {
2157#if XtSpecificationRelease >= 4
2158# ifdef FEAT_XFONTSET
2159 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2160 NULL, NULL, 0, NULL, NULL, NULL);
2161# else
2162 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002163 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164
2165 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002166 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 XSetWMProperties(x11_display, x11_window, &text_prop,
2168 NULL, NULL, 0, NULL, NULL, NULL);
2169# endif
2170#else
2171 XStoreName(x11_display, x11_window, (char *)title);
2172#endif
2173 }
2174 XFlush(x11_display);
2175}
2176
2177/*
2178 * Set x11 Window icon
2179 *
2180 * get_x11_windis() must be called before this and have returned OK
2181 */
2182 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002183set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184{
2185 /* See above for comments about using X*SetWMProperties(). */
2186#ifdef USE_UTF8_STRING
2187 if (enc_utf8)
2188 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2189 NULL, 0, NULL, NULL, NULL);
2190 else
2191#endif
2192 {
2193#if XtSpecificationRelease >= 4
2194# ifdef FEAT_XFONTSET
2195 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2196 NULL, 0, NULL, NULL, NULL);
2197# else
2198 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002199 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002201 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2203 NULL, 0, NULL, NULL, NULL);
2204# endif
2205#else
2206 XSetIconName(x11_display, x11_window, (char *)icon);
2207#endif
2208 }
2209 XFlush(x11_display);
2210}
2211
2212#else /* FEAT_X11 */
2213
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002215get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216{
2217 return FALSE;
2218}
2219
2220 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002221get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002222{
2223 if (!test_only)
2224 {
2225 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002226 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002228 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 }
2230 return FALSE;
2231}
2232
2233#endif /* FEAT_X11 */
2234
2235 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002236mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237{
2238 return get_x11_title(TRUE);
2239}
2240
2241 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002242mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243{
2244 return get_x11_icon(TRUE);
2245}
2246
2247/*
2248 * Set the window title and icon.
2249 */
2250 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002251mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252{
2253 int type = 0;
2254 static int recursive = 0;
2255
2256 if (T_NAME == NULL) /* no terminal name (yet) */
2257 return;
2258 if (title == NULL && icon == NULL) /* nothing to do */
2259 return;
2260
2261 /* When one of the X11 functions causes a deadly signal, we get here again
2262 * recursively. Avoid hanging then (something is probably locked). */
2263 if (recursive)
2264 return;
2265 ++recursive;
2266
2267 /*
2268 * if the window ID and the display is known, we may use X11 calls
2269 */
2270#ifdef FEAT_X11
2271 if (get_x11_windis() == OK)
2272 type = 1;
2273#else
2274# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2275 if (gui.in_use)
2276 type = 1;
2277# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278#endif
2279
2280 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002281 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 * than x11 calls, because the x11 calls don't always work
2283 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 if ((type || *T_TS != NUL) && title != NULL)
2285 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002286 if (oldtitle_outdated)
2287 {
2288 oldtitle_outdated = FALSE;
2289 VIM_CLEAR(oldtitle);
2290 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291 if (oldtitle == NULL
2292#ifdef FEAT_GUI
2293 && !gui.in_use
2294#endif
2295 ) /* first call but not in GUI, save title */
2296 (void)get_x11_title(FALSE);
2297
2298 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2299 term_settitle(title);
2300#ifdef FEAT_X11
2301 else
2302# ifdef FEAT_GUI_GTK
2303 if (!gui.in_use) /* don't do this if GTK+ is running */
2304# endif
2305 set_x11_title(title); /* x11 */
2306#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002307#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2309 else
2310 gui_mch_settitle(title, icon);
2311#endif
2312 did_set_title = TRUE;
2313 }
2314
2315 if ((type || *T_CIS != NUL) && icon != NULL)
2316 {
2317 if (oldicon == NULL
2318#ifdef FEAT_GUI
2319 && !gui.in_use
2320#endif
2321 ) /* first call, save icon */
2322 get_x11_icon(FALSE);
2323
2324 if (*T_CIS != NUL)
2325 {
2326 out_str(T_CIS); /* set icon start */
2327 out_str_nf(icon);
2328 out_str(T_CIE); /* set icon end */
2329 out_flush();
2330 }
2331#ifdef FEAT_X11
2332 else
2333# ifdef FEAT_GUI_GTK
2334 if (!gui.in_use) /* don't do this if GTK+ is running */
2335# endif
2336 set_x11_icon(icon); /* x11 */
2337#endif
2338 did_set_icon = TRUE;
2339 }
2340 --recursive;
2341}
2342
2343/*
2344 * Restore the window/icon title.
2345 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002346 * SAVE_RESTORE_TITLE only restore title
2347 * SAVE_RESTORE_ICON only restore icon
2348 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 */
2350 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002351mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352{
2353 /* only restore the title or icon when it has been set */
Bram Moolenaar40385db2018-08-07 22:31:44 +02002354 mch_settitle(((which & SAVE_RESTORE_TITLE) && did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002356 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2357
2358 // pop and push from/to the stack
2359 term_pop_title(which);
2360 term_push_title(which);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361}
2362
2363#endif /* FEAT_TITLE */
2364
2365/*
2366 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002367 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 */
2369 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002370vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371{
2372 if (name == NULL)
2373 return FALSE;
2374 return (STRNICMP(name, "xterm", 5) == 0
2375 || STRNICMP(name, "nxterm", 6) == 0
2376 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002377 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002379 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 || STRCMP(name, "builtin_xterm") == 0);
2381}
2382
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002383#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2384/*
2385 * Return TRUE if "name" appears to be that of a terminal
2386 * known to support the xterm-style mouse protocol.
2387 * Relies on term_is_xterm having been set to its correct value.
2388 */
2389 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002390use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002391{
2392 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002393 && (term_is_xterm
2394 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002395 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002396 || STRICMP(name, "st") == 0
2397 || STRNICMP(name, "st-", 3) == 0
2398 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002399}
2400#endif
2401
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2403/*
2404 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2405 * Return 1 for "xterm".
2406 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002407 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002408 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 */
2410 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002411use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002413 if (ttym_flags == TTYM_SGR)
2414 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002415 if (ttym_flags == TTYM_URXVT)
2416 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 if (ttym_flags == TTYM_XTERM2)
2418 return 2;
2419 if (ttym_flags == TTYM_XTERM)
2420 return 1;
2421 return 0;
2422}
2423#endif
2424
2425 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002426vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427{
2428 if (name == NULL)
2429 return FALSE;
2430 return (STRNICMP(name, "iris-ansi", 9) == 0
2431 || STRCMP(name, "builtin_iris-ansi") == 0);
2432}
2433
2434 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002435vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436{
2437 if (name == NULL)
2438 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002439 /* catch VT100 - VT5xx */
2440 return ((STRNICMP(name, "vt", 2) == 0
2441 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 || STRCMP(name, "builtin_vt320") == 0);
2443}
2444
2445/*
2446 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2447 * This should include all windowed terminal emulators.
2448 */
2449 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002450vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451{
2452 if (name == NULL)
2453 return FALSE;
2454 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2455 return TRUE;
2456 return ( STRNICMP(name, "hpterm", 6) == 0
2457 || STRNICMP(name, "sun-cmd", 7) == 0
2458 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002459 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 || STRNICMP(name, "dtterm", 6) == 0);
2461}
2462
2463/*
2464 * Insert user name in s[len].
2465 * Return OK if a name found.
2466 */
2467 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002468mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002469{
2470#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002471 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472 return OK;
2473#else
2474 return mch_get_uname(getuid(), s, len);
2475#endif
2476}
2477
2478/*
2479 * Insert user name for "uid" in s[len].
2480 * Return OK if a name found.
2481 */
2482 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002483mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484{
2485#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2486 struct passwd *pw;
2487
2488 if ((pw = getpwuid(uid)) != NULL
2489 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2490 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002491 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 return OK;
2493 }
2494#endif
2495 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2496 return FAIL; /* a number is not a name */
2497}
2498
2499/*
2500 * Insert host name is s[len].
2501 */
2502
2503#ifdef HAVE_SYS_UTSNAME_H
2504 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002505mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506{
2507 struct utsname vutsname;
2508
2509 if (uname(&vutsname) < 0)
2510 *s = NUL;
2511 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002512 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513}
2514#else /* HAVE_SYS_UTSNAME_H */
2515
2516# ifdef HAVE_SYS_SYSTEMINFO_H
2517# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2518# endif
2519
2520 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002521mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522{
2523# ifdef VAXC
2524 vaxc$gethostname((char *)s, len);
2525# else
2526 gethostname((char *)s, len);
2527# endif
2528 s[len - 1] = NUL; /* make sure it's terminated */
2529}
2530#endif /* HAVE_SYS_UTSNAME_H */
2531
2532/*
2533 * return process ID
2534 */
2535 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002536mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537{
2538 return (long)getpid();
2539}
2540
2541#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01002542static char *strerror(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543
2544 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002545strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546{
2547 extern int sys_nerr;
2548 extern char *sys_errlist[];
2549 static char er[20];
2550
2551 if (err > 0 && err < sys_nerr)
2552 return (sys_errlist[err]);
2553 sprintf(er, "Error %d", err);
2554 return er;
2555}
2556#endif
2557
2558/*
2559 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2560 * Return OK for success, FAIL for failure.
2561 */
2562 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002563mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564{
2565#if defined(USE_GETCWD)
2566 if (getcwd((char *)buf, len) == NULL)
2567 {
2568 STRCPY(buf, strerror(errno));
2569 return FAIL;
2570 }
2571 return OK;
2572#else
2573 return (getwd((char *)buf) != NULL ? OK : FAIL);
2574#endif
2575}
2576
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002578 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 *
2580 * return FAIL for failure, OK for success
2581 */
2582 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002583mch_FullName(
2584 char_u *fname,
2585 char_u *buf,
2586 int len,
2587 int force) /* also expand when already absolute path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588{
2589 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002590#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 int fd = -1;
2592 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002593#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 char_u olddir[MAXPATHL];
2595 char_u *p;
2596 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002597#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002598 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2599 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002600#endif
2601
Bram Moolenaar38323e42007-03-06 19:22:53 +00002602#ifdef VMS
2603 fname = vms_fixfilename(fname);
2604#endif
2605
Bram Moolenaara2442432007-04-26 14:26:37 +00002606#ifdef __CYGWIN__
2607 /*
2608 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2609 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002610# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar06b07342015-12-31 22:26:28 +01002611 /* Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2612 * a forward slash. */
2613 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2614 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002615# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002616 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002617# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002618 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002619#endif
2620
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002621 /* Expand it if forced or not an absolute path.
2622 * Do not do it for "/file", the result is always "/". */
2623 if ((force || !mch_isFullName(fname))
2624 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625 {
2626 /*
2627 * If the file name has a path, change to that directory for a moment,
2628 * and then do the getwd() (and get back to where we were).
2629 * This will get the correct path name with "../" things.
2630 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002631 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002633#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634 /*
2635 * Use fchdir() if possible, it's said to be faster and more
2636 * reliable. But on SunOS 4 it might not work. Check this by
2637 * doing a fchdir() right now.
2638 */
2639 if (!dont_fchdir)
2640 {
2641 fd = open(".", O_RDONLY | O_EXTRA, 0);
2642 if (fd >= 0 && fchdir(fd) < 0)
2643 {
2644 close(fd);
2645 fd = -1;
2646 dont_fchdir = TRUE; /* don't try again */
2647 }
2648 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002649#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650
2651 /* Only change directory when we are sure we can return to where
2652 * we are now. After doing "su" chdir(".") might not work. */
2653 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002654#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002656#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657 (mch_dirname(olddir, MAXPATHL) == FAIL
2658 || mch_chdir((char *)olddir) != 0))
2659 {
2660 p = NULL; /* can't get current dir: don't chdir */
2661 retval = FAIL;
2662 }
2663 else
2664 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 /* The directory is copied into buf[], to be able to remove
2666 * the file name without changing it (could be a string in
2667 * read-only memory) */
2668 if (p - fname >= len)
2669 retval = FAIL;
2670 else
2671 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002672 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 if (mch_chdir((char *)buf))
2674 retval = FAIL;
2675 else
2676 fname = p + 1;
2677 *buf = NUL;
2678 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 }
2680 }
2681 if (mch_dirname(buf, len) == FAIL)
2682 {
2683 retval = FAIL;
2684 *buf = NUL;
2685 }
2686 if (p != NULL)
2687 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002688#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 if (fd >= 0)
2690 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002691 if (p_verbose >= 5)
2692 {
2693 verbose_enter();
2694 MSG("fchdir() to previous dir");
2695 verbose_leave();
2696 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697 l = fchdir(fd);
2698 close(fd);
2699 }
2700 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002701#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 l = mch_chdir((char *)olddir);
2703 if (l != 0)
2704 EMSG(_(e_prev_dir));
2705 }
2706
2707 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002708 if (l >= len - 1)
2709 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002710#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002711 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002713 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002714#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002716
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002718 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719 return FAIL;
2720
2721 /* Do not append ".", "/dir/." is equal to "/dir". */
2722 if (STRCMP(fname, ".") != 0)
2723 STRCAT(buf, fname);
2724
2725 return OK;
2726}
2727
2728/*
2729 * Return TRUE if "fname" does not depend on the current directory.
2730 */
2731 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002732mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002734#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735 return ( fname[0] == '/' || fname[0] == '.' ||
2736 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2737 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2738 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002739#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741#endif
2742}
2743
Bram Moolenaar24552be2005-12-10 20:17:30 +00002744#if defined(USE_FNAME_CASE) || defined(PROTO)
2745/*
2746 * Set the case of the file name, if it already exists. This will cause the
2747 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002748 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002749 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002750 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002751fname_case(
2752 char_u *name,
2753 int len UNUSED) /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002754{
2755 struct stat st;
2756 char_u *slash, *tail;
2757 DIR *dirp;
2758 struct dirent *dp;
2759
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002760 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002761 {
2762 /* Open the directory where the file is located. */
2763 slash = vim_strrchr(name, '/');
2764 if (slash == NULL)
2765 {
2766 dirp = opendir(".");
2767 tail = name;
2768 }
2769 else
2770 {
2771 *slash = NUL;
2772 dirp = opendir((char *)name);
2773 *slash = '/';
2774 tail = slash + 1;
2775 }
2776
2777 if (dirp != NULL)
2778 {
2779 while ((dp = readdir(dirp)) != NULL)
2780 {
2781 /* Only accept names that differ in case and are the same byte
2782 * length. TODO: accept different length name. */
2783 if (STRICMP(tail, dp->d_name) == 0
2784 && STRLEN(tail) == STRLEN(dp->d_name))
2785 {
2786 char_u newname[MAXPATHL + 1];
2787 struct stat st2;
2788
2789 /* Verify the inode is equal. */
2790 vim_strncpy(newname, name, MAXPATHL);
2791 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2792 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002793 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002794 && st.st_ino == st2.st_ino
2795 && st.st_dev == st2.st_dev)
2796 {
2797 STRCPY(tail, dp->d_name);
2798 break;
2799 }
2800 }
2801 }
2802
2803 closedir(dirp);
2804 }
2805 }
2806}
2807#endif
2808
Bram Moolenaar071d4272004-06-13 20:20:40 +00002809/*
2810 * Get file permissions for 'name'.
2811 * Returns -1 when it doesn't exist.
2812 */
2813 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002814mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815{
2816 struct stat statb;
2817
2818 /* Keep the #ifdef outside of stat(), it may be a macro. */
2819#ifdef VMS
2820 if (stat((char *)vms_fixfilename(name), &statb))
2821#else
2822 if (stat((char *)name, &statb))
2823#endif
2824 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002825#ifdef __INTERIX
2826 /* The top bit makes the value negative, which means the file doesn't
2827 * exist. Remove the bit, we don't use it. */
2828 return statb.st_mode & ~S_ADDACE;
2829#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002831#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832}
2833
2834/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002835 * Set file permission for "name" to "perm".
2836 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 */
2838 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002839mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840{
2841 return (chmod((char *)
2842#ifdef VMS
2843 vms_fixfilename(name),
2844#else
2845 name,
2846#endif
2847 (mode_t)perm) == 0 ? OK : FAIL);
2848}
2849
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002850#if defined(HAVE_FCHMOD) || defined(PROTO)
2851/*
2852 * Set file permission for open file "fd" to "perm".
2853 * Return FAIL for failure, OK otherwise.
2854 */
2855 int
2856mch_fsetperm(int fd, long perm)
2857{
2858 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2859}
2860#endif
2861
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862#if defined(HAVE_ACL) || defined(PROTO)
2863# ifdef HAVE_SYS_ACL_H
2864# include <sys/acl.h>
2865# endif
2866# ifdef HAVE_SYS_ACCESS_H
2867# include <sys/access.h>
2868# endif
2869
2870# ifdef HAVE_SOLARIS_ACL
2871typedef struct vim_acl_solaris_T {
2872 int acl_cnt;
2873 aclent_t *acl_entry;
2874} vim_acl_solaris_T;
2875# endif
2876
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002877#if defined(HAVE_SELINUX) || defined(PROTO)
2878/*
2879 * Copy security info from "from_file" to "to_file".
2880 */
2881 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002882mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002883{
2884 if (from_file == NULL)
2885 return;
2886
2887 if (selinux_enabled == -1)
2888 selinux_enabled = is_selinux_enabled();
2889
2890 if (selinux_enabled > 0)
2891 {
2892 security_context_t from_context = NULL;
2893 security_context_t to_context = NULL;
2894
2895 if (getfilecon((char *)from_file, &from_context) < 0)
2896 {
2897 /* If the filesystem doesn't support extended attributes,
2898 the original had no special security context and the
2899 target cannot have one either. */
2900 if (errno == EOPNOTSUPP)
2901 return;
2902
2903 MSG_PUTS(_("\nCould not get security context for "));
2904 msg_outtrans(from_file);
2905 msg_putchar('\n');
2906 return;
2907 }
2908 if (getfilecon((char *)to_file, &to_context) < 0)
2909 {
2910 MSG_PUTS(_("\nCould not get security context for "));
2911 msg_outtrans(to_file);
2912 msg_putchar('\n');
2913 freecon (from_context);
2914 return ;
2915 }
2916 if (strcmp(from_context, to_context) != 0)
2917 {
2918 if (setfilecon((char *)to_file, from_context) < 0)
2919 {
2920 MSG_PUTS(_("\nCould not set security context for "));
2921 msg_outtrans(to_file);
2922 msg_putchar('\n');
2923 }
2924 }
2925 freecon(to_context);
2926 freecon(from_context);
2927 }
2928}
2929#endif /* HAVE_SELINUX */
2930
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002931#if defined(HAVE_SMACK) && !defined(PROTO)
2932/*
2933 * Copy security info from "from_file" to "to_file".
2934 */
2935 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002936mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002937{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002938 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002939 {
2940 XATTR_NAME_SMACK,
2941 XATTR_NAME_SMACKEXEC,
2942 XATTR_NAME_SMACKMMAP
2943 };
2944
2945 char buffer[SMACK_LABEL_LEN];
2946 const char *name;
2947 int index;
2948 int ret;
2949 ssize_t size;
2950
2951 if (from_file == NULL)
2952 return;
2953
2954 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2955 / sizeof(smack_copied_attributes)[0]) ; index++)
2956 {
2957 /* get the name of the attribute to copy */
2958 name = smack_copied_attributes[index];
2959
2960 /* get the value of the attribute in buffer */
2961 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2962 if (size >= 0)
2963 {
2964 /* copy the attribute value of buffer */
2965 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2966 if (ret < 0)
2967 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002968 vim_snprintf((char *)IObuff, IOSIZE,
2969 _("Could not set security context %s for %s"),
2970 name, to_file);
2971 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002972 msg_putchar('\n');
2973 }
2974 }
2975 else
2976 {
2977 /* what reason of not having the attribute value? */
2978 switch (errno)
2979 {
2980 case ENOTSUP:
2981 /* extended attributes aren't supported or enabled */
2982 /* should a message be echoed? not sure... */
2983 return; /* leave because it isn't usefull to continue */
2984
2985 case ERANGE:
2986 default:
2987 /* no enough size OR unexpected error */
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002988 vim_snprintf((char *)IObuff, IOSIZE,
2989 _("Could not get security context %s for %s. Removing it!"),
2990 name, from_file);
2991 msg_puts(IObuff);
2992 msg_putchar('\n');
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002993 /* FALLTHROUGH to remove the attribute */
2994
2995 case ENODATA:
2996 /* no attribute of this name */
2997 ret = removexattr((char*)to_file, name);
Bram Moolenaar57a728d2014-04-02 23:09:26 +02002998 /* Silently ignore errors, apparently this happens when
2999 * smack is not actually being used. */
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003000 break;
3001 }
3002 }
3003 }
3004}
3005#endif /* HAVE_SMACK */
3006
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007/*
3008 * Return a pointer to the ACL of file "fname" in allocated memory.
3009 * Return NULL if the ACL is not available for whatever reason.
3010 */
3011 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01003012mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013{
3014 vim_acl_T ret = NULL;
3015#ifdef HAVE_POSIX_ACL
3016 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
3017#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003018#ifdef HAVE_SOLARIS_ZFS_ACL
3019 acl_t *aclent;
3020
3021 if (acl_get((char *)fname, 0, &aclent) < 0)
3022 return NULL;
3023 ret = (vim_acl_T)aclent;
3024#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025#ifdef HAVE_SOLARIS_ACL
3026 vim_acl_solaris_T *aclent;
3027
3028 aclent = malloc(sizeof(vim_acl_solaris_T));
3029 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
3030 {
3031 free(aclent);
3032 return NULL;
3033 }
3034 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
3035 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
3036 {
3037 free(aclent->acl_entry);
3038 free(aclent);
3039 return NULL;
3040 }
3041 ret = (vim_acl_T)aclent;
3042#else
3043#if defined(HAVE_AIX_ACL)
3044 int aclsize;
3045 struct acl *aclent;
3046
3047 aclsize = sizeof(struct acl);
3048 aclent = malloc(aclsize);
3049 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3050 {
3051 if (errno == ENOSPC)
3052 {
3053 aclsize = aclent->acl_len;
3054 aclent = realloc(aclent, aclsize);
3055 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3056 {
3057 free(aclent);
3058 return NULL;
3059 }
3060 }
3061 else
3062 {
3063 free(aclent);
3064 return NULL;
3065 }
3066 }
3067 ret = (vim_acl_T)aclent;
3068#endif /* HAVE_AIX_ACL */
3069#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003070#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071#endif /* HAVE_POSIX_ACL */
3072 return ret;
3073}
3074
3075/*
3076 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3077 */
3078 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003079mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080{
3081 if (aclent == NULL)
3082 return;
3083#ifdef HAVE_POSIX_ACL
3084 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3085#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003086#ifdef HAVE_SOLARIS_ZFS_ACL
3087 acl_set((char *)fname, (acl_t *)aclent);
3088#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089#ifdef HAVE_SOLARIS_ACL
3090 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3091 ((vim_acl_solaris_T *)aclent)->acl_entry);
3092#else
3093#ifdef HAVE_AIX_ACL
3094 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
3095#endif /* HAVE_AIX_ACL */
3096#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003097#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098#endif /* HAVE_POSIX_ACL */
3099}
3100
3101 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003102mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103{
3104 if (aclent == NULL)
3105 return;
3106#ifdef HAVE_POSIX_ACL
3107 acl_free((acl_t)aclent);
3108#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003109#ifdef HAVE_SOLARIS_ZFS_ACL
3110 acl_free((acl_t *)aclent);
3111#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112#ifdef HAVE_SOLARIS_ACL
3113 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3114 free(aclent);
3115#else
3116#ifdef HAVE_AIX_ACL
3117 free(aclent);
3118#endif /* HAVE_AIX_ACL */
3119#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003120#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121#endif /* HAVE_POSIX_ACL */
3122}
3123#endif
3124
3125/*
3126 * Set hidden flag for "name".
3127 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003129mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130{
3131 /* can't hide a file */
3132}
3133
3134/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003135 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 * return FALSE if "name" is not a directory
3137 * return FALSE for error
3138 */
3139 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003140mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141{
3142 struct stat statb;
3143
3144 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3145 return FALSE;
3146 if (stat((char *)name, &statb))
3147 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149}
3150
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003151/*
3152 * return TRUE if "name" is a directory, NOT a symlink to a directory
3153 * return FALSE if "name" is not a directory
3154 * return FALSE for error
3155 */
3156 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003157mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003158{
3159 struct stat statb;
3160
3161 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3162 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003163 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003164 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003165 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003166}
3167
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003168static int executable_file(char_u *name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169
3170/*
3171 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3172 */
3173 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003174executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175{
3176 struct stat st;
3177
3178 if (stat((char *)name, &st))
3179 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003180#ifdef VMS
3181 /* Like on Unix system file can have executable rights but not necessarily
3182 * be an executable, but on Unix is not a default for an ordianry file to
3183 * have an executable flag - on VMS it is in most cases.
3184 * Therefore, this check does not have any sense - let keep us to the
3185 * conventions instead:
3186 * *.COM and *.EXE files are the executables - the rest are not. This is
3187 * not ideal but better then it was.
3188 */
3189 int vms_executable = 0;
3190 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3191 {
3192 if (strstr(vms_tolower((char*)name),".exe") != NULL
3193 || strstr(vms_tolower((char*)name),".com")!= NULL)
3194 vms_executable = 1;
3195 }
3196 return vms_executable;
3197#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003199#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200}
3201
3202/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003203 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003204 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 * Return -1 if unknown.
3206 */
3207 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003208mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210 char_u *buf;
3211 char_u *p, *e;
3212 int retval;
3213
Bram Moolenaarb5971142015-03-21 17:32:19 +01003214 /* When "use_path" is false and if it's an absolute or relative path don't
3215 * need to use $PATH. */
3216 if (!use_path || mch_isFullName(name) || (name[0] == '.'
3217 && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003218 {
Bram Moolenaarb5971142015-03-21 17:32:19 +01003219 /* There must be a path separator, files in the current directory
3220 * can't be executed. */
3221 if (gettail(name) != name && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003222 {
3223 if (path != NULL)
3224 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003225 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003226 *path = FullName_save(name, TRUE);
3227 else
3228 *path = vim_strsave(name);
3229 }
3230 return TRUE;
3231 }
3232 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003233 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234
3235 p = (char_u *)getenv("PATH");
3236 if (p == NULL || *p == NUL)
3237 return -1;
3238 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3239 if (buf == NULL)
3240 return -1;
3241
3242 /*
3243 * Walk through all entries in $PATH to check if "name" exists there and
3244 * is an executable file.
3245 */
3246 for (;;)
3247 {
3248 e = (char_u *)strchr((char *)p, ':');
3249 if (e == NULL)
3250 e = p + STRLEN(p);
3251 if (e - p <= 1) /* empty entry means current dir */
3252 STRCPY(buf, "./");
3253 else
3254 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003255 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 add_pathsep(buf);
3257 }
3258 STRCAT(buf, name);
3259 retval = executable_file(buf);
3260 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003261 {
3262 if (path != NULL)
3263 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003264 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003265 *path = FullName_save(buf, TRUE);
3266 else
3267 *path = vim_strsave(buf);
3268 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003270 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271
3272 if (*e != ':')
3273 break;
3274 p = e + 1;
3275 }
3276
3277 vim_free(buf);
3278 return retval;
3279}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280
3281/*
3282 * Check what "name" is:
3283 * NODE_NORMAL: file or directory (or doesn't exist)
3284 * NODE_WRITABLE: writable device, socket, fifo, etc.
3285 * NODE_OTHER: non-writable things
3286 */
3287 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003288mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289{
3290 struct stat st;
3291
3292 if (stat((char *)name, &st))
3293 return NODE_NORMAL;
3294 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3295 return NODE_NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3297 return NODE_OTHER;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 /* Everything else is writable? */
3299 return NODE_WRITABLE;
3300}
3301
3302 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003303mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304{
3305#ifdef HAVE_CHECK_STACK_GROWTH
3306 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308 check_stack_growth((char *)&i);
3309
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003310# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311 get_stack_limit();
3312# endif
3313
3314#endif
3315
3316 /*
3317 * Setup an alternative stack for signals. Helps to catch signals when
3318 * running out of stack space.
3319 * Use of sigaltstack() is preferred, it's more portable.
3320 * Ignore any errors.
3321 */
3322#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003323 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 init_signal_stack();
3325#endif
3326}
3327
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003328#if defined(EXITFREE) || defined(PROTO)
3329 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003330mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003331{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003332# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3333 if (clip_star.owned)
3334 clip_lose_selection(&clip_star);
3335 if (clip_plus.owned)
3336 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003337# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003338# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003339 if (xterm_Shell != (Widget)0)
3340 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003341# ifndef LESSTIF_VERSION
3342 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003343 if (xterm_dpy != NULL)
3344 XtCloseDisplay(xterm_dpy);
3345 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003346 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003347 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003348# ifdef FEAT_X11
3349 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3350# endif
3351 }
3352# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003353# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003354# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003355 if (x11_display != NULL
3356# ifdef FEAT_XCLIPBOARD
3357 && x11_display != xterm_dpy
3358# endif
3359 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003360 XCloseDisplay(x11_display);
3361# endif
3362# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003363 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003364# endif
3365# ifdef FEAT_TITLE
3366 vim_free(oldtitle);
3367 vim_free(oldicon);
3368# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003369}
3370#endif
3371
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003372static void exit_scroll(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373
3374/*
3375 * Output a newline when exiting.
3376 * Make sure the newline goes to the same stream as the text.
3377 */
3378 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003379exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003381 if (silent_mode)
3382 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 if (newline_on_exit || msg_didout)
3384 {
3385 if (msg_use_printf())
3386 {
3387 if (info_message)
3388 mch_msg("\n");
3389 else
3390 mch_errmsg("\r\n");
3391 }
3392 else
3393 out_char('\n');
3394 }
3395 else
3396 {
3397 restore_cterm_colors(); /* get original colors back */
3398 msg_clr_eos_force(); /* clear the rest of the display */
3399 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3400 }
3401}
3402
3403 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003404mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405{
3406 exiting = TRUE;
3407
3408#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3409 x11_export_final_selection();
3410#endif
3411
3412#ifdef FEAT_GUI
3413 if (!gui.in_use)
3414#endif
3415 {
3416 settmode(TMODE_COOK);
3417#ifdef FEAT_TITLE
Bram Moolenaar40385db2018-08-07 22:31:44 +02003418 // restore xterm title and icon name
3419 mch_restore_title(SAVE_RESTORE_BOTH);
3420 term_pop_title(SAVE_RESTORE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421#endif
3422 /*
3423 * When t_ti is not empty but it doesn't cause swapping terminal
3424 * pages, need to output a newline when msg_didout is set. But when
3425 * t_ti does swap pages it should not go to the shell page. Do this
3426 * before stoptermcap().
3427 */
3428 if (swapping_screen() && !newline_on_exit)
3429 exit_scroll();
3430
3431 /* Stop termcap: May need to check for T_CRV response, which
3432 * requires RAW mode. */
3433 stoptermcap();
3434
3435 /*
3436 * A newline is only required after a message in the alternate screen.
3437 * This is set to TRUE by wait_return().
3438 */
3439 if (!swapping_screen() || newline_on_exit)
3440 exit_scroll();
3441
3442 /* Cursor may have been switched off without calling starttermcap()
3443 * when doing "vim -u vimrc" and vimrc contains ":q". */
3444 if (full_screen)
3445 cursor_on();
3446 }
3447 out_flush();
3448 ml_close_all(TRUE); /* remove all memfiles */
3449 may_core_dump();
3450#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 gui_exit(r);
3453#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003454
Bram Moolenaar56718732006-03-15 22:53:57 +00003455#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003456 mac_conv_cleanup();
3457#endif
3458
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459#ifdef __QNX__
3460 /* A core dump won't be created if the signal handler
3461 * doesn't return, so we can't call exit() */
3462 if (deadly_signal != 0)
3463 return;
3464#endif
3465
Bram Moolenaar009b2592004-10-24 19:18:58 +00003466#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003467 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003468#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003469
3470#ifdef EXITFREE
3471 free_all_mem();
3472#endif
3473
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 exit(r);
3475}
3476
3477 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003478may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003479{
3480 if (deadly_signal != 0)
3481 {
3482 signal(deadly_signal, SIG_DFL);
3483 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3484 }
3485}
3486
3487#ifndef VMS
3488
3489 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003490mch_settmode(int tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491{
3492 static int first = TRUE;
3493
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003494#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495# ifdef HAVE_TERMIOS_H
3496 static struct termios told;
3497 struct termios tnew;
3498# else
3499 static struct termio told;
3500 struct termio tnew;
3501# endif
3502
3503 if (first)
3504 {
3505 first = FALSE;
3506# if defined(HAVE_TERMIOS_H)
3507 tcgetattr(read_cmd_fd, &told);
3508# else
3509 ioctl(read_cmd_fd, TCGETA, &told);
3510# endif
3511 }
3512
3513 tnew = told;
3514 if (tmode == TMODE_RAW)
3515 {
3516 /*
3517 * ~ICRNL enables typing ^V^M
3518 */
3519 tnew.c_iflag &= ~ICRNL;
3520 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3521# if defined(IEXTEN) && !defined(__MINT__)
3522 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3523 /* but it breaks function keys on MINT */
3524# endif
3525 );
3526# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3527 tnew.c_oflag &= ~ONLCR;
3528# endif
3529 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3530 tnew.c_cc[VTIME] = 0; /* don't wait */
3531 }
3532 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003533 {
3534 /* Also reset ICANON here, otherwise on Solaris select() won't see
3535 * typeahead characters. */
3536 tnew.c_lflag &= ~(ICANON | ECHO);
3537 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3538 tnew.c_cc[VTIME] = 0; /* don't wait */
3539 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540
3541# if defined(HAVE_TERMIOS_H)
3542 {
3543 int n = 10;
3544
3545 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3546 * few times. */
3547 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3548 && errno == EINTR && n > 0)
3549 --n;
3550 }
3551# else
3552 ioctl(read_cmd_fd, TCSETA, &tnew);
3553# endif
3554
3555#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556 /*
3557 * for "old" tty systems
3558 */
3559# ifndef TIOCSETN
3560# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3561# endif
3562 static struct sgttyb ttybold;
3563 struct sgttyb ttybnew;
3564
3565 if (first)
3566 {
3567 first = FALSE;
3568 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3569 }
3570
3571 ttybnew = ttybold;
3572 if (tmode == TMODE_RAW)
3573 {
3574 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3575 ttybnew.sg_flags |= RAW;
3576 }
3577 else if (tmode == TMODE_SLEEP)
3578 ttybnew.sg_flags &= ~(ECHO);
3579 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3580#endif
3581 curr_tmode = tmode;
3582}
3583
3584/*
3585 * Try to get the code for "t_kb" from the stty setting
3586 *
3587 * Even if termcap claims a backspace key, the user's setting *should*
3588 * prevail. stty knows more about reality than termcap does, and if
3589 * somebody's usual erase key is DEL (which, for most BSD users, it will
3590 * be), they're going to get really annoyed if their erase key starts
3591 * doing forward deletes for no reason. (Eric Fischer)
3592 */
3593 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003594get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003596 ttyinfo_T info;
3597 char_u buf[2];
3598 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003600 if (get_tty_info(read_cmd_fd, &info) == OK)
3601 {
3602 intr_char = info.interrupt;
3603 buf[0] = info.backspace;
3604 buf[1] = NUL;
3605 add_termcode((char_u *)"kb", buf, FALSE);
3606
3607 /* If <BS> and <DEL> are now the same, redefine <DEL>. */
3608 p = find_termcode((char_u *)"kD");
3609 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3610 do_fixdel(NULL);
3611 }
3612}
3613
3614/*
3615 * Obtain the characters that Backspace and Enter produce on "fd".
3616 * Returns OK or FAIL.
3617 */
3618 int
3619get_tty_info(int fd, ttyinfo_T *info)
3620{
3621#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622# ifdef HAVE_TERMIOS_H
3623 struct termios keys;
3624# else
3625 struct termio keys;
3626# endif
3627
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003628 if (
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629# if defined(HAVE_TERMIOS_H)
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003630 tcgetattr(fd, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631# else
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003632 ioctl(fd, TCGETA, &keys) != -1
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633# endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003634 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003636 info->backspace = keys.c_cc[VERASE];
3637 info->interrupt = keys.c_cc[VINTR];
3638 if (keys.c_iflag & ICRNL)
3639 info->enter = NL;
3640 else
3641 info->enter = CAR;
3642 if (keys.c_oflag & ONLCR)
3643 info->nl_does_cr = TRUE;
3644 else
3645 info->nl_does_cr = FALSE;
3646 return OK;
3647 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648#else
3649 /* for "old" tty systems */
3650 struct sgttyb keys;
3651
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003652 if (ioctl(fd, TIOCGETP, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003654 info->backspace = keys.sg_erase;
3655 info->interrupt = keys.sg_kill;
3656 info->enter = CAR;
3657 info->nl_does_cr = TRUE;
3658 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003661 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662}
3663
3664#endif /* VMS */
3665
3666#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003667static int mouse_ison = FALSE;
3668
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669/*
3670 * Set mouse clicks on or off.
3671 */
3672 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003673mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674{
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003675# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003676 static int bevalterm_ison = FALSE;
3677# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 int xterm_mouse_vers;
3679
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003680 if (on == mouse_ison
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003681# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003682 && p_bevalterm == bevalterm_ison
3683# endif
3684 )
3685 /* return quickly if nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 return;
3687
3688 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003689
3690# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003691 if (ttym_flags == TTYM_URXVT)
3692 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003693 out_str_nf((char_u *)
3694 (on
3695 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3696 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003697 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003698 }
3699# endif
3700
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003701# ifdef FEAT_MOUSE_SGR
3702 if (ttym_flags == TTYM_SGR)
3703 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003704 /* SGR mode supports columns above 223 */
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003705 out_str_nf((char_u *)
3706 (on
3707 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3708 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003709 mouse_ison = on;
3710 }
3711# endif
3712
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003713# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003714 if (bevalterm_ison != (p_bevalterm && on))
3715 {
3716 bevalterm_ison = (p_bevalterm && on);
3717 if (xterm_mouse_vers > 1 && !bevalterm_ison)
3718 /* disable mouse movement events, enabling is below */
3719 out_str_nf((char_u *)
3720 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003721 }
3722# endif
3723
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 if (xterm_mouse_vers > 0)
3725 {
3726 if (on) /* enable mouse events, use mouse tracking if available */
3727 out_str_nf((char_u *)
3728 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003729 ? (
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003730# ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003731 bevalterm_ison
3732 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
3733# endif
3734 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3736 else /* disable mouse events, could probably always send the same */
3737 out_str_nf((char_u *)
3738 (xterm_mouse_vers > 1
3739 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3740 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003741 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742 }
3743
3744# ifdef FEAT_MOUSE_DEC
3745 else if (ttym_flags == TTYM_DEC)
3746 {
3747 if (on) /* enable mouse events */
3748 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3749 else /* disable mouse events */
3750 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003751 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752 }
3753# endif
3754
3755# ifdef FEAT_MOUSE_GPM
3756 else
3757 {
3758 if (on)
3759 {
3760 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003761 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 }
3763 else
3764 {
3765 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003766 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767 }
3768 }
3769# endif
3770
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003771# ifdef FEAT_SYSMOUSE
3772 else
3773 {
3774 if (on)
3775 {
3776 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003777 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003778 }
3779 else
3780 {
3781 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003782 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003783 }
3784 }
3785# endif
3786
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787# ifdef FEAT_MOUSE_JSB
3788 else
3789 {
3790 if (on)
3791 {
3792 /* D - Enable Mouse up/down messages
3793 * L - Enable Left Button Reporting
3794 * M - Enable Middle Button Reporting
3795 * R - Enable Right Button Reporting
3796 * K - Enable SHIFT and CTRL key Reporting
3797 * + - Enable Advanced messaging of mouse moves and up/down messages
3798 * Q - Quiet No Ack
3799 * # - Numeric value of mouse pointer required
3800 * 0 = Multiview 2000 cursor, used as standard
3801 * 1 = Windows Arrow
3802 * 2 = Windows I Beam
3803 * 3 = Windows Hour Glass
3804 * 4 = Windows Cross Hair
3805 * 5 = Windows UP Arrow
3806 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003807# ifdef JSBTERM_MOUSE_NONADVANCED
3808 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3810 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003811# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3813 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003814# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003815 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816 }
3817 else
3818 {
3819 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3820 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003821 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 }
3823 }
3824# endif
3825# ifdef FEAT_MOUSE_PTERM
3826 else
3827 {
3828 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3829 if (on)
3830 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3831 else
3832 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003833 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 }
3835# endif
3836}
3837
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003838#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003839/*
3840 * Called when 'balloonevalterm' changed.
3841 */
3842 void
3843mch_bevalterm_changed(void)
3844{
3845 mch_setmouse(mouse_ison);
3846}
3847#endif
3848
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849/*
3850 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3851 */
3852 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003853check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854{
3855# ifdef FEAT_MOUSE_XTERM
3856 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003857# ifdef FEAT_MOUSE_URXVT
3858 && use_xterm_mouse() != 3
3859# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860# ifdef FEAT_GUI
3861 && !gui.in_use
3862# endif
3863 )
3864 {
3865 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003866 ? IF_EB("\233M", CSI_STR "M")
3867 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 if (*p_mouse != NUL)
3869 {
3870 /* force mouse off and maybe on to send possibly new mouse
3871 * activation sequence to the xterm, with(out) drag tracing. */
3872 mch_setmouse(FALSE);
3873 setmouse();
3874 }
3875 }
3876 else
3877 del_mouse_termcode(KS_MOUSE);
3878# endif
3879
3880# ifdef FEAT_MOUSE_GPM
3881 if (!use_xterm_mouse()
3882# ifdef FEAT_GUI
3883 && !gui.in_use
3884# endif
3885 )
3886 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3887# endif
3888
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003889# ifdef FEAT_SYSMOUSE
3890 if (!use_xterm_mouse()
3891# ifdef FEAT_GUI
3892 && !gui.in_use
3893# endif
3894 )
3895 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3896# endif
3897
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898# ifdef FEAT_MOUSE_JSB
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003899 /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900 if (!use_xterm_mouse()
3901# ifdef FEAT_GUI
3902 && !gui.in_use
3903# endif
3904 )
3905 set_mouse_termcode(KS_JSBTERM_MOUSE,
3906 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3907 else
3908 del_mouse_termcode(KS_JSBTERM_MOUSE);
3909# endif
3910
3911# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003912 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 * define it in the GUI or when using an xterm. */
3914 if (!use_xterm_mouse()
3915# ifdef FEAT_GUI
3916 && !gui.in_use
3917# endif
3918 )
3919 set_mouse_termcode(KS_NETTERM_MOUSE,
3920 (char_u *)IF_EB("\033}", ESC_STR "}"));
3921 else
3922 del_mouse_termcode(KS_NETTERM_MOUSE);
3923# endif
3924
3925# ifdef FEAT_MOUSE_DEC
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003926 /* Conflicts with xterm mouse: "\033[" and "\033[M" */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003927 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928# ifdef FEAT_GUI
3929 && !gui.in_use
3930# endif
3931 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003932 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3933 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934 else
3935 del_mouse_termcode(KS_DEC_MOUSE);
3936# endif
3937# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003938 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003939 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940# ifdef FEAT_GUI
3941 && !gui.in_use
3942# endif
3943 )
3944 set_mouse_termcode(KS_PTERM_MOUSE,
3945 (char_u *) IF_EB("\033[", ESC_STR "["));
3946 else
3947 del_mouse_termcode(KS_PTERM_MOUSE);
3948# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003949# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003950 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003951# ifdef FEAT_GUI
3952 && !gui.in_use
3953# endif
3954 )
3955 {
3956 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003957 ? IF_EB("\233*M", CSI_STR "*M")
3958 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003959
3960 if (*p_mouse != NUL)
3961 {
3962 mch_setmouse(FALSE);
3963 setmouse();
3964 }
3965 }
3966 else
3967 del_mouse_termcode(KS_URXVT_MOUSE);
3968# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003969# ifdef FEAT_MOUSE_SGR
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003970 if (use_xterm_mouse() == 4
3971# ifdef FEAT_GUI
3972 && !gui.in_use
3973# endif
3974 )
3975 {
3976 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003977 ? IF_EB("\233<*M", CSI_STR "<*M")
3978 : IF_EB("\033[<*M", ESC_STR "[<*M")));
3979
3980 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
3981 ? IF_EB("\233<*m", CSI_STR "<*m")
3982 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003983
3984 if (*p_mouse != NUL)
3985 {
3986 mch_setmouse(FALSE);
3987 setmouse();
3988 }
3989 }
3990 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02003991 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003992 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02003993 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
3994 }
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003995# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996}
3997#endif
3998
3999/*
4000 * set screen mode, always fails.
4001 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004003mch_screenmode(char_u *arg UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004{
4005 EMSG(_(e_screenmode));
4006 return FAIL;
4007}
4008
4009#ifndef VMS
4010
4011/*
4012 * Try to get the current window size:
4013 * 1. with an ioctl(), most accurate method
4014 * 2. from the environment variables LINES and COLUMNS
4015 * 3. from the termcap
4016 * 4. keep using the old values
4017 * Return OK when size could be determined, FAIL otherwise.
4018 */
4019 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004020mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021{
4022 long rows = 0;
4023 long columns = 0;
4024 char_u *p;
4025
4026 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 * 1. try using an ioctl. It is the most accurate method.
4028 *
4029 * Try using TIOCGWINSZ first, some systems that have it also define
4030 * TIOCGSIZE but don't have a struct ttysize.
4031 */
4032# ifdef TIOCGWINSZ
4033 {
4034 struct winsize ws;
4035 int fd = 1;
4036
4037 /* When stdout is not a tty, use stdin for the ioctl(). */
4038 if (!isatty(fd) && isatty(read_cmd_fd))
4039 fd = read_cmd_fd;
4040 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4041 {
4042 columns = ws.ws_col;
4043 rows = ws.ws_row;
4044 }
4045 }
4046# else /* TIOCGWINSZ */
4047# ifdef TIOCGSIZE
4048 {
4049 struct ttysize ts;
4050 int fd = 1;
4051
4052 /* When stdout is not a tty, use stdin for the ioctl(). */
4053 if (!isatty(fd) && isatty(read_cmd_fd))
4054 fd = read_cmd_fd;
4055 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4056 {
4057 columns = ts.ts_cols;
4058 rows = ts.ts_lines;
4059 }
4060 }
4061# endif /* TIOCGSIZE */
4062# endif /* TIOCGWINSZ */
4063
4064 /*
4065 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004066 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4067 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004069 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070 {
4071 if ((p = (char_u *)getenv("LINES")))
4072 rows = atoi((char *)p);
4073 if ((p = (char_u *)getenv("COLUMNS")))
4074 columns = atoi((char *)p);
4075 }
4076
4077#ifdef HAVE_TGETENT
4078 /*
4079 * 3. try reading "co" and "li" entries from termcap
4080 */
4081 if (columns == 0 || rows == 0)
4082 getlinecol(&columns, &rows);
4083#endif
4084
4085 /*
4086 * 4. If everything fails, use the old values
4087 */
4088 if (columns <= 0 || rows <= 0)
4089 return FAIL;
4090
4091 Rows = rows;
4092 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004093 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 return OK;
4095}
4096
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004097#if defined(FEAT_TERMINAL) || defined(PROTO)
4098/*
4099 * Report the windows size "rows" and "cols" to tty "fd".
4100 */
4101 int
4102mch_report_winsize(int fd, int rows, int cols)
4103{
4104# ifdef TIOCSWINSZ
4105 struct winsize ws;
4106
4107 ws.ws_col = cols;
4108 ws.ws_row = rows;
4109 ws.ws_xpixel = cols * 5;
4110 ws.ws_ypixel = rows * 10;
4111 if (ioctl(fd, TIOCSWINSZ, &ws) == 0)
4112 {
4113 ch_log(NULL, "ioctl(TIOCSWINSZ) success");
4114 return OK;
4115 }
4116 ch_log(NULL, "ioctl(TIOCSWINSZ) failed");
4117# else
4118# ifdef TIOCSSIZE
4119 struct ttysize ts;
4120
4121 ts.ts_cols = cols;
4122 ts.ts_lines = rows;
4123 if (ioctl(fd, TIOCSSIZE, &ws) == 0)
4124 {
4125 ch_log(NULL, "ioctl(TIOCSSIZE) success");
4126 return OK;
4127 }
4128 ch_log(NULL, "ioctl(TIOCSSIZE) failed");
4129# endif
4130# endif
4131 return FAIL;
4132}
4133#endif
4134
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135/*
4136 * Try to set the window size to Rows and Columns.
4137 */
4138 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004139mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140{
4141 if (*T_CWS)
4142 {
4143 /*
4144 * NOTE: if you get an error here that term_set_winsize() is
4145 * undefined, check the output of configure. It could probably not
4146 * find a ncurses, termcap or termlib library.
4147 */
4148 term_set_winsize((int)Rows, (int)Columns);
4149 out_flush();
4150 screen_start(); /* don't know where cursor is now */
4151 }
4152}
4153
4154#endif /* VMS */
4155
4156/*
4157 * Rows and/or Columns has changed.
4158 */
4159 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004160mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161{
4162 /* Nothing to do. */
4163}
4164
Bram Moolenaar205b8862011-09-07 15:04:31 +02004165/*
4166 * Wait for process "child" to end.
4167 * Return "child" if it exited properly, <= 0 on error.
4168 */
4169 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004170wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004171{
4172 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004173 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004174
4175 while (wait_pid != child)
4176 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004177 /* When compiled with Python threads are probably used, in which case
4178 * wait() sometimes hangs for no obvious reason. Use waitpid()
4179 * instead and loop (like the GUI). Also needed for other interfaces,
4180 * they might call system(). */
4181# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004182 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004183# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004184 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004185# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004186 if (wait_pid == 0)
4187 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004188 /* Wait for 1 to 10 msec before trying again. */
4189 mch_delay(delay_msec, TRUE);
4190 if (++delay_msec > 10)
4191 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004192 continue;
4193 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004194 if (wait_pid <= 0
4195# ifdef ECHILD
4196 && errno == ECHILD
4197# endif
4198 )
4199 break;
4200 }
4201 return wait_pid;
4202}
4203
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004204#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004205/*
4206 * Set the environment for a child process.
4207 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004208 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004209set_child_environment(
4210 long rows,
4211 long columns,
4212 char *term,
4213 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004214{
4215# ifdef HAVE_SETENV
4216 char envbuf[50];
4217# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004218 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004219 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004220 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004221 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004222 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004223# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004224 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004225# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004226# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004227 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004228# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004229# endif
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004230 long colors =
4231# ifdef FEAT_GUI
4232 gui.in_use ? 256*256*256 :
4233# endif
4234 t_colors;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004235
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004236# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004237 setenv("TERM", term, 1);
4238 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004239 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004240 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004241 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004242 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004243 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004244 sprintf((char *)envbuf, "%ld", colors);
4245 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004246# ifdef FEAT_TERMINAL
4247 if (is_terminal)
4248 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004249 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004250 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4251 }
4252# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004253# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004254 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004255# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004256# else
4257 /*
4258 * Putenv does not copy the string, it has to remain valid.
4259 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004260 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004261 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004262 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4263 putenv(envbuf_Term);
4264 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004265 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004266 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4267 putenv(envbuf_Lines);
4268 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4269 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004270 putenv(envbuf_Columns);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004271 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors);
4272 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004273# ifdef FEAT_TERMINAL
4274 if (is_terminal)
4275 {
4276 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004277 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004278 putenv(envbuf_Version);
4279 }
4280# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004281# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004282 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4283 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4284 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004285# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004286# endif
4287}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004288
4289 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004290set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004291{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004292 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004293}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004294#endif
4295
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004296#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004297/*
4298 * Open a PTY, with FD for the master and slave side.
4299 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
4300 * When successful both file descriptors are stored.
4301 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004302 static void
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004303open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004304{
4305 char *tty_name;
4306
4307 *pty_master_fd = OpenPTY(&tty_name); /* open pty */
4308 if (*pty_master_fd >= 0)
4309 {
4310 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4311 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4312 * adding O_NOCTTY always works when defined. */
4313#ifdef O_NOCTTY
4314 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4315#else
4316 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4317#endif
4318 if (*pty_slave_fd < 0)
4319 {
4320 close(*pty_master_fd);
4321 *pty_master_fd = -1;
4322 }
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004323 else if (namep != NULL)
4324 *namep = vim_strsave((char_u *)tty_name);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004325 }
4326}
4327#endif
4328
Bram Moolenaarfae42832017-08-01 22:24:26 +02004329/*
4330 * Send SIGINT to a child process if "c" is an interrupt character.
4331 */
4332 void
4333may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4334{
4335# ifdef SIGINT
4336 if (c == Ctrl_C || c == intr_char)
4337 {
4338# ifdef HAVE_SETSID
4339 kill(-pid, SIGINT);
4340# else
4341 kill(0, SIGINT);
4342# endif
4343 if (wpid > 0)
4344 kill(wpid, SIGINT);
4345 }
4346# endif
4347}
4348
Bram Moolenaar13568252018-03-16 20:46:58 +01004349#if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL))
4350
4351 static int
4352build_argv(
4353 char_u *cmd,
4354 char ***argvp,
4355 char_u **sh_tofree,
4356 char_u **shcf_tofree)
4357{
4358 char **argv = NULL;
4359 int argc;
4360
4361 *sh_tofree = vim_strsave(p_sh);
4362 if (*sh_tofree == NULL) /* out of memory */
4363 return FAIL;
4364
4365 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4366 return FAIL;
4367 *argvp = argv;
4368
4369 if (cmd != NULL)
4370 {
4371 char_u *s;
4372 char_u *p;
4373
4374 if (extra_shell_arg != NULL)
4375 argv[argc++] = (char *)extra_shell_arg;
4376
4377 /* Break 'shellcmdflag' into white separated parts. This doesn't
4378 * handle quoted strings, they are very unlikely to appear. */
4379 *shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1);
4380 if (*shcf_tofree == NULL) /* out of memory */
4381 return FAIL;
4382 s = *shcf_tofree;
4383 p = p_shcf;
4384 while (*p != NUL)
4385 {
4386 argv[argc++] = (char *)s;
4387 while (*p && *p != ' ' && *p != TAB)
4388 *s++ = *p++;
4389 *s++ = NUL;
4390 p = skipwhite(p);
4391 }
4392
4393 argv[argc++] = (char *)cmd;
4394 }
4395 argv[argc] = NULL;
4396 return OK;
4397}
4398#endif
4399
4400#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4401/*
4402 * Use a terminal window to run a shell command in.
4403 */
4404 static int
4405mch_call_shell_terminal(
4406 char_u *cmd,
4407 int options UNUSED) /* SHELL_*, see vim.h */
4408{
4409 jobopt_T opt;
4410 char **argv = NULL;
4411 char_u *tofree1 = NULL;
4412 char_u *tofree2 = NULL;
4413 int retval = -1;
4414 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004415 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004416 aco_save_T aco;
4417 oparg_T oa; /* operator arguments */
4418
4419 if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
4420 goto theend;
4421
4422 init_job_options(&opt);
4423 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4424 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004425 if (buf == NULL)
4426 goto theend;
4427
4428 job = term_getjob(buf->b_term);
4429 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004430
4431 /* Find a window to make "buf" curbuf. */
4432 aucmd_prepbuf(&aco, buf);
4433
4434 clear_oparg(&oa);
4435 while (term_use_loop())
4436 {
4437 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4438 {
4439 /* If terminal_loop() returns OK we got a key that is handled
4440 * in Normal model. We don't do redrawing anyway. */
4441 if (terminal_loop(TRUE) == OK)
4442 normal_cmd(&oa, TRUE);
4443 }
4444 else
4445 normal_cmd(&oa, TRUE);
4446 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004447 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004448 ch_log(NULL, "system command finished");
4449
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004450 job_unref(job);
4451
Bram Moolenaar13568252018-03-16 20:46:58 +01004452 /* restore curwin/curbuf and a few other things */
4453 aucmd_restbuf(&aco);
4454
4455 wait_return(TRUE);
4456 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4457
4458theend:
4459 vim_free(argv);
4460 vim_free(tofree1);
4461 vim_free(tofree2);
4462 return retval;
4463}
4464#endif
4465
4466#ifdef USE_SYSTEM
4467/*
4468 * Use system() to start the shell: simple but slow.
4469 */
4470 static int
4471mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004472 char_u *cmd,
4473 int options) /* SHELL_*, see vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474{
4475#ifdef VMS
4476 char *ifn = NULL;
4477 char *ofn = NULL;
4478#endif
4479 int tmode = cur_tmode;
Bram Moolenaarb2b050a2016-07-16 21:52:46 +02004480 char_u *newcmd; /* only needed for unix */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004481 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482
4483 out_flush();
4484
4485 if (options & SHELL_COOKED)
4486 settmode(TMODE_COOK); /* set to normal mode */
4487
Bram Moolenaar62b42182010-09-21 22:09:37 +02004488# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004489 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004490 loose_clipboard();
4491# endif
4492
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 if (cmd == NULL)
4494 x = system((char *)p_sh);
4495 else
4496 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004497# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 if (ofn = strchr((char *)cmd, '>'))
4499 *ofn++ = '\0';
4500 if (ifn = strchr((char *)cmd, '<'))
4501 {
4502 char *p;
4503
4504 *ifn++ = '\0';
4505 p = strchr(ifn,' '); /* chop off any trailing spaces */
4506 if (p)
4507 *p = '\0';
4508 }
4509 if (ofn)
4510 x = vms_sys((char *)cmd, ofn, ifn);
4511 else
4512 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004513# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 newcmd = lalloc(STRLEN(p_sh)
4515 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
4516 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
4517 if (newcmd == NULL)
4518 x = 0;
4519 else
4520 {
4521 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4522 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4523 (char *)p_shcf,
4524 (char *)cmd);
4525 x = system((char *)newcmd);
4526 vim_free(newcmd);
4527 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004528# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 }
4530# ifdef VMS
4531 x = vms_sys_status(x);
4532# endif
4533 if (emsg_silent)
4534 ;
4535 else if (x == 127)
4536 MSG_PUTS(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 else if (x && !(options & SHELL_SILENT))
4538 {
4539 MSG_PUTS(_("\nshell returned "));
4540 msg_outnum((long)x);
4541 msg_putchar('\n');
4542 }
4543
4544 if (tmode == TMODE_RAW)
4545 settmode(TMODE_RAW); /* set to raw mode */
4546# ifdef FEAT_TITLE
4547 resettitle();
4548# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004549# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4550 restore_clipboard();
4551# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004553}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554
Bram Moolenaar13568252018-03-16 20:46:58 +01004555#else /* USE_SYSTEM */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556
Bram Moolenaardf177f62005-02-22 08:39:57 +00004557# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4558 127, some shells use that already */
Bram Moolenaarb109bb42017-08-21 21:07:29 +02004559# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560
Bram Moolenaar13568252018-03-16 20:46:58 +01004561/*
4562 * Don't use system(), use fork()/exec().
4563 */
4564 static int
4565mch_call_shell_fork(
4566 char_u *cmd,
4567 int options) /* SHELL_*, see vim.h */
4568{
4569 int tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004571 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 pid_t wait_pid = 0;
4573# ifdef HAVE_UNION_WAIT
4574 union wait status;
4575# else
4576 int status = -1;
4577# endif
4578 int retval = -1;
4579 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004580 char_u *tofree1 = NULL;
4581 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004584# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004586# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004587 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588 int fd_fromshell[2];
4589 int pipe_error = FALSE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004590 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591
4592 out_flush();
4593 if (options & SHELL_COOKED)
4594 settmode(TMODE_COOK); /* set to normal mode */
4595
Bram Moolenaar13568252018-03-16 20:46:58 +01004596 if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004597 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004598
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004600 * For the GUI, when writing the output into the buffer and when reading
4601 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4602 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004604 if ((options & (SHELL_READ|SHELL_WRITE))
4605# ifdef FEAT_GUI
4606 || (gui.in_use && show_shell_mess)
4607# endif
4608 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004610# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 /*
4612 * Try to open a master pty.
4613 * If this works, open the slave pty.
4614 * If the slave can't be opened, close the master pty.
4615 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004616 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02004617 open_pty(&pty_master_fd, &pty_slave_fd, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 /*
4619 * If not opening a pty or it didn't work, try using pipes.
4620 */
4621 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004622# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 {
4624 pipe_error = (pipe(fd_toshell) < 0);
4625 if (!pipe_error) /* pipe create OK */
4626 {
4627 pipe_error = (pipe(fd_fromshell) < 0);
4628 if (pipe_error) /* pipe create failed */
4629 {
4630 close(fd_toshell[0]);
4631 close(fd_toshell[1]);
4632 }
4633 }
4634 if (pipe_error)
4635 {
4636 MSG_PUTS(_("\nCannot create pipes\n"));
4637 out_flush();
4638 }
4639 }
4640 }
4641
4642 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004644 SIGSET_DECL(curset)
4645
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646# ifdef __BEOS__
4647 beos_cleanup_read_thread();
4648# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004649
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004650 BLOCK_SIGNALS(&curset);
4651 pid = fork(); /* maybe we should use vfork() */
4652 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004654 UNBLOCK_SIGNALS(&curset);
4655
Bram Moolenaar071d4272004-06-13 20:20:40 +00004656 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004657 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004659 || (gui.in_use && show_shell_mess)
4660# endif
4661 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004663# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 if (pty_master_fd >= 0) /* close the pseudo tty */
4665 {
4666 close(pty_master_fd);
4667 close(pty_slave_fd);
4668 }
4669 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004670# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 {
4672 close(fd_toshell[0]);
4673 close(fd_toshell[1]);
4674 close(fd_fromshell[0]);
4675 close(fd_fromshell[1]);
4676 }
4677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 }
4679 else if (pid == 0) /* child */
4680 {
4681 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004682 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683
Bram Moolenaar819524702018-02-27 19:10:00 +01004684# ifdef FEAT_JOB_CHANNEL
4685 if (ch_log_active())
4686 /* close the log file in the child */
4687 ch_logfile((char_u *)"", (char_u *)"");
4688# endif
4689
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 if (!show_shell_mess || (options & SHELL_EXPAND))
4691 {
4692 int fd;
4693
4694 /*
4695 * Don't want to show any message from the shell. Can't just
4696 * close stdout and stderr though, because some systems will
4697 * break if you try to write to them after that, so we must
4698 * use dup() to replace them with something else -- webb
4699 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4700 * waiting for input.
4701 */
4702 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4703 fclose(stdin);
4704 fclose(stdout);
4705 fclose(stderr);
4706
4707 /*
4708 * If any of these open()'s and dup()'s fail, we just continue
4709 * anyway. It's not fatal, and on most systems it will make
4710 * no difference at all. On a few it will cause the execvp()
4711 * to exit with a non-zero status even when the completion
4712 * could be done, which is nothing too serious. If the open()
4713 * or dup() failed we'd just do the same thing ourselves
4714 * anyway -- webb
4715 */
4716 if (fd >= 0)
4717 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004718 ignored = dup(fd); /* To replace stdin (fd 0) */
4719 ignored = dup(fd); /* To replace stdout (fd 1) */
4720 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721
4722 /* Don't need this now that we've duplicated it */
4723 close(fd);
4724 }
4725 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004726 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004728 || gui.in_use
4729# endif
4730 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 {
4732
Bram Moolenaardf177f62005-02-22 08:39:57 +00004733# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004734 /* Create our own process group, so that the child and all its
4735 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004736 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004737 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004738 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004739 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004740# if defined(SIGHUP)
4741 /* When doing "!xterm&" and 'shell' is bash: the shell
4742 * will exit and send SIGHUP to all processes in its
4743 * group, killing the just started process. Ignore SIGHUP
4744 * to avoid that. (suggested by Simon Schubert)
4745 */
4746 signal(SIGHUP, SIG_IGN);
4747# endif
4748 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004749# endif
4750# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004751 if (pty_slave_fd >= 0)
4752 {
4753 /* push stream discipline modules */
4754 if (options & SHELL_COOKED)
4755 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004757 /* Try to become controlling tty (probably doesn't work,
4758 * unless run by root) */
4759 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004761 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004762# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004763 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764
Bram Moolenaara5792f52005-11-23 21:25:05 +00004765 /*
4766 * stderr is only redirected when using the GUI, so that a
4767 * program like gpg can still access the terminal to get a
4768 * passphrase using stderr.
4769 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004770# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771 if (pty_master_fd >= 0)
4772 {
4773 close(pty_master_fd); /* close master side of pty */
4774
4775 /* set up stdin/stdout/stderr for the child */
4776 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004777 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004779 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004780 if (gui.in_use)
4781 {
4782 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004783 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004784 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785
4786 close(pty_slave_fd); /* has been dupped, close it now */
4787 }
4788 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004789# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004790 {
4791 /* set up stdin for the child */
4792 close(fd_toshell[1]);
4793 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004794 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 close(fd_toshell[0]);
4796
4797 /* set up stdout for the child */
4798 close(fd_fromshell[0]);
4799 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004800 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801 close(fd_fromshell[1]);
4802
Bram Moolenaara5792f52005-11-23 21:25:05 +00004803# ifdef FEAT_GUI
4804 if (gui.in_use)
4805 {
4806 /* set up stderr for the child */
4807 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004808 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004809 }
4810# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 }
4812 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004813
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814 /*
4815 * There is no type cast for the argv, because the type may be
4816 * different on different machines. This may cause a warning
4817 * message with strict compilers, don't worry about it.
4818 * Call _exit() instead of exit() to avoid closing the connection
4819 * to the X server (esp. with GTK, which uses atexit()).
4820 */
4821 execvp(argv[0], argv);
4822 _exit(EXEC_FAILED); /* exec failed, return failure code */
4823 }
4824 else /* parent */
4825 {
4826 /*
4827 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004828 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829 */
4830 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004831 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004832 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004833# ifdef FEAT_JOB_CHANNEL
4834 ++dont_check_job_ended;
4835# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 /*
4837 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004838 * This is also used to pipe stdin/stdout to/from the external
4839 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004841 if ((options & (SHELL_READ|SHELL_WRITE))
4842# ifdef FEAT_GUI
4843 || (gui.in_use && show_shell_mess)
4844# endif
4845 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004847# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004849# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004850 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004851# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4853 int ta_len = 0; /* valid bytes in ta_buf[] */
4854 int len;
4855 int p_more_save;
4856 int old_State;
4857 int c;
4858 int toshell_fd;
4859 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004860 garray_T ga;
4861 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004862# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4863 struct timeval start_tv;
4864# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865
Bram Moolenaardf177f62005-02-22 08:39:57 +00004866# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 if (pty_master_fd >= 0)
4868 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869 fromshell_fd = pty_master_fd;
4870 toshell_fd = dup(pty_master_fd);
4871 }
4872 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004873# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 {
4875 close(fd_toshell[0]);
4876 close(fd_fromshell[1]);
4877 toshell_fd = fd_toshell[1];
4878 fromshell_fd = fd_fromshell[0];
4879 }
4880
4881 /*
4882 * Write to the child if there are typed characters.
4883 * Read from the child if there are characters available.
4884 * Repeat the reading a few times if more characters are
4885 * available. Need to check for typed keys now and then, but
4886 * not too often (delays when no chars are available).
4887 * This loop is quit if no characters can be read from the pty
4888 * (WaitForChar detected special condition), or there are no
4889 * characters available and the child has exited.
4890 * Only check if the child has exited when there is no more
4891 * output. The child may exit before all the output has
4892 * been printed.
4893 *
4894 * Currently this busy loops!
4895 * This can probably dead-lock when the write blocks!
4896 */
4897 p_more_save = p_more;
4898 p_more = FALSE;
4899 old_State = State;
4900 State = EXTERNCMD; /* don't redraw at window resize */
4901
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004902 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004903 {
4904 /* Fork a process that will write the lines to the
4905 * external program. */
4906 if ((wpid = fork()) == -1)
4907 {
4908 MSG_PUTS(_("\nCannot fork\n"));
4909 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004910 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004911 {
4912 linenr_T lnum = curbuf->b_op_start.lnum;
4913 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004914 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004915 size_t l;
4916
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004917 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004918 for (;;)
4919 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004920 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004921 if (l == 0)
4922 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004923 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004924 /* NL -> NUL translation */
4925 len = write(toshell_fd, "", (size_t)1);
4926 else
4927 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004928 char_u *s = vim_strchr(lp + written, NL);
4929
Bram Moolenaar89d40322006-08-29 15:30:07 +00004930 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004931 s == NULL ? l
4932 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004933 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004934 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004935 {
4936 /* Finished a line, add a NL, unless this line
4937 * should not have one. */
4938 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004939 || (!curbuf->b_p_bin
4940 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004941 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004942 && (lnum !=
4943 curbuf->b_ml.ml_line_count
4944 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004945 ignored = write(toshell_fd, "\n",
4946 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004947 ++lnum;
4948 if (lnum > curbuf->b_op_end.lnum)
4949 {
4950 /* finished all the lines, close pipe */
4951 close(toshell_fd);
4952 toshell_fd = -1;
4953 break;
4954 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004955 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004956 written = 0;
4957 }
4958 else if (len > 0)
4959 written += len;
4960 }
4961 _exit(0);
4962 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004963 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004964 {
4965 close(toshell_fd);
4966 toshell_fd = -1;
4967 }
4968 }
4969
4970 if (options & SHELL_READ)
4971 ga_init2(&ga, 1, BUFLEN);
4972
4973 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004974# ifdef ELAPSED_FUNC
4975 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004976# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 for (;;)
4978 {
4979 /*
4980 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004981 * if there are any.
4982 * Don't do this if we are expanding wild cards (would eat
4983 * typeahead).
4984 * Don't do this when filtering and terminal is in cooked
4985 * mode, the shell command will handle the I/O. Avoids
4986 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004987 * Don't get characters when the child has already
4988 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004989 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004990 * while (noread_cnt > 4), avoids that ":r !ls" eats
4991 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992 */
4993 len = 0;
4994 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004995 && ((options &
4996 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4997 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004998# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004999 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005000# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005001 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005002 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005003 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005005 if (ta_len == 0)
5006 {
5007 /* Get extra characters when we don't have any.
5008 * Reset the counter and timer. */
5009 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005010# ifdef ELAPSED_FUNC
5011 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005012# endif
5013 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5014 }
5015 if (ta_len > 0 || len > 0)
5016 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 /*
5018 * For pipes:
5019 * Check for CTRL-C: send interrupt signal to child.
5020 * Check for CTRL-D: EOF, close pipe to child.
5021 */
5022 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5023 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024 /*
5025 * Send SIGINT to the child's group or all
5026 * processes in our group.
5027 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005028 may_send_sigint(ta_buf[ta_len], pid, wpid);
5029
Bram Moolenaar071d4272004-06-13 20:20:40 +00005030 if (pty_master_fd < 0 && toshell_fd >= 0
5031 && ta_buf[ta_len] == Ctrl_D)
5032 {
5033 close(toshell_fd);
5034 toshell_fd = -1;
5035 }
5036 }
5037
5038 /* replace K_BS by <BS> and K_DEL by <DEL> */
5039 for (i = ta_len; i < ta_len + len; ++i)
5040 {
5041 if (ta_buf[i] == CSI && len - i > 2)
5042 {
5043 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
5044 if (c == K_DEL || c == K_KDEL || c == K_BS)
5045 {
5046 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
5047 (size_t)(len - i - 2));
5048 if (c == K_DEL || c == K_KDEL)
5049 ta_buf[i] = DEL;
5050 else
5051 ta_buf[i] = Ctrl_H;
5052 len -= 2;
5053 }
5054 }
5055 else if (ta_buf[i] == '\r')
5056 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00005057# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00005059 i += (*mb_ptr2len_len)(ta_buf + i,
5060 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005061# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 }
5063
5064 /*
5065 * For pipes: echo the typed characters.
5066 * For a pty this does not seem to work.
5067 */
5068 if (pty_master_fd < 0)
5069 {
5070 for (i = ta_len; i < ta_len + len; ++i)
5071 {
5072 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5073 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005074# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075 else if (has_mbyte)
5076 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005077 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078
5079 msg_outtrans_len(ta_buf + i, l);
5080 i += l - 1;
5081 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005082# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083 else
5084 msg_outtrans_len(ta_buf + i, 1);
5085 }
5086 windgoto(msg_row, msg_col);
5087 out_flush();
5088 }
5089
5090 ta_len += len;
5091
5092 /*
5093 * Write the characters to the child, unless EOF has
5094 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005095 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005096 * When writing buffer lines, drop the typed
5097 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005099 if (options & SHELL_WRITE)
5100 ta_len = 0;
5101 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102 {
5103 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5104 if (len > 0)
5105 {
5106 ta_len -= len;
5107 mch_memmove(ta_buf, ta_buf + len, ta_len);
5108 }
5109 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005110 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 }
5112
Bram Moolenaardf177f62005-02-22 08:39:57 +00005113 if (got_int)
5114 {
5115 /* CTRL-C sends a signal to the child, we ignore it
5116 * ourselves */
5117# ifdef HAVE_SETSID
5118 kill(-pid, SIGINT);
5119# else
5120 kill(0, SIGINT);
5121# endif
5122 if (wpid > 0)
5123 kill(wpid, SIGINT);
5124 got_int = FALSE;
5125 }
5126
Bram Moolenaar071d4272004-06-13 20:20:40 +00005127 /*
5128 * Check if the child has any characters to be printed.
5129 * Read them and write them to our window. Repeat this as
5130 * long as there is something to do, avoid the 10ms wait
5131 * for mch_inchar(), or sending typeahead characters to
5132 * the external process.
5133 * TODO: This should handle escape sequences, compatible
5134 * to some terminal (vt52?).
5135 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005136 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005137 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005139 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00005140# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00005142# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00005144# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 );
5146 if (len <= 0) /* end of file or error */
5147 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005148
5149 noread_cnt = 0;
5150 if (options & SHELL_READ)
5151 {
5152 /* Do NUL -> NL translation, append NL separated
5153 * lines to the current buffer. */
5154 for (i = 0; i < len; ++i)
5155 {
5156 if (buffer[i] == NL)
5157 append_ga_line(&ga);
5158 else if (buffer[i] == NUL)
5159 ga_append(&ga, NL);
5160 else
5161 ga_append(&ga, buffer[i]);
5162 }
5163 }
5164# ifdef FEAT_MBYTE
5165 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166 {
5167 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005168 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169
Bram Moolenaardf177f62005-02-22 08:39:57 +00005170 len += buffer_off;
5171 buffer[len] = NUL;
5172
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173 /* Check if the last character in buffer[] is
5174 * incomplete, keep these bytes for the next
5175 * round. */
5176 for (p = buffer; p < buffer + len; p += l)
5177 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005178 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 if (l == 0)
5180 l = 1; /* NUL byte? */
5181 else if (MB_BYTE2LEN(*p) != l)
5182 break;
5183 }
5184 if (p == buffer) /* no complete character */
5185 {
5186 /* avoid getting stuck at an illegal byte */
5187 if (len >= 12)
5188 ++p;
5189 else
5190 {
5191 buffer_off = len;
5192 continue;
5193 }
5194 }
5195 c = *p;
5196 *p = NUL;
5197 msg_puts(buffer);
5198 if (p < buffer + len)
5199 {
5200 *p = c;
5201 buffer_off = (buffer + len) - p;
5202 mch_memmove(buffer, p, buffer_off);
5203 continue;
5204 }
5205 buffer_off = 0;
5206 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005207# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005209 {
5210 buffer[len] = NUL;
5211 msg_puts(buffer);
5212 }
5213
5214 windgoto(msg_row, msg_col);
5215 cursor_on();
5216 out_flush();
5217 if (got_int)
5218 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005219
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005220# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005221 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005222 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005223 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005224
5225 /* Avoid that we keep looping here without
5226 * checking for a CTRL-C for a long time. Don't
5227 * break out too often to avoid losing typeahead. */
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005228 if (msec > 2000)
5229 {
5230 noread_cnt = 5;
5231 break;
5232 }
5233 }
5234# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235 }
5236
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005237 /* If we already detected the child has finished, continue
5238 * reading output for a short while. Some text may be
5239 * buffered. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005240 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005241 {
5242 if (noread_cnt < 5)
5243 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005244 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005245 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005246
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 /*
5248 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005249 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005251# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005252 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005253# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005255# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5257 || (wait_pid == pid && WIFEXITED(status)))
5258 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005259 /* Don't break the loop yet, try reading more
5260 * characters from "fromshell_fd" first. When using
5261 * pipes there might still be something to read and
5262 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005265 else
5266 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005267
Bram Moolenaar95a51352013-03-21 22:53:50 +01005268# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005269 /* Handle any X events, e.g. serving the clipboard. */
5270 clip_update();
5271# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272 }
5273finished:
5274 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005275 if (options & SHELL_READ)
5276 {
5277 if (ga.ga_len > 0)
5278 {
5279 append_ga_line(&ga);
5280 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005281 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005282 }
5283 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005284 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005285 ga_clear(&ga);
5286 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005287
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 /*
5289 * Give all typeahead that wasn't used back to ui_inchar().
5290 */
5291 if (ta_len)
5292 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293 State = old_State;
5294 if (toshell_fd >= 0)
5295 close(toshell_fd);
5296 close(fromshell_fd);
5297 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005298# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005299 else
5300 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005301 long delay_msec = 1;
5302
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005303 /*
5304 * Similar to the loop above, but only handle X events, no
5305 * I/O.
5306 */
5307 for (;;)
5308 {
5309 if (got_int)
5310 {
5311 /* CTRL-C sends a signal to the child, we ignore it
5312 * ourselves */
5313# ifdef HAVE_SETSID
5314 kill(-pid, SIGINT);
5315# else
5316 kill(0, SIGINT);
5317# endif
5318 got_int = FALSE;
5319 }
5320# ifdef __NeXT__
5321 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5322# else
5323 wait_pid = waitpid(pid, &status, WNOHANG);
5324# endif
5325 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5326 || (wait_pid == pid && WIFEXITED(status)))
5327 {
5328 wait_pid = pid;
5329 break;
5330 }
5331
5332 /* Handle any X events, e.g. serving the clipboard. */
5333 clip_update();
5334
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005335 /* Wait for 1 to 10 msec. 1 is faster but gives the child
5336 * less time. */
5337 mch_delay(delay_msec, TRUE);
5338 if (++delay_msec > 10)
5339 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005340 }
5341 }
5342# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005343
5344 /*
5345 * Wait until our child has exited.
5346 * Ignore wait() returning pids of other children and returning
5347 * because of some signal like SIGWINCH.
5348 * Don't wait if wait_pid was already set above, indicating the
5349 * child already exited.
5350 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005351 if (wait_pid != pid)
5352 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353
Bram Moolenaar624891f2010-10-13 16:22:09 +02005354# ifdef FEAT_GUI
5355 /* Close slave side of pty. Only do this after the child has
5356 * exited, otherwise the child may hang when it tries to write on
5357 * the pty. */
5358 if (pty_master_fd >= 0)
5359 close(pty_slave_fd);
5360# endif
5361
Bram Moolenaardf177f62005-02-22 08:39:57 +00005362 /* Make sure the child that writes to the external program is
5363 * dead. */
5364 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005365 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005366 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005367 wait4pid(wpid, NULL);
5368 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005369
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005370# ifdef FEAT_JOB_CHANNEL
5371 --dont_check_job_ended;
5372# endif
5373
Bram Moolenaar071d4272004-06-13 20:20:40 +00005374 /*
5375 * Set to raw mode right now, otherwise a CTRL-C after
5376 * catch_signals() will kill Vim.
5377 */
5378 if (tmode == TMODE_RAW)
5379 settmode(TMODE_RAW);
5380 did_settmode = TRUE;
5381 set_signals();
5382
5383 if (WIFEXITED(status))
5384 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00005385 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005386 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005387 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005388 {
5389 if (retval == EXEC_FAILED)
5390 {
5391 MSG_PUTS(_("\nCannot execute shell "));
5392 msg_outtrans(p_sh);
5393 msg_putchar('\n');
5394 }
5395 else if (!(options & SHELL_SILENT))
5396 {
5397 MSG_PUTS(_("\nshell returned "));
5398 msg_outnum((long)retval);
5399 msg_putchar('\n');
5400 }
5401 }
5402 }
5403 else
5404 MSG_PUTS(_("\nCommand terminated\n"));
5405 }
5406 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407
5408error:
5409 if (!did_settmode)
5410 if (tmode == TMODE_RAW)
5411 settmode(TMODE_RAW); /* set to raw mode */
5412# ifdef FEAT_TITLE
5413 resettitle();
5414# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005415 vim_free(argv);
5416 vim_free(tofree1);
5417 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005418
5419 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005420}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005421#endif /* USE_SYSTEM */
Bram Moolenaar13568252018-03-16 20:46:58 +01005422
5423 int
5424mch_call_shell(
5425 char_u *cmd,
5426 int options) /* SHELL_*, see vim.h */
5427{
5428#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5429 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5430 return mch_call_shell_terminal(cmd, options);
5431#endif
5432#ifdef USE_SYSTEM
5433 return mch_call_shell_system(cmd, options);
5434#else
5435 return mch_call_shell_fork(cmd, options);
5436#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005437}
5438
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005439#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005440 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005441mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005442{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005443 pid_t pid;
Bram Moolenaar7c9aec42017-08-03 13:51:25 +02005444 int fd_in[2] = {-1, -1}; /* for stdin */
5445 int fd_out[2] = {-1, -1}; /* for stdout */
5446 int fd_err[2] = {-1, -1}; /* for stderr */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005447 int pty_master_fd = -1;
5448 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005449 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005450 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5451 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5452 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005453 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005454 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5455 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005456 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005457 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005458 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005459
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005460 if (use_out_for_err && use_null_for_out)
5461 use_null_for_err = TRUE;
5462
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005463 /* default is to fail */
5464 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005465
Bram Moolenaarb2412082017-08-20 18:09:14 +02005466 if (options->jo_pty
5467 && (!(use_file_for_in || use_null_for_in)
5468 || !(use_file_for_in || use_null_for_out)
5469 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005470 {
5471 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5472 if (job->jv_tty_out != NULL)
5473 job->jv_tty_in = vim_strsave(job->jv_tty_out);
5474 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005475
Bram Moolenaar12dcf022016-02-15 23:09:04 +01005476 /* TODO: without the channel feature connect the child to /dev/null? */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005477 /* Open pipes for stdin, stdout, stderr. */
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005478 if (use_file_for_in)
5479 {
5480 char_u *fname = options->jo_io_name[PART_IN];
5481
5482 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5483 if (fd_in[0] < 0)
5484 {
5485 EMSG2(_(e_notopen), fname);
5486 goto failed;
5487 }
5488 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005489 else
5490 /* When writing buffer lines to the input don't use the pty, so that
5491 * the pipe can be closed when all lines were written. */
5492 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5493 && pipe(fd_in) < 0)
5494 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005495
5496 if (use_file_for_out)
5497 {
5498 char_u *fname = options->jo_io_name[PART_OUT];
5499
5500 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5501 if (fd_out[1] < 0)
5502 {
5503 EMSG2(_(e_notopen), fname);
5504 goto failed;
5505 }
5506 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005507 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005508 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005509
5510 if (use_file_for_err)
5511 {
5512 char_u *fname = options->jo_io_name[PART_ERR];
5513
5514 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5515 if (fd_err[1] < 0)
5516 {
5517 EMSG2(_(e_notopen), fname);
5518 goto failed;
5519 }
5520 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005521 else if (!use_out_for_err && !use_null_for_err
5522 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005523 goto failed;
5524
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005525 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5526 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005527 if (options->jo_set & JO_CHANNEL)
5528 {
5529 channel = options->jo_channel;
5530 if (channel != NULL)
5531 ++channel->ch_refcount;
5532 }
5533 else
5534 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005535 if (channel == NULL)
5536 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005537 if (job->jv_tty_out != NULL)
5538 ch_log(channel, "using pty %s on fd %d",
5539 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005540 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005541
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005542 BLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005543 pid = fork(); /* maybe we should use vfork() */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005544 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005545 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005546 /* failed to fork */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005547 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005548 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005549 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005550 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005551 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005552 int null_fd = -1;
5553 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005554
Bram Moolenaar835dc632016-02-07 14:27:38 +01005555 /* child */
5556 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005557 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005558
Bram Moolenaar819524702018-02-27 19:10:00 +01005559# ifdef FEAT_JOB_CHANNEL
5560 if (ch_log_active())
5561 /* close the log file in the child */
5562 ch_logfile((char_u *)"", (char_u *)"");
5563# endif
5564
Bram Moolenaar835dc632016-02-07 14:27:38 +01005565# ifdef HAVE_SETSID
5566 /* Create our own process group, so that the child and all its
5567 * children can be kill()ed. Don't do this when using pipes,
5568 * because stdin is not a tty, we would lose /dev/tty. */
5569 (void)setsid();
5570# endif
5571
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005572# ifdef FEAT_TERMINAL
5573 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005574 {
5575 char *term = (char *)T_NAME;
5576
5577#ifdef FEAT_GUI
5578 if (term_is_gui(T_NAME))
5579 /* In the GUI 'term' is not what we want, use $TERM. */
5580 term = getenv("TERM");
5581#endif
5582 /* Use 'term' or $TERM if it starts with "xterm", otherwise fall
5583 * back to "xterm". */
5584 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
5585 term = "xterm";
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005586 set_child_environment(
5587 (long)options->jo_term_rows,
5588 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005589 term,
5590 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005591 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005592 else
5593# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005594 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005595
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005596 if (options->jo_env != NULL)
5597 {
5598 dict_T *dict = options->jo_env;
5599 hashitem_T *hi;
5600 int todo = (int)dict->dv_hashtab.ht_used;
5601
5602 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5603 if (!HASHITEM_EMPTY(hi))
5604 {
5605 typval_T *item = &dict_lookup(hi)->di_tv;
5606
5607 vim_setenv((char_u*)hi->hi_key, get_tv_string(item));
5608 --todo;
5609 }
5610 }
5611
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005612 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005613 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005614 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005615 if (null_fd < 0)
5616 {
5617 perror("opening /dev/null failed");
5618 _exit(OPEN_NULL_FAILED);
5619 }
5620 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005621
Bram Moolenaar223896d2017-08-02 22:33:28 +02005622 if (pty_slave_fd >= 0)
5623 {
5624 /* push stream discipline modules */
5625 SetupSlavePTY(pty_slave_fd);
5626# ifdef TIOCSCTTY
5627 /* Try to become controlling tty (probably doesn't work,
5628 * unless run by root) */
5629 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5630# endif
5631 }
5632
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005633 /* set up stdin for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005634 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005635 if (use_null_for_in && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005636 ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005637 else if (fd_in[0] < 0)
5638 ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005639 else
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005640 ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005641
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005642 /* set up stderr for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005643 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005644 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005645 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005646 ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005647 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005648 }
5649 else if (use_out_for_err)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005650 ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005651 else if (fd_err[1] < 0)
5652 ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005653 else
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005654 ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005655
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005656 /* set up stdout for the child */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005657 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005658 if (use_null_for_out && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005659 ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005660 else if (fd_out[1] < 0)
5661 ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005662 else
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005663 ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005664
5665 if (fd_in[0] >= 0)
5666 close(fd_in[0]);
5667 if (fd_in[1] >= 0)
5668 close(fd_in[1]);
5669 if (fd_out[0] >= 0)
5670 close(fd_out[0]);
5671 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005672 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005673 if (fd_err[0] >= 0)
5674 close(fd_err[0]);
5675 if (fd_err[1] >= 0)
5676 close(fd_err[1]);
5677 if (pty_master_fd >= 0)
5678 {
Bram Moolenaar223896d2017-08-02 22:33:28 +02005679 close(pty_master_fd); /* not used in the child */
5680 close(pty_slave_fd); /* was duped above */
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005681 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005682
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005683 if (null_fd >= 0)
5684 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005685
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005686 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5687 _exit(EXEC_FAILED);
5688
Bram Moolenaar835dc632016-02-07 14:27:38 +01005689 /* See above for type of argv. */
5690 execvp(argv[0], argv);
5691
Bram Moolenaar4694a172016-04-21 14:05:23 +02005692 if (stderr_works)
5693 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005694# ifdef EXITFREE
Bram Moolenaarcda77642016-06-04 13:32:35 +02005695 /* calling free_all_mem() here causes problems. Ignore valgrind
5696 * reporting possibly leaked memory. */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005697# endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005698 _exit(EXEC_FAILED); /* exec failed, return failure code */
5699 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005700
5701 /* parent */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005702 UNBLOCK_SIGNALS(&curset);
5703
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005704 job->jv_pid = pid;
5705 job->jv_status = JOB_STARTED;
Bram Moolenaarde279892016-03-11 22:19:44 +01005706 job->jv_channel = channel; /* ch_refcount was set above */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005707
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005708 if (pty_master_fd >= 0)
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005709 close(pty_slave_fd); /* not used in the parent */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005710 /* close child stdin, stdout and stderr */
Bram Moolenaar819524702018-02-27 19:10:00 +01005711 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005712 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005713 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005714 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005715 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005716 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005717 if (channel != NULL)
5718 {
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005719 int in_fd = use_file_for_in || use_null_for_in
5720 ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1];
5721 int out_fd = use_file_for_out || use_null_for_out
5722 ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0];
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005723 /* When using pty_master_fd only set it for stdout, do not duplicate it
5724 * for stderr, it only needs to be read once. */
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005725 int err_fd = use_out_for_err || use_file_for_err || use_null_for_err
Bram Moolenaarcd8fb442018-05-12 17:42:42 +02005726 ? INVALID_FD
5727 : fd_err[0] >= 0
5728 ? fd_err[0]
5729 : (out_fd == pty_master_fd
5730 ? INVALID_FD
5731 : pty_master_fd);
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005732
5733 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005734 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005735 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005736 else
5737 {
5738 if (fd_in[1] >= 0)
5739 close(fd_in[1]);
5740 if (fd_out[0] >= 0)
5741 close(fd_out[0]);
5742 if (fd_err[0] >= 0)
5743 close(fd_err[0]);
5744 if (pty_master_fd >= 0)
5745 close(pty_master_fd);
5746 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005747
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005748 /* success! */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005749 return;
5750
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005751failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005752 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005753 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005754 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005755 if (fd_in[1] >= 0)
5756 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005757 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005758 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005759 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005760 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005761 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005762 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005763 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005764 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005765 if (pty_master_fd >= 0)
5766 close(pty_master_fd);
5767 if (pty_slave_fd >= 0)
5768 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005769}
5770
5771 char *
5772mch_job_status(job_T *job)
5773{
5774# ifdef HAVE_UNION_WAIT
5775 union wait status;
5776# else
5777 int status = -1;
5778# endif
5779 pid_t wait_pid = 0;
5780
5781# ifdef __NeXT__
5782 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5783# else
5784 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5785# endif
5786 if (wait_pid == -1)
5787 {
5788 /* process must have exited */
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005789 if (job->jv_status < JOB_ENDED)
5790 ch_log(job->jv_channel, "Job no longer exists: %s",
5791 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005792 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005793 }
5794 if (wait_pid == 0)
5795 return "run";
5796 if (WIFEXITED(status))
5797 {
5798 /* LINTED avoid "bitwise operation on signed value" */
5799 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005800 if (job->jv_status < JOB_ENDED)
5801 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005802 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005803 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005804 if (WIFSIGNALED(status))
5805 {
5806 job->jv_exitval = -1;
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005807 if (job->jv_status < JOB_ENDED)
5808 ch_log(job->jv_channel, "Job terminated by a signal");
Bram Moolenaar97792de2016-10-15 18:36:49 +02005809 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005810 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005811 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005812
5813return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005814 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005815 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005816 return "dead";
5817}
5818
5819 job_T *
5820mch_detect_ended_job(job_T *job_list)
5821{
5822# ifdef HAVE_UNION_WAIT
5823 union wait status;
5824# else
5825 int status = -1;
5826# endif
5827 pid_t wait_pid = 0;
5828 job_T *job;
5829
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005830# ifndef USE_SYSTEM
5831 /* Do not do this when waiting for a shell command to finish, we would get
5832 * the exit value here (and discard it), the exit value obtained there
5833 * would then be wrong. */
5834 if (dont_check_job_ended > 0)
5835 return NULL;
5836# endif
5837
Bram Moolenaar97792de2016-10-15 18:36:49 +02005838# ifdef __NeXT__
5839 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5840# else
5841 wait_pid = waitpid(-1, &status, WNOHANG);
5842# endif
5843 if (wait_pid <= 0)
5844 /* no process ended */
5845 return NULL;
5846 for (job = job_list; job != NULL; job = job->jv_next)
5847 {
5848 if (job->jv_pid == wait_pid)
5849 {
5850 if (WIFEXITED(status))
5851 /* LINTED avoid "bitwise operation on signed value" */
5852 job->jv_exitval = WEXITSTATUS(status);
5853 else if (WIFSIGNALED(status))
5854 job->jv_exitval = -1;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005855 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005856 {
5857 ch_log(job->jv_channel, "Job ended");
5858 job->jv_status = JOB_ENDED;
5859 }
5860 return job;
5861 }
5862 }
5863 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005864}
5865
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005866/*
5867 * Send a (deadly) signal to "job".
5868 * Return FAIL if "how" is not a valid name.
5869 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005870 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005871mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005872{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005873 int sig = -1;
5874 pid_t job_pid;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005875
Bram Moolenaar923d9262016-02-25 20:56:01 +01005876 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005877 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005878 else if (STRCMP(how, "hup") == 0)
5879 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005880 else if (STRCMP(how, "quit") == 0)
5881 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005882 else if (STRCMP(how, "int") == 0)
5883 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005884 else if (STRCMP(how, "kill") == 0)
5885 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005886#ifdef SIGWINCH
5887 else if (STRCMP(how, "winch") == 0)
5888 sig = SIGWINCH;
5889#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005890 else if (isdigit(*how))
5891 sig = atoi((char *)how);
5892 else
5893 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005894
Bram Moolenaar72801402016-02-09 11:37:50 +01005895 /* TODO: have an option to only kill the process, not the group? */
Bram Moolenaar76467df2016-02-12 19:30:26 +01005896 job_pid = job->jv_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005897#ifdef HAVE_GETPGID
Bram Moolenaar76467df2016-02-12 19:30:26 +01005898 if (job_pid == getpgid(job_pid))
5899 job_pid = -job_pid;
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01005900#endif
Bram Moolenaar76467df2016-02-12 19:30:26 +01005901
Bram Moolenaar61a66052017-07-22 18:39:00 +02005902 /* Never kill ourselves! */
5903 if (job_pid != 0)
5904 kill(job_pid, sig);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005905
Bram Moolenaar835dc632016-02-07 14:27:38 +01005906 return OK;
5907}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005908
5909/*
5910 * Clear the data related to "job".
5911 */
5912 void
5913mch_clear_job(job_T *job)
5914{
5915 /* call waitpid because child process may become zombie */
5916# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005917 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005918# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005919 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005920# endif
5921}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005922#endif
5923
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005924#if defined(FEAT_TERMINAL) || defined(PROTO)
5925 int
5926mch_create_pty_channel(job_T *job, jobopt_T *options)
5927{
5928 int pty_master_fd = -1;
5929 int pty_slave_fd = -1;
5930 channel_T *channel;
5931
Bram Moolenaar2dc9d262017-09-08 14:39:30 +02005932 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
5933 if (job->jv_tty_out != NULL)
5934 job->jv_tty_in = vim_strsave(job->jv_tty_out);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005935 close(pty_slave_fd);
5936
5937 channel = add_channel();
5938 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005939 {
5940 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005941 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005942 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005943 if (job->jv_tty_out != NULL)
5944 ch_log(channel, "using pty %s on fd %d",
5945 job->jv_tty_out, pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005946 job->jv_channel = channel; /* ch_refcount was set by add_channel() */
5947 channel->ch_keep_open = TRUE;
5948
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005949 /* Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5950 * it only needs to be read once. */
5951 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005952 channel_set_job(channel, job, options);
5953 return OK;
5954}
5955#endif
5956
Bram Moolenaar071d4272004-06-13 20:20:40 +00005957/*
5958 * Check for CTRL-C typed by reading all available characters.
5959 * In cooked mode we should get SIGINT, no need to check.
5960 */
5961 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005962mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005963{
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005964 if ((curr_tmode == TMODE_RAW || force)
5965 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005966 fill_input_buf(FALSE);
5967}
5968
5969/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005970 * Wait "msec" msec until a character is available from the mouse, keyboard,
5971 * from inbuf[].
5972 * "msec" == -1 will block forever.
5973 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005974 * When "ignore_input" is TRUE even check for pending input when input is
5975 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005976 * "interrupted" (if not NULL) is set to TRUE when no character is available
5977 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005978 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005979 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980 */
5981 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005982WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005983{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005984#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01005985 return ui_wait_for_chars_or_timer(
5986 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005987#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005988 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005989#endif
5990}
5991
5992/*
5993 * Wait "msec" msec until a character is available from the mouse or keyboard
5994 * or from inbuf[].
5995 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005996 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02005997 * "interrupted" (if not NULL) is set to TRUE when no character is available
5998 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005999 * When a GUI is being used, this will never get called -- webb
6000 */
6001 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006002WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006003{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006004#ifdef FEAT_MOUSE_GPM
6005 int gpm_process_wanted;
6006#endif
6007#ifdef FEAT_XCLIPBOARD
6008 int rest;
6009#endif
6010 int avail;
6011
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006012 if (!ignore_input && input_available()) /* something in inbuf[] */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006013 return 1;
6014
6015#if defined(FEAT_MOUSE_DEC)
6016 /* May need to query the mouse position. */
6017 if (WantQueryMouse)
6018 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006019 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
6021 }
6022#endif
6023
6024 /*
6025 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6026 * events. This is a bit complicated, because they might both be defined.
6027 */
6028#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6029# ifdef FEAT_XCLIPBOARD
6030 rest = 0;
6031 if (do_xterm_trace())
6032 rest = msec;
6033# endif
6034 do
6035 {
6036# ifdef FEAT_XCLIPBOARD
6037 if (rest != 0)
6038 {
6039 msec = XT_TRACE_DELAY;
6040 if (rest >= 0 && rest < XT_TRACE_DELAY)
6041 msec = rest;
6042 if (rest >= 0)
6043 rest -= msec;
6044 }
6045# endif
6046# ifdef FEAT_MOUSE_GPM
6047 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006048 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006049 &gpm_process_wanted, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006051 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006052# endif
6053 if (!avail)
6054 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006055 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006056 return 1;
6057# ifdef FEAT_XCLIPBOARD
6058 if (rest == 0 || !do_xterm_trace())
6059# endif
6060 break;
6061 }
6062 }
6063 while (FALSE
6064# ifdef FEAT_MOUSE_GPM
6065 || (gpm_process_wanted && mch_gpm_process() == 0)
6066# endif
6067# ifdef FEAT_XCLIPBOARD
6068 || (!avail && rest != 0)
6069# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006070 )
6071 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072
6073#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006074 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006075#endif
6076 return avail;
6077}
6078
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006079#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006080/*
6081 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006082 * "msec" == 0 will check for characters once.
6083 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006085 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006086 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006087 * "interrupted" (if not NULL) is set to TRUE when no character is available
6088 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006089 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006090#if defined(__BEOS__)
6091 int
6092#else
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006093 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006095RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096{
6097 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006098 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006099#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100 static int busy = FALSE;
6101
6102 /* May retry getting characters after an event was handled. */
6103# define MAY_LOOP
6104
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006105# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006106 /* Remember at what time we started, so that we know how much longer we
6107 * should wait after being interrupted. */
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006108 long start_msec = msec;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006109 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006110
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006111 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006112 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006113# endif
6114
6115 /* Handle being called recursively. This may happen for the session
6116 * manager stuff, it may save the file, which does a breakcheck. */
6117 if (busy)
6118 return 0;
6119#endif
6120
6121#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006122 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123#endif
6124 {
6125#ifdef MAY_LOOP
6126 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006127# ifdef FEAT_MZSCHEME
6128 int mzquantum_used = FALSE;
6129# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130#endif
6131#ifndef HAVE_SELECT
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006132 /* each channel may use in, out and err */
6133 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134 int nfd;
6135# ifdef FEAT_XCLIPBOARD
6136 int xterm_idx = -1;
6137# endif
6138# ifdef FEAT_MOUSE_GPM
6139 int gpm_idx = -1;
6140# endif
6141# ifdef USE_XSMP
6142 int xsmp_idx = -1;
6143# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006144 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006145
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006146# ifdef FEAT_MZSCHEME
6147 mzvim_check_threads();
6148 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6149 {
6150 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
6151 mzquantum_used = TRUE;
6152 }
6153# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006154 fds[0].fd = fd;
6155 fds[0].events = POLLIN;
6156 nfd = 1;
6157
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006159 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160 if (xterm_Shell != (Widget)0)
6161 {
6162 xterm_idx = nfd;
6163 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6164 fds[nfd].events = POLLIN;
6165 nfd++;
6166 }
6167# endif
6168# ifdef FEAT_MOUSE_GPM
6169 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6170 {
6171 gpm_idx = nfd;
6172 fds[nfd].fd = gpm_fd;
6173 fds[nfd].events = POLLIN;
6174 nfd++;
6175 }
6176# endif
6177# ifdef USE_XSMP
6178 if (xsmp_icefd != -1)
6179 {
6180 xsmp_idx = nfd;
6181 fds[nfd].fd = xsmp_icefd;
6182 fds[nfd].events = POLLIN;
6183 nfd++;
6184 }
6185# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006186#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006187 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006188#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006189 if (interrupted != NULL)
6190 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006191
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006192 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006193
6194 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006195 if (result == 0 && interrupted != NULL && ret > 0)
6196 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006197
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006198# ifdef FEAT_MZSCHEME
6199 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006200 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006201 finished = FALSE;
6202# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204# ifdef FEAT_XCLIPBOARD
6205 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6206 {
6207 xterm_update(); /* Maybe we should hand out clipboard */
6208 if (--ret == 0 && !input_available())
6209 /* Try again */
6210 finished = FALSE;
6211 }
6212# endif
6213# ifdef FEAT_MOUSE_GPM
6214 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
6215 {
6216 *check_for_gpm = 1;
6217 }
6218# endif
6219# ifdef USE_XSMP
6220 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6221 {
6222 if (fds[xsmp_idx].revents & POLLIN)
6223 {
6224 busy = TRUE;
6225 xsmp_handle_requests();
6226 busy = FALSE;
6227 }
6228 else if (fds[xsmp_idx].revents & POLLHUP)
6229 {
6230 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006231 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006232 xsmp_close();
6233 }
6234 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006235 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006236 }
6237# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006238#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006239 /* also call when ret == 0, we may be polling a keep-open channel */
6240 if (ret >= 0)
Bram Moolenaare0874f82016-01-24 20:36:41 +01006241 ret = channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006242#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006243
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244#else /* HAVE_SELECT */
6245
6246 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006247 struct timeval *tvp;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006248 fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006250 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006252# ifdef FEAT_MZSCHEME
6253 mzvim_check_threads();
6254 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6255 {
6256 towait = p_mzq; /* don't wait longer than 'mzquantum' */
6257 mzquantum_used = TRUE;
6258 }
6259# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006260
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006261 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006262 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006263 tv.tv_sec = towait / 1000;
6264 tv.tv_usec = (towait % 1000) * (1000000/1000);
6265 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006266 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006267 else
6268 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006269
6270 /*
6271 * Select on ready for reading and exceptional condition (end of file).
6272 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006273select_eintr:
6274 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006275 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006276 FD_ZERO(&efds);
6277 FD_SET(fd, &rfds);
6278# if !defined(__QNX__) && !defined(__CYGWIN32__)
6279 /* For QNX select() always returns 1 if this is set. Why? */
6280 FD_SET(fd, &efds);
6281# endif
6282 maxfd = fd;
6283
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006285 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006286 if (xterm_Shell != (Widget)0)
6287 {
6288 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6289 if (maxfd < ConnectionNumber(xterm_dpy))
6290 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006291
6292 /* An event may have already been read but not handled. In
6293 * particulary, XFlush may cause this. */
6294 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006295 }
6296# endif
6297# ifdef FEAT_MOUSE_GPM
6298 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6299 {
6300 FD_SET(gpm_fd, &rfds);
6301 FD_SET(gpm_fd, &efds);
6302 if (maxfd < gpm_fd)
6303 maxfd = gpm_fd;
6304 }
6305# endif
6306# ifdef USE_XSMP
6307 if (xsmp_icefd != -1)
6308 {
6309 FD_SET(xsmp_icefd, &rfds);
6310 FD_SET(xsmp_icefd, &efds);
6311 if (maxfd < xsmp_icefd)
6312 maxfd = xsmp_icefd;
6313 }
6314# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006315# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006316 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006317# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006318 if (interrupted != NULL)
6319 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006321 ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006322 result = ret > 0 && FD_ISSET(fd, &rfds);
6323 if (result)
6324 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006325 else if (interrupted != NULL && ret > 0)
6326 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006327
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006328# ifdef EINTR
6329 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006330 {
6331 /* Check whether window has been resized, EINTR may be caused by
6332 * SIGWINCH. */
6333 if (do_resize)
6334 handle_resize();
6335
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006336 /* Interrupted by a signal, need to try again. We ignore msec
6337 * here, because we do want to check even after a timeout if
6338 * characters are available. Needed for reading output of an
6339 * external command after the process has finished. */
6340 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006341 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006342# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006343# ifdef __TANDEM
6344 if (ret == -1 && errno == ENOTSUP)
6345 {
6346 FD_ZERO(&rfds);
6347 FD_ZERO(&efds);
6348 ret = 0;
6349 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006350# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006351# ifdef FEAT_MZSCHEME
6352 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006353 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006354 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006355# endif
6356
Bram Moolenaar071d4272004-06-13 20:20:40 +00006357# ifdef FEAT_XCLIPBOARD
6358 if (ret > 0 && xterm_Shell != (Widget)0
6359 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6360 {
6361 xterm_update(); /* Maybe we should hand out clipboard */
6362 /* continue looping when we only got the X event and the input
6363 * buffer is empty */
6364 if (--ret == 0 && !input_available())
6365 {
6366 /* Try again */
6367 finished = FALSE;
6368 }
6369 }
6370# endif
6371# ifdef FEAT_MOUSE_GPM
6372 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6373 {
6374 if (FD_ISSET(gpm_fd, &efds))
6375 gpm_close();
6376 else if (FD_ISSET(gpm_fd, &rfds))
6377 *check_for_gpm = 1;
6378 }
6379# endif
6380# ifdef USE_XSMP
6381 if (ret > 0 && xsmp_icefd != -1)
6382 {
6383 if (FD_ISSET(xsmp_icefd, &efds))
6384 {
6385 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006386 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006387 xsmp_close();
6388 if (--ret == 0)
6389 finished = FALSE; /* keep going if event was only one */
6390 }
6391 else if (FD_ISSET(xsmp_icefd, &rfds))
6392 {
6393 busy = TRUE;
6394 xsmp_handle_requests();
6395 busy = FALSE;
6396 if (--ret == 0)
6397 finished = FALSE; /* keep going if event was only one */
6398 }
6399 }
6400# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006401#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006402 /* also call when ret == 0, we may be polling a keep-open channel */
6403 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006404 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006405#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006406
6407#endif /* HAVE_SELECT */
6408
6409#ifdef MAY_LOOP
6410 if (finished || msec == 0)
6411 break;
6412
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006413# ifdef FEAT_CLIENTSERVER
6414 if (server_waiting())
6415 break;
6416# endif
6417
Bram Moolenaar071d4272004-06-13 20:20:40 +00006418 /* We're going to loop around again, find out for how long */
6419 if (msec > 0)
6420 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006421# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006422 /* Compute remaining wait time. */
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006423 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424# else
6425 /* Guess we got interrupted halfway. */
6426 msec = msec / 2;
6427# endif
6428 if (msec <= 0)
6429 break; /* waited long enough */
6430 }
6431#endif
6432 }
6433
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006434 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435}
6436
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00006438/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006439 * Expand a path into all matching files and/or directories. Handles "*",
6440 * "?", "[a-z]", "**", etc.
6441 * "path" has backslashes before chars that are not to be expanded.
6442 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006443 */
6444 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006445mch_expandpath(
6446 garray_T *gap,
6447 char_u *path,
6448 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006449{
Bram Moolenaar02743632005-07-25 20:42:36 +00006450 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006451}
6452#endif
6453
6454/*
6455 * mch_expand_wildcards() - this code does wild-card pattern matching using
6456 * the shell
6457 *
6458 * return OK for success, FAIL for error (you may lose some memory) and put
6459 * an error message in *file.
6460 *
6461 * num_pat is number of input patterns
6462 * pat is array of pointers to input patterns
6463 * num_file is pointer to number of matched file names
6464 * file is pointer to array of pointers to matched file names
6465 */
6466
6467#ifndef SEEK_SET
6468# define SEEK_SET 0
6469#endif
6470#ifndef SEEK_END
6471# define SEEK_END 2
6472#endif
6473
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006474#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006475
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006477mch_expand_wildcards(
6478 int num_pat,
6479 char_u **pat,
6480 int *num_file,
6481 char_u ***file,
6482 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006483{
6484 int i;
6485 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006486 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006487 char_u *p;
6488 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489
Bram Moolenaarc7247912008-01-13 12:54:11 +00006490 /*
6491 * This is the non-OS/2 implementation (really Unix).
6492 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006493 int j;
6494 char_u *tempname;
6495 char_u *command;
6496 FILE *fd;
6497 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006498#define STYLE_ECHO 0 /* use "echo", the default */
6499#define STYLE_GLOB 1 /* use "glob", for csh */
6500#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
6501#define STYLE_PRINT 3 /* use "print -N", for zsh */
6502#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
6503 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504 int shell_style = STYLE_ECHO;
6505 int check_spaces;
6506 static int did_find_nul = FALSE;
6507 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006508 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006509 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510
6511 *num_file = 0; /* default: no files found */
6512 *file = NULL;
6513
6514 /*
6515 * If there are no wildcards, just copy the names to allocated memory.
6516 * Saves a lot of time, because we don't have to start a new shell.
6517 */
6518 if (!have_wildcard(num_pat, pat))
6519 return save_patterns(num_pat, pat, num_file, file);
6520
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006521# ifdef HAVE_SANDBOX
6522 /* Don't allow any shell command in the sandbox. */
6523 if (sandbox != 0 && check_secure())
6524 return FAIL;
6525# endif
6526
Bram Moolenaar071d4272004-06-13 20:20:40 +00006527 /*
6528 * Don't allow the use of backticks in secure and restricted mode.
6529 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006530 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006531 for (i = 0; i < num_pat; ++i)
6532 if (vim_strchr(pat[i], '`') != NULL
6533 && (check_restricted() || check_secure()))
6534 return FAIL;
6535
6536 /*
6537 * get a name for the temp file
6538 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006539 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006540 {
6541 EMSG(_(e_notmp));
6542 return FAIL;
6543 }
6544
6545 /*
6546 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006547 * file.
6548 * STYLE_BT: NL separated
6549 * If expanding `cmd` execute it directly.
6550 * STYLE_GLOB: NUL separated
6551 * If we use *csh, "glob" will work better than "echo".
6552 * STYLE_PRINT: NL or NUL separated
6553 * If we use *zsh, "print -N" will work better than "glob".
6554 * STYLE_VIMGLOB: NL separated
6555 * If we use *sh*, we define "vimglob()".
6556 * STYLE_ECHO: space separated.
6557 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006558 */
6559 if (num_pat == 1 && *pat[0] == '`'
6560 && (len = STRLEN(pat[0])) > 2
6561 && *(pat[0] + len - 1) == '`')
6562 shell_style = STYLE_BT;
6563 else if ((len = STRLEN(p_sh)) >= 3)
6564 {
6565 if (STRCMP(p_sh + len - 3, "csh") == 0)
6566 shell_style = STYLE_GLOB;
6567 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6568 shell_style = STYLE_PRINT;
6569 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006570 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6571 "sh") != NULL)
6572 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006573
Bram Moolenaarc7247912008-01-13 12:54:11 +00006574 /* Compute the length of the command. We need 2 extra bytes: for the
6575 * optional '&' and for the NUL.
6576 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006578 if (shell_style == STYLE_VIMGLOB)
6579 len += STRLEN(sh_vimglob_func);
6580
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006581 for (i = 0; i < num_pat; ++i)
6582 {
6583 /* Count the length of the patterns in the same way as they are put in
6584 * "command" below. */
6585#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006587#else
6588 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006589 for (j = 0; pat[i][j] != NUL; ++j)
6590 {
6591 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
6592 ++len; /* may add a backslash */
6593 ++len;
6594 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006595#endif
6596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006597 command = alloc(len);
6598 if (command == NULL)
6599 {
6600 /* out of memory */
6601 vim_free(tempname);
6602 return FAIL;
6603 }
6604
6605 /*
6606 * Build the shell command:
6607 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6608 * recognizes this).
6609 * - Add the shell command to print the expanded names.
6610 * - Add the temp file name.
6611 * - Add the file name patterns.
6612 */
6613 if (shell_style == STYLE_BT)
6614 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00006615 /* change `command; command& ` to (command; command ) */
6616 STRCPY(command, "(");
6617 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006618 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006619 *p-- = ')'; /* remove last backtick */
Bram Moolenaar1c465442017-03-12 20:10:05 +01006620 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006621 --p;
6622 if (*p == '&') /* remove trailing '&' */
6623 {
6624 ampersent = TRUE;
6625 *p = ' ';
6626 }
6627 STRCAT(command, ">");
6628 }
6629 else
6630 {
6631 if (flags & EW_NOTFOUND)
6632 STRCPY(command, "set nonomatch; ");
6633 else
6634 STRCPY(command, "unset nonomatch; ");
6635 if (shell_style == STYLE_GLOB)
6636 STRCAT(command, "glob >");
6637 else if (shell_style == STYLE_PRINT)
6638 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006639 else if (shell_style == STYLE_VIMGLOB)
6640 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006641 else
6642 STRCAT(command, "echo >");
6643 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006644
Bram Moolenaar071d4272004-06-13 20:20:40 +00006645 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006646
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647 if (shell_style != STYLE_BT)
6648 for (i = 0; i < num_pat; ++i)
6649 {
6650 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00006651 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006652 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006653#ifdef USE_SYSTEM
6654 STRCAT(command, " \"");
6655 STRCAT(command, pat[i]);
6656 STRCAT(command, "\"");
6657#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006658 int intick = FALSE;
6659
Bram Moolenaar071d4272004-06-13 20:20:40 +00006660 p = command + STRLEN(command);
6661 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006662 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006663 {
6664 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006665 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006666 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6667 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006668 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00006669 * backslash inside backticks, before a special character
6670 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006671 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006672 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6673 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006674 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006675 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006676 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006677 else if (!intick
6678 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6679 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00006680 /* Put a backslash before a special character, but not
Bram Moolenaare4df1642014-08-29 12:58:44 +02006681 * when inside ``. And not for $var when EW_KEEPDOLLAR is
6682 * set. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006683 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006684
6685 /* Copy one character. */
6686 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006687 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006688 *p = NUL;
6689#endif
6690 }
6691 if (flags & EW_SILENT)
6692 show_shell_mess = FALSE;
6693 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00006694 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006695
6696 /*
6697 * Using zsh -G: If a pattern has no matches, it is just deleted from
6698 * the argument list, otherwise zsh gives an error message and doesn't
6699 * expand any other pattern.
6700 */
6701 if (shell_style == STYLE_PRINT)
6702 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
6703
6704 /*
6705 * If we use -f then shell variables set in .cshrc won't get expanded.
6706 * vi can do it, so we will too, but it is only necessary if there is a "$"
6707 * in one of the patterns, otherwise we can still use the fast option.
6708 */
6709 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
6710 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
6711
6712 /*
6713 * execute the shell command
6714 */
6715 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6716
6717 /* When running in the background, give it some time to create the temp
6718 * file, but don't wait for it to finish. */
6719 if (ampersent)
6720 mch_delay(10L, TRUE);
6721
6722 extra_shell_arg = NULL; /* cleanup */
6723 show_shell_mess = TRUE;
6724 vim_free(command);
6725
Bram Moolenaarc7247912008-01-13 12:54:11 +00006726 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006727 {
6728 mch_remove(tempname);
6729 vim_free(tempname);
6730 /*
6731 * With interactive completion, the error message is not printed.
6732 * However with USE_SYSTEM, I don't know how to turn off error messages
6733 * from the shell, so screen may still get messed up -- webb.
6734 */
6735#ifndef USE_SYSTEM
6736 if (!(flags & EW_SILENT))
6737#endif
6738 {
6739 redraw_later_clear(); /* probably messed up screen */
6740 msg_putchar('\n'); /* clear bottom line quickly */
6741 cmdline_row = Rows - 1; /* continue on last line */
6742#ifdef USE_SYSTEM
6743 if (!(flags & EW_SILENT))
6744#endif
6745 {
6746 MSG(_(e_wildexpand));
6747 msg_start(); /* don't overwrite this message */
6748 }
6749 }
6750 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
6751 * EW_NOTFOUND is given */
6752 if (shell_style == STYLE_BT)
6753 return FAIL;
6754 goto notfound;
6755 }
6756
6757 /*
6758 * read the names from the file into memory
6759 */
6760 fd = fopen((char *)tempname, READBIN);
6761 if (fd == NULL)
6762 {
6763 /* Something went wrong, perhaps a file name with a special char. */
6764 if (!(flags & EW_SILENT))
6765 {
6766 MSG(_(e_wildexpand));
6767 msg_start(); /* don't overwrite this message */
6768 }
6769 vim_free(tempname);
6770 goto notfound;
6771 }
6772 fseek(fd, 0L, SEEK_END);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006773 llen = ftell(fd); /* get size of temp file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006774 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006775 if (llen < 0)
6776 /* just in case ftell() would fail */
6777 buffer = NULL;
6778 else
6779 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006780 if (buffer == NULL)
6781 {
6782 /* out of memory */
6783 mch_remove(tempname);
6784 vim_free(tempname);
6785 fclose(fd);
6786 return FAIL;
6787 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006788 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006789 i = fread((char *)buffer, 1, len, fd);
6790 fclose(fd);
6791 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006792 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006793 {
6794 /* unexpected read error */
6795 EMSG2(_(e_notread), tempname);
6796 vim_free(tempname);
6797 vim_free(buffer);
6798 return FAIL;
6799 }
6800 vim_free(tempname);
6801
Bram Moolenaarc7247912008-01-13 12:54:11 +00006802# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006803 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
6804 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006805 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006806 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6807 *p++ = buffer[i];
6808 len = p - buffer;
6809# endif
6810
6811
6812 /* file names are separated with Space */
6813 if (shell_style == STYLE_ECHO)
6814 {
6815 buffer[len] = '\n'; /* make sure the buffer ends in NL */
6816 p = buffer;
6817 for (i = 0; *p != '\n'; ++i) /* count number of entries */
6818 {
6819 while (*p != ' ' && *p != '\n')
6820 ++p;
6821 p = skipwhite(p); /* skip to next entry */
6822 }
6823 }
6824 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006825 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 {
6827 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6828 p = buffer;
6829 for (i = 0; *p != NUL; ++i) /* count number of entries */
6830 {
6831 while (*p != '\n' && *p != NUL)
6832 ++p;
6833 if (*p != NUL)
6834 ++p;
6835 p = skipwhite(p); /* skip leading white space */
6836 }
6837 }
6838 /* file names are separated with NUL */
6839 else
6840 {
6841 /*
6842 * Some versions of zsh use spaces instead of NULs to separate
6843 * results. Only do this when there is no NUL before the end of the
6844 * buffer, otherwise we would never be able to use file names with
6845 * embedded spaces when zsh does use NULs.
6846 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6847 * don't check for spaces again.
6848 */
6849 check_spaces = FALSE;
6850 if (shell_style == STYLE_PRINT && !did_find_nul)
6851 {
6852 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006853 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006854 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006855 did_find_nul = TRUE;
6856 else
6857 check_spaces = TRUE;
6858 }
6859
6860 /*
6861 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6862 * already is one, for STYLE_GLOB it needs to be added.
6863 */
6864 if (len && buffer[len - 1] == NUL)
6865 --len;
6866 else
6867 buffer[len] = NUL;
6868 i = 0;
6869 for (p = buffer; p < buffer + len; ++p)
6870 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6871 {
6872 ++i;
6873 *p = NUL;
6874 }
6875 if (len)
6876 ++i; /* count last entry */
6877 }
6878 if (i == 0)
6879 {
6880 /*
6881 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6882 * /bin/sh will happily expand it to nothing rather than returning an
6883 * error; and hey, it's good to check anyway -- webb.
6884 */
6885 vim_free(buffer);
6886 goto notfound;
6887 }
6888 *num_file = i;
6889 *file = (char_u **)alloc(sizeof(char_u *) * i);
6890 if (*file == NULL)
6891 {
6892 /* out of memory */
6893 vim_free(buffer);
6894 return FAIL;
6895 }
6896
6897 /*
6898 * Isolate the individual file names.
6899 */
6900 p = buffer;
6901 for (i = 0; i < *num_file; ++i)
6902 {
6903 (*file)[i] = p;
6904 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006905 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6906 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006908 while (!(shell_style == STYLE_ECHO && *p == ' ')
6909 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 ++p;
6911 if (p == buffer + len) /* last entry */
6912 *p = NUL;
6913 else
6914 {
6915 *p++ = NUL;
6916 p = skipwhite(p); /* skip to next entry */
6917 }
6918 }
6919 else /* NUL separates */
6920 {
6921 while (*p && p < buffer + len) /* skip entry */
6922 ++p;
6923 ++p; /* skip NUL */
6924 }
6925 }
6926
6927 /*
6928 * Move the file names to allocated memory.
6929 */
6930 for (j = 0, i = 0; i < *num_file; ++i)
6931 {
6932 /* Require the files to exist. Helps when using /bin/sh */
6933 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6934 continue;
6935
6936 /* check if this entry should be included */
6937 dir = (mch_isdir((*file)[i]));
6938 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6939 continue;
6940
Bram Moolenaara2031822006-03-07 22:29:51 +00006941 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01006942 if (!dir && (flags & EW_EXEC)
6943 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006944 continue;
6945
Bram Moolenaar071d4272004-06-13 20:20:40 +00006946 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6947 if (p)
6948 {
6949 STRCPY(p, (*file)[i]);
6950 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006951 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006952 (*file)[j++] = p;
6953 }
6954 }
6955 vim_free(buffer);
6956 *num_file = j;
6957
6958 if (*num_file == 0) /* rejected all entries */
6959 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006960 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 goto notfound;
6962 }
6963
6964 return OK;
6965
6966notfound:
6967 if (flags & EW_NOTFOUND)
6968 return save_patterns(num_pat, pat, num_file, file);
6969 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006970}
6971
6972#endif /* VMS */
6973
Bram Moolenaar071d4272004-06-13 20:20:40 +00006974 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006975save_patterns(
6976 int num_pat,
6977 char_u **pat,
6978 int *num_file,
6979 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006980{
6981 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006982 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006983
6984 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6985 if (*file == NULL)
6986 return FAIL;
6987 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006988 {
6989 s = vim_strsave(pat[i]);
6990 if (s != NULL)
6991 /* Be compatible with expand_filename(): halve the number of
6992 * backslashes. */
6993 backslash_halve(s);
6994 (*file)[i] = s;
6995 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006996 *num_file = num_pat;
6997 return OK;
6998}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006999
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000/*
7001 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7002 * expand.
7003 */
7004 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007005mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007006{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007007 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007009 if (*p == '\\' && p[1] != NUL)
7010 ++p;
7011 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007012 if (vim_strchr((char_u *)
7013#ifdef VMS
7014 "*?%"
7015#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007017#endif
7018 , *p) != NULL)
7019 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 }
7021 return FALSE;
7022}
7023
7024/*
7025 * Return TRUE if the string "p" contains a wildcard.
7026 * Don't recognize '~' at the end as a wildcard.
7027 */
7028 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007029mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007030{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007031 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007032 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033 if (*p == '\\' && p[1] != NUL)
7034 ++p;
7035 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007036 if (vim_strchr((char_u *)
7037#ifdef VMS
7038 "*?%$"
7039#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007040 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007041#endif
7042 , *p) != NULL
7043 || (*p == '~' && p[1] != NUL))
7044 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007045 }
7046 return FALSE;
7047}
7048
Bram Moolenaar071d4272004-06-13 20:20:40 +00007049 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007050have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007051{
7052 int i;
7053
7054 for (i = 0; i < num; i++)
7055 if (mch_has_wildcard(file[i]))
7056 return 1;
7057 return 0;
7058}
7059
7060 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007061have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007062{
7063 int i;
7064
7065 for (i = 0; i < num; i++)
7066 if (vim_strchr(file[i], '$') != NULL)
7067 return TRUE;
7068 return FALSE;
7069}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007071#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007072/*
7073 * Scaled-down version of rename(), which is missing in Xenix.
7074 * This version can only move regular files and will fail if the
7075 * destination exists.
7076 */
7077 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007078mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007079{
7080 struct stat st;
7081
7082 if (stat(dest, &st) >= 0) /* fail if destination exists */
7083 return -1;
7084 if (link(src, dest) != 0) /* link file to new name */
7085 return -1;
7086 if (mch_remove(src) == 0) /* delete link to old name */
7087 return 0;
7088 return -1;
7089}
7090#endif /* !HAVE_RENAME */
7091
7092#ifdef FEAT_MOUSE_GPM
7093/*
7094 * Initializes connection with gpm (if it isn't already opened)
7095 * Return 1 if succeeded (or connection already opened), 0 if failed
7096 */
7097 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007098gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007099{
7100 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
7101
7102 if (!gpm_flag)
7103 {
7104 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7105 gpm_connect.defaultMask = ~GPM_HARD;
7106 /* Default handling for mouse move*/
7107 gpm_connect.minMod = 0; /* Handle any modifier keys */
7108 gpm_connect.maxMod = 0xffff;
7109 if (Gpm_Open(&gpm_connect, 0) > 0)
7110 {
7111 /* gpm library tries to handling TSTP causes
7112 * problems. Anyways, we close connection to Gpm whenever
7113 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00007114 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007115 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007116# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007118# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007119 return 1; /* succeed */
7120 }
7121 if (gpm_fd == -2)
7122 Gpm_Close(); /* We don't want to talk to xterm via gpm */
7123 return 0;
7124 }
7125 return 1; /* already open */
7126}
7127
7128/*
7129 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007130 */
7131 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007132gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007133{
7134 if (gpm_flag && gpm_fd >= 0) /* if Open */
7135 Gpm_Close();
7136}
7137
7138/* Reads gpm event and adds special keys to input buf. Returns length of
7139 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007140 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 */
7142 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007143mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007144{
7145 int button;
7146 static Gpm_Event gpm_event;
7147 char_u string[6];
7148 int_u vim_modifiers;
7149 int row,col;
7150 unsigned char buttons_mask;
7151 unsigned char gpm_modifiers;
7152 static unsigned char old_buttons = 0;
7153
7154 Gpm_GetEvent(&gpm_event);
7155
7156#ifdef FEAT_GUI
7157 /* Don't put events in the input queue now. */
7158 if (hold_gui_events)
7159 return 0;
7160#endif
7161
7162 row = gpm_event.y - 1;
7163 col = gpm_event.x - 1;
7164
7165 string[0] = ESC; /* Our termcode */
7166 string[1] = 'M';
7167 string[2] = 'G';
7168 switch (GPM_BARE_EVENTS(gpm_event.type))
7169 {
7170 case GPM_DRAG:
7171 string[3] = MOUSE_DRAG;
7172 break;
7173 case GPM_DOWN:
7174 buttons_mask = gpm_event.buttons & ~old_buttons;
7175 old_buttons = gpm_event.buttons;
7176 switch (buttons_mask)
7177 {
7178 case GPM_B_LEFT:
7179 button = MOUSE_LEFT;
7180 break;
7181 case GPM_B_MIDDLE:
7182 button = MOUSE_MIDDLE;
7183 break;
7184 case GPM_B_RIGHT:
7185 button = MOUSE_RIGHT;
7186 break;
7187 default:
7188 return 0;
7189 /*Don't know what to do. Can more than one button be
7190 * reported in one event? */
7191 }
7192 string[3] = (char_u)(button | 0x20);
7193 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7194 break;
7195 case GPM_UP:
7196 string[3] = MOUSE_RELEASE;
7197 old_buttons &= ~gpm_event.buttons;
7198 break;
7199 default:
7200 return 0;
7201 }
7202 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
7203 gpm_modifiers = gpm_event.modifiers;
7204 vim_modifiers = 0x0;
7205 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
7206 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7207 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
7208 */
7209 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7210 vim_modifiers |= MOUSE_SHIFT;
7211
7212 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7213 vim_modifiers |= MOUSE_CTRL;
7214 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7215 vim_modifiers |= MOUSE_ALT;
7216 string[3] |= vim_modifiers;
7217 string[4] = (char_u)(col + ' ' + 1);
7218 string[5] = (char_u)(row + ' ' + 1);
7219 add_to_input_buf(string, 6);
7220 return 6;
7221}
7222#endif /* FEAT_MOUSE_GPM */
7223
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007224#ifdef FEAT_SYSMOUSE
7225/*
7226 * Initialize connection with sysmouse.
7227 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7228 * output, any sysmouse output than will be processed via sig_sysmouse().
7229 * Return OK if succeeded, FAIL if failed.
7230 */
7231 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007232sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007233{
7234 struct mouse_info mouse;
7235
7236 mouse.operation = MOUSE_MODE;
7237 mouse.u.mode.mode = 0;
7238 mouse.u.mode.signal = SIGUSR2;
7239 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7240 {
7241 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7242 mouse.operation = MOUSE_SHOW;
7243 ioctl(1, CONS_MOUSECTL, &mouse);
7244 return OK;
7245 }
7246 return FAIL;
7247}
7248
7249/*
7250 * Stop processing SIGUSR2 signals, and also make sure that
7251 * virtual console do not send us any sysmouse related signal.
7252 */
7253 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007254sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007255{
7256 struct mouse_info mouse;
7257
7258 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7259 mouse.operation = MOUSE_MODE;
7260 mouse.u.mode.mode = 0;
7261 mouse.u.mode.signal = 0;
7262 ioctl(1, CONS_MOUSECTL, &mouse);
7263}
7264
7265/*
7266 * Gets info from sysmouse and adds special keys to input buf.
7267 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007268 static RETSIGTYPE
7269sig_sysmouse SIGDEFARG(sigarg)
7270{
7271 struct mouse_info mouse;
7272 struct video_info video;
7273 char_u string[6];
7274 int row, col;
7275 int button;
7276 int buttons;
7277 static int oldbuttons = 0;
7278
7279#ifdef FEAT_GUI
7280 /* Don't put events in the input queue now. */
7281 if (hold_gui_events)
7282 return;
7283#endif
7284
7285 mouse.operation = MOUSE_GETINFO;
7286 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7287 && ioctl(1, FBIO_MODEINFO, &video) != -1
7288 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7289 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7290 {
7291 row = mouse.u.data.y / video.vi_cheight;
7292 col = mouse.u.data.x / video.vi_cwidth;
7293 buttons = mouse.u.data.buttons;
7294 string[0] = ESC; /* Our termcode */
7295 string[1] = 'M';
7296 string[2] = 'S';
7297 if (oldbuttons == buttons && buttons != 0)
7298 {
7299 button = MOUSE_DRAG;
7300 }
7301 else
7302 {
7303 switch (buttons)
7304 {
7305 case 0:
7306 button = MOUSE_RELEASE;
7307 break;
7308 case 1:
7309 button = MOUSE_LEFT;
7310 break;
7311 case 2:
7312 button = MOUSE_MIDDLE;
7313 break;
7314 case 4:
7315 button = MOUSE_RIGHT;
7316 break;
7317 default:
7318 return;
7319 }
7320 oldbuttons = buttons;
7321 }
7322 string[3] = (char_u)(button);
7323 string[4] = (char_u)(col + ' ' + 1);
7324 string[5] = (char_u)(row + ' ' + 1);
7325 add_to_input_buf(string, 6);
7326 }
7327 return;
7328}
7329#endif /* FEAT_SYSMOUSE */
7330
Bram Moolenaar071d4272004-06-13 20:20:40 +00007331#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007332typedef char_u * (*STRPROCSTR)(char_u *);
7333typedef char_u * (*INTPROCSTR)(int);
7334typedef int (*STRPROCINT)(char_u *);
7335typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007336
7337/*
7338 * Call a DLL routine which takes either a string or int param
7339 * and returns an allocated string.
7340 */
7341 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007342mch_libcall(
7343 char_u *libname,
7344 char_u *funcname,
7345 char_u *argstring, /* NULL when using a argint */
7346 int argint,
7347 char_u **string_result,/* NULL when using number_result */
7348 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007349{
7350# if defined(USE_DLOPEN)
7351 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007352 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007353# else
7354 shl_t hinstLib;
7355# endif
7356 STRPROCSTR ProcAdd;
7357 INTPROCSTR ProcAddI;
7358 char_u *retval_str = NULL;
7359 int retval_int = 0;
7360 int success = FALSE;
7361
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007362 /*
7363 * Get a handle to the DLL module.
7364 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007366 /* First clear any error, it's not cleared by the dlopen() call. */
7367 (void)dlerror();
7368
Bram Moolenaar071d4272004-06-13 20:20:40 +00007369 hinstLib = dlopen((char *)libname, RTLD_LAZY
7370# ifdef RTLD_LOCAL
7371 | RTLD_LOCAL
7372# endif
7373 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007374 if (hinstLib == NULL)
7375 {
7376 /* "dlerr" must be used before dlclose() */
7377 dlerr = (char *)dlerror();
7378 if (dlerr != NULL)
7379 EMSG2(_("dlerror = \"%s\""), dlerr);
7380 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007381# else
7382 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7383# endif
7384
7385 /* If the handle is valid, try to get the function address. */
7386 if (hinstLib != NULL)
7387 {
7388# ifdef HAVE_SETJMP_H
7389 /*
7390 * Catch a crash when calling the library function. For example when
7391 * using a number where a string pointer is expected.
7392 */
7393 mch_startjmp();
7394 if (SETJMP(lc_jump_env) != 0)
7395 {
7396 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007397# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007398 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007399# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007400 mch_didjmp();
7401 }
7402 else
7403# endif
7404 {
7405 retval_str = NULL;
7406 retval_int = 0;
7407
7408 if (argstring != NULL)
7409 {
7410# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007411 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007412 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007413# else
7414 if (shl_findsym(&hinstLib, (const char *)funcname,
7415 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7416 ProcAdd = NULL;
7417# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007418 if ((success = (ProcAdd != NULL
7419# if defined(USE_DLOPEN)
7420 && dlerr == NULL
7421# endif
7422 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423 {
7424 if (string_result == NULL)
7425 retval_int = ((STRPROCINT)ProcAdd)(argstring);
7426 else
7427 retval_str = (ProcAdd)(argstring);
7428 }
7429 }
7430 else
7431 {
7432# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007433 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007434 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435# else
7436 if (shl_findsym(&hinstLib, (const char *)funcname,
7437 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7438 ProcAddI = NULL;
7439# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007440 if ((success = (ProcAddI != NULL
7441# if defined(USE_DLOPEN)
7442 && dlerr == NULL
7443# endif
7444 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007445 {
7446 if (string_result == NULL)
7447 retval_int = ((INTPROCINT)ProcAddI)(argint);
7448 else
7449 retval_str = (ProcAddI)(argint);
7450 }
7451 }
7452
7453 /* Save the string before we free the library. */
7454 /* Assume that a "1" or "-1" result is an illegal pointer. */
7455 if (string_result == NULL)
7456 *number_result = retval_int;
7457 else if (retval_str != NULL
7458 && retval_str != (char_u *)1
7459 && retval_str != (char_u *)-1)
7460 *string_result = vim_strsave(retval_str);
7461 }
7462
7463# ifdef HAVE_SETJMP_H
7464 mch_endjmp();
7465# ifdef SIGHASARG
7466 if (lc_signal != 0)
7467 {
7468 int i;
7469
7470 /* try to find the name of this signal */
7471 for (i = 0; signal_info[i].sig != -1; i++)
7472 if (lc_signal == signal_info[i].sig)
7473 break;
7474 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
7475 }
7476# endif
7477# endif
7478
Bram Moolenaar071d4272004-06-13 20:20:40 +00007479# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007480 /* "dlerr" must be used before dlclose() */
7481 if (dlerr != NULL)
7482 EMSG2(_("dlerror = \"%s\""), dlerr);
7483
7484 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007485 (void)dlclose(hinstLib);
7486# else
7487 (void)shl_unload(hinstLib);
7488# endif
7489 }
7490
7491 if (!success)
7492 {
7493 EMSG2(_(e_libcall), funcname);
7494 return FAIL;
7495 }
7496
7497 return OK;
7498}
7499#endif
7500
7501#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
7502static int xterm_trace = -1; /* default: disabled */
7503static int xterm_button;
7504
7505/*
7506 * Setup a dummy window for X selections in a terminal.
7507 */
7508 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007509setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007510{
7511 int z = 0;
7512 char *strp = "";
7513 Widget AppShell;
7514
7515 if (!x_connect_to_server())
7516 return;
7517
7518 open_app_context();
7519 if (app_context != NULL && xterm_Shell == (Widget)0)
7520 {
7521 int (*oldhandler)();
7522#if defined(HAVE_SETJMP_H)
7523 int (*oldIOhandler)();
7524#endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007525# ifdef ELAPSED_FUNC
7526 ELAPSED_TYPE start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007527
7528 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007529 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007530# endif
7531
7532 /* Ignore X errors while opening the display */
7533 oldhandler = XSetErrorHandler(x_error_check);
7534
7535#if defined(HAVE_SETJMP_H)
7536 /* Ignore X IO errors while opening the display */
7537 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7538 mch_startjmp();
7539 if (SETJMP(lc_jump_env) != 0)
7540 {
7541 mch_didjmp();
7542 xterm_dpy = NULL;
7543 }
7544 else
7545#endif
7546 {
7547 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7548 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
7549#if defined(HAVE_SETJMP_H)
7550 mch_endjmp();
7551#endif
7552 }
7553
7554#if defined(HAVE_SETJMP_H)
7555 /* Now handle X IO errors normally. */
7556 (void)XSetIOErrorHandler(oldIOhandler);
7557#endif
7558 /* Now handle X errors normally. */
7559 (void)XSetErrorHandler(oldhandler);
7560
7561 if (xterm_dpy == NULL)
7562 {
7563 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007564 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007565 return;
7566 }
7567
7568 /* Catch terminating error of the X server connection. */
7569 (void)XSetIOErrorHandler(x_IOerror_handler);
7570
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007571# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007572 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007573 {
7574 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007575 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007576 verbose_leave();
7577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007578# endif
7579
7580 /* Create a Shell to make converters work. */
7581 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7582 applicationShellWidgetClass, xterm_dpy,
7583 NULL);
7584 if (AppShell == (Widget)0)
7585 return;
7586 xterm_Shell = XtVaCreatePopupShell("VIM",
7587 topLevelShellWidgetClass, AppShell,
7588 XtNmappedWhenManaged, 0,
7589 XtNwidth, 1,
7590 XtNheight, 1,
7591 NULL);
7592 if (xterm_Shell == (Widget)0)
7593 return;
7594
7595 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007596 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007597 if (x11_display == NULL)
7598 x11_display = xterm_dpy;
7599
7600 XtRealizeWidget(xterm_Shell);
7601 XSync(xterm_dpy, False);
7602 xterm_update();
7603 }
7604 if (xterm_Shell != (Widget)0)
7605 {
7606 clip_init(TRUE);
7607 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7608 x11_window = (Window)atol(strp);
7609 /* Check if $WINDOWID is valid. */
7610 if (test_x11_window(xterm_dpy) == FAIL)
7611 x11_window = 0;
7612 if (x11_window != 0)
7613 xterm_trace = 0;
7614 }
7615}
7616
7617 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007618start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007619{
7620 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7621 return;
7622 xterm_trace = 1;
7623 xterm_button = button;
7624 do_xterm_trace();
7625}
7626
7627
7628 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007629stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007630{
7631 if (xterm_trace < 0)
7632 return;
7633 xterm_trace = 0;
7634}
7635
7636/*
7637 * Query the xterm pointer and generate mouse termcodes if necessary
7638 * return TRUE if dragging is active, else FALSE
7639 */
7640 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007641do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007642{
7643 Window root, child;
7644 int root_x, root_y;
7645 int win_x, win_y;
7646 int row, col;
7647 int_u mask_return;
7648 char_u buf[50];
7649 char_u *strp;
7650 long got_hints;
7651 static char_u *mouse_code;
7652 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7653 static int prev_row = 0, prev_col = 0;
7654 static XSizeHints xterm_hints;
7655
7656 if (xterm_trace <= 0)
7657 return FALSE;
7658
7659 if (xterm_trace == 1)
7660 {
7661 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007662 * have changed recently. */
7663 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7664 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007665 || xterm_hints.width_inc <= 1
7666 || xterm_hints.height_inc <= 1)
7667 {
7668 xterm_trace = -1; /* Not enough data -- disable tracing */
7669 return FALSE;
7670 }
7671
7672 /* Rely on the same mouse code for the duration of this */
7673 mouse_code = find_termcode(mouse_name);
7674 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007675 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007676 xterm_trace = 2;
7677
7678 /* Find the offset of the chars, there might be a scrollbar on the
7679 * left of the window and/or a menu on the top (eterm etc.) */
7680 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7681 &win_x, &win_y, &mask_return);
7682 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7683 - (xterm_hints.height_inc / 2);
7684 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7685 xterm_hints.y = 2;
7686 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7687 - (xterm_hints.width_inc / 2);
7688 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7689 xterm_hints.x = 2;
7690 return TRUE;
7691 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007692 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693 {
7694 xterm_trace = 0;
7695 return FALSE;
7696 }
7697
7698 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7699 &win_x, &win_y, &mask_return);
7700
7701 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7702 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7703 if (row == prev_row && col == prev_col)
7704 return TRUE;
7705
7706 STRCPY(buf, mouse_code);
7707 strp = buf + STRLEN(buf);
7708 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7709 *strp++ = (char_u)(col + ' ' + 1);
7710 *strp++ = (char_u)(row + ' ' + 1);
7711 *strp = 0;
7712 add_to_input_buf(buf, STRLEN(buf));
7713
7714 prev_row = row;
7715 prev_col = col;
7716 return TRUE;
7717}
7718
7719# if defined(FEAT_GUI) || defined(PROTO)
7720/*
7721 * Destroy the display, window and app_context. Required for GTK.
7722 */
7723 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007724clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007725{
7726 if (xterm_Shell != (Widget)0)
7727 {
7728 XtDestroyWidget(xterm_Shell);
7729 xterm_Shell = (Widget)0;
7730 }
7731 if (xterm_dpy != NULL)
7732 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007733# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007734 /* Lesstif and Solaris crash here, lose some memory */
7735 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007736# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007737 if (x11_display == xterm_dpy)
7738 x11_display = NULL;
7739 xterm_dpy = NULL;
7740 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007741# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007742 if (app_context != (XtAppContext)NULL)
7743 {
7744 /* Lesstif and Solaris crash here, lose some memory */
7745 XtDestroyApplicationContext(app_context);
7746 app_context = (XtAppContext)NULL;
7747 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007748# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007749}
7750# endif
7751
7752/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007753 * Catch up with GUI or X events.
7754 */
7755 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007756clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007757{
7758# ifdef FEAT_GUI
7759 if (gui.in_use)
7760 gui_mch_update();
7761 else
7762# endif
7763 if (xterm_Shell != (Widget)0)
7764 xterm_update();
7765}
7766
7767/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768 * Catch up with any queued X events. This may put keyboard input into the
7769 * input buffer, call resize call-backs, trigger timers etc. If there is
7770 * nothing in the X event queue (& no timers pending), then we return
7771 * immediately.
7772 */
7773 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007774xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007775{
7776 XEvent event;
7777
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007778 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007779 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007780 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007781
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007782 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007783 break;
7784
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007785 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007786 {
7787 /* There is an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007788 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007789#ifdef FEAT_CLIENTSERVER
7790 {
7791 XPropertyEvent *e = (XPropertyEvent *)&event;
7792
7793 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007794 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007795 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007796 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007797#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007798 XtDispatchEvent(&event);
7799 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007800 else
7801 {
7802 /* There is something else than an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007803 XtAppProcessEvent(app_context, mask);
7804 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007805 }
7806}
7807
7808 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007809clip_xterm_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007810{
7811 if (xterm_Shell != (Widget)0)
7812 return clip_x11_own_selection(xterm_Shell, cbd);
7813 return FAIL;
7814}
7815
7816 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007817clip_xterm_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007818{
7819 if (xterm_Shell != (Widget)0)
7820 clip_x11_lose_selection(xterm_Shell, cbd);
7821}
7822
7823 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007824clip_xterm_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007825{
7826 if (xterm_Shell != (Widget)0)
7827 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7828}
7829
7830 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007831clip_xterm_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007832{
7833 clip_x11_set_selection(cbd);
7834}
7835#endif
7836
7837
7838#if defined(USE_XSMP) || defined(PROTO)
7839/*
7840 * Code for X Session Management Protocol.
7841 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007842static void xsmp_handle_save_yourself(SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast);
7843static void xsmp_die(SmcConn smc_conn, SmPointer client_data);
7844static void xsmp_save_complete(SmcConn smc_conn, SmPointer client_data);
7845static void xsmp_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data);
7846static void xsmp_ice_connection(IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007847
7848
7849# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007850static void xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007851
7852/*
7853 * This is our chance to ask the user if they want to save,
7854 * or abort the logout
7855 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007856 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007857xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007858{
7859 cmdmod_T save_cmdmod;
7860 int cancel_shutdown = False;
7861
7862 save_cmdmod = cmdmod;
7863 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007864 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007865 /* Mustn't logout */
7866 cancel_shutdown = True;
7867 cmdmod = save_cmdmod;
7868 setcursor(); /* position cursor */
7869 out_flush();
7870
7871 /* Done interaction */
7872 SmcInteractDone(smc_conn, cancel_shutdown);
7873
7874 /* Finish off
7875 * Only end save-yourself here if we're not cancelling shutdown;
7876 * we'll get a cancelled callback later in which we'll end it.
7877 * Hopefully get around glitchy SMs (like GNOME-1)
7878 */
7879 if (!cancel_shutdown)
7880 {
7881 xsmp.save_yourself = False;
7882 SmcSaveYourselfDone(smc_conn, True);
7883 }
7884}
7885# endif
7886
7887/*
7888 * Callback that starts save-yourself.
7889 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007890 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007891xsmp_handle_save_yourself(
7892 SmcConn smc_conn,
7893 SmPointer client_data UNUSED,
7894 int save_type UNUSED,
7895 Bool shutdown,
7896 int interact_style UNUSED,
7897 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007898{
7899 /* Handle already being in saveyourself */
7900 if (xsmp.save_yourself)
7901 SmcSaveYourselfDone(smc_conn, True);
7902 xsmp.save_yourself = True;
7903 xsmp.shutdown = shutdown;
7904
7905 /* First up, preserve all files */
7906 out_flush();
7907 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7908
7909 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007910 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007911
7912# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7913 /* Now see if we can ask about unsaved files */
7914 if (shutdown && !fast && gui.in_use)
7915 /* Need to interact with user, but need SM's permission */
7916 SmcInteractRequest(smc_conn, SmDialogError,
7917 xsmp_handle_interaction, client_data);
7918 else
7919# endif
7920 {
7921 /* Can stop the cycle here */
7922 SmcSaveYourselfDone(smc_conn, True);
7923 xsmp.save_yourself = False;
7924 }
7925}
7926
7927
7928/*
7929 * Callback to warn us of imminent death.
7930 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007931 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007932xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007933{
7934 xsmp_close();
7935
7936 /* quit quickly leaving swapfiles for modified buffers behind */
7937 getout_preserve_modified(0);
7938}
7939
7940
7941/*
7942 * Callback to tell us that save-yourself has completed.
7943 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007944 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007945xsmp_save_complete(
7946 SmcConn smc_conn UNUSED,
7947 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007948{
7949 xsmp.save_yourself = False;
7950}
7951
7952
7953/*
7954 * Callback to tell us that an instigated shutdown was cancelled
7955 * (maybe even by us)
7956 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007957 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007958xsmp_shutdown_cancelled(
7959 SmcConn smc_conn,
7960 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007961{
7962 if (xsmp.save_yourself)
7963 SmcSaveYourselfDone(smc_conn, True);
7964 xsmp.save_yourself = False;
7965 xsmp.shutdown = False;
7966}
7967
7968
7969/*
7970 * Callback to tell us that a new ICE connection has been established.
7971 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007972 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007973xsmp_ice_connection(
7974 IceConn iceConn,
7975 IcePointer clientData UNUSED,
7976 Bool opening,
7977 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007978{
7979 /* Intercept creation of ICE connection fd */
7980 if (opening)
7981 {
7982 xsmp_icefd = IceConnectionNumber(iceConn);
7983 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7984 }
7985}
7986
7987
7988/* Handle any ICE processing that's required; return FAIL if SM lost */
7989 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007990xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007991{
7992 Bool rep;
7993
7994 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7995 == IceProcessMessagesIOError)
7996 {
7997 /* Lost ICE */
7998 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007999 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008000 xsmp_close();
8001 return FAIL;
8002 }
8003 else
8004 return OK;
8005}
8006
8007static int dummy;
8008
8009/* Set up X Session Management Protocol */
8010 void
8011xsmp_init(void)
8012{
8013 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008014 SmcCallbacks smcallbacks;
8015#if 0
8016 SmPropValue smname;
8017 SmProp smnameprop;
8018 SmProp *smprops[1];
8019#endif
8020
8021 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008022 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008023
8024 xsmp.save_yourself = xsmp.shutdown = False;
8025
8026 /* Set up SM callbacks - must have all, even if they're not used */
8027 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8028 smcallbacks.save_yourself.client_data = NULL;
8029 smcallbacks.die.callback = xsmp_die;
8030 smcallbacks.die.client_data = NULL;
8031 smcallbacks.save_complete.callback = xsmp_save_complete;
8032 smcallbacks.save_complete.client_data = NULL;
8033 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8034 smcallbacks.shutdown_cancelled.client_data = NULL;
8035
8036 /* Set up a watch on ICE connection creations. The "dummy" argument is
8037 * apparently required for FreeBSD (we get a BUS error when using NULL). */
8038 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8039 {
8040 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008041 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008042 return;
8043 }
8044
8045 /* Create an SM connection */
8046 xsmp.smcconn = SmcOpenConnection(
8047 NULL,
8048 NULL,
8049 SmProtoMajor,
8050 SmProtoMinor,
8051 SmcSaveYourselfProcMask | SmcDieProcMask
8052 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8053 &smcallbacks,
8054 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008055 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008056 sizeof(errorstring),
8057 errorstring);
8058 if (xsmp.smcconn == NULL)
8059 {
8060 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00008061
Bram Moolenaar071d4272004-06-13 20:20:40 +00008062 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008063 {
8064 vim_snprintf(errorreport, sizeof(errorreport),
8065 _("XSMP SmcOpenConnection failed: %s"), errorstring);
8066 verb_msg((char_u *)errorreport);
8067 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008068 return;
8069 }
8070 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8071
8072#if 0
8073 /* ID ourselves */
8074 smname.value = "vim";
8075 smname.length = 3;
8076 smnameprop.name = "SmProgram";
8077 smnameprop.type = "SmARRAY8";
8078 smnameprop.num_vals = 1;
8079 smnameprop.vals = &smname;
8080
8081 smprops[0] = &smnameprop;
8082 SmcSetProperties(xsmp.smcconn, 1, smprops);
8083#endif
8084}
8085
8086
8087/* Shut down XSMP comms. */
8088 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008089xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008090{
8091 if (xsmp_icefd != -1)
8092 {
8093 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008094 if (xsmp.clientid != NULL)
8095 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008096 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008097 xsmp_icefd = -1;
8098 }
8099}
8100#endif /* USE_XSMP */
8101
8102
8103#ifdef EBCDIC
8104/* Translate character to its CTRL- value */
8105char CtrlTable[] =
8106{
8107/* 00 - 5E */
8108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8114/* ^ */ 0x1E,
8115/* - */ 0x1F,
8116/* 61 - 6C */
8117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8118/* _ */ 0x1F,
8119/* 6E - 80 */
8120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8121/* a */ 0x01,
8122/* b */ 0x02,
8123/* c */ 0x03,
8124/* d */ 0x37,
8125/* e */ 0x2D,
8126/* f */ 0x2E,
8127/* g */ 0x2F,
8128/* h */ 0x16,
8129/* i */ 0x05,
8130/* 8A - 90 */
8131 0, 0, 0, 0, 0, 0, 0,
8132/* j */ 0x15,
8133/* k */ 0x0B,
8134/* l */ 0x0C,
8135/* m */ 0x0D,
8136/* n */ 0x0E,
8137/* o */ 0x0F,
8138/* p */ 0x10,
8139/* q */ 0x11,
8140/* r */ 0x12,
8141/* 9A - A1 */
8142 0, 0, 0, 0, 0, 0, 0, 0,
8143/* s */ 0x13,
8144/* t */ 0x3C,
8145/* u */ 0x3D,
8146/* v */ 0x32,
8147/* w */ 0x26,
8148/* x */ 0x18,
8149/* y */ 0x19,
8150/* z */ 0x3F,
8151/* AA - AC */
8152 0, 0, 0,
8153/* [ */ 0x27,
8154/* AE - BC */
8155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8156/* ] */ 0x1D,
8157/* BE - C0 */ 0, 0, 0,
8158/* A */ 0x01,
8159/* B */ 0x02,
8160/* C */ 0x03,
8161/* D */ 0x37,
8162/* E */ 0x2D,
8163/* F */ 0x2E,
8164/* G */ 0x2F,
8165/* H */ 0x16,
8166/* I */ 0x05,
8167/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8168/* J */ 0x15,
8169/* K */ 0x0B,
8170/* L */ 0x0C,
8171/* M */ 0x0D,
8172/* N */ 0x0E,
8173/* O */ 0x0F,
8174/* P */ 0x10,
8175/* Q */ 0x11,
8176/* R */ 0x12,
8177/* DA - DF */ 0, 0, 0, 0, 0, 0,
8178/* \ */ 0x1C,
8179/* E1 */ 0,
8180/* S */ 0x13,
8181/* T */ 0x3C,
8182/* U */ 0x3D,
8183/* V */ 0x32,
8184/* W */ 0x26,
8185/* X */ 0x18,
8186/* Y */ 0x19,
8187/* Z */ 0x3F,
8188/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8190};
8191
8192char MetaCharTable[]=
8193{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
8194 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8195 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8196 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8197 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8198};
8199
8200
8201/* TODO: Use characters NOT numbers!!! */
8202char CtrlCharTable[]=
8203{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
8204 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8205 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8206 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8207 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8208};
8209
8210
8211#endif