blob: 73caa1a3e45324e37802ecb6b0d7a5fd5d206a47 [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!!!
Bram Moolenaar041c7102020-05-30 18:14:57 +020015 * Also for Atari MiNT.
Bram Moolenaar071d4272004-06-13 20:20:40 +000016 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram Moolenaar0f873732019-12-05 20:28:46 +010027#include "os_unixx.h" // unix includes for os_unix.c only
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
29#ifdef USE_XSMP
30# include <X11/SM/SMlib.h>
31#endif
32
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000033#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35static int selinux_enabled = -1;
36#endif
37
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020038#ifdef HAVE_SMACK
39# include <attr/xattr.h>
40# include <linux/xattr.h>
41# ifndef SMACK_LABEL_LEN
42# define SMACK_LABEL_LEN 1024
43# endif
44#endif
45
Bram Moolenaara2442432007-04-26 14:26:37 +000046#ifdef __CYGWIN__
Bram Moolenaar4f974752019-02-17 17:44:42 +010047# ifndef MSWIN
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000048# include <cygwin/version.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010049# include <sys/cygwin.h> // for cygwin_conv_to_posix_path() and/or
50 // for cygwin_conv_path()
Bram Moolenaar693e40c2013-02-26 14:56:42 +010051# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
52# define WIN32_LEAN_AND_MEAN
53# include <windows.h>
54# include "winclip.pro"
55# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000056# endif
57#endif
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059#ifdef FEAT_MOUSE_GPM
60# include <gpm.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010061// <linux/keyboard.h> contains defines conflicting with "keymap.h",
62// I just copied relevant defines here. A cleaner solution would be to put gpm
63// code into separate file and include there linux/keyboard.h
64// #include <linux/keyboard.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000065# define KG_SHIFT 0
66# define KG_CTRL 2
67# define KG_ALT 3
68# define KG_ALTGR 1
69# define KG_SHIFTL 4
70# define KG_SHIFTR 5
71# define KG_CTRLL 6
72# define KG_CTRLR 7
73# define KG_CAPSSHIFT 8
74
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010075static void gpm_close(void);
76static int gpm_open(void);
77static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#endif
79
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000080#ifdef FEAT_SYSMOUSE
81# include <sys/consio.h>
82# include <sys/fbio.h>
83
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010084static int sysmouse_open(void);
85static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +010086static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000087#endif
88
Bram Moolenaar071d4272004-06-13 20:20:40 +000089/*
90 * end of autoconf section. To be extended...
91 */
92
Bram Moolenaar0f873732019-12-05 20:28:46 +010093// Are the following #ifdefs still required? And why? Is that for X11?
Bram Moolenaar071d4272004-06-13 20:20:40 +000094
95#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
96# ifdef SIGWINCH
97# undef SIGWINCH
98# endif
99# ifdef TIOCGWINSZ
100# undef TIOCGWINSZ
101# endif
102#endif
103
Bram Moolenaar0f873732019-12-05 20:28:46 +0100104#if defined(SIGWINDOW) && !defined(SIGWINCH) // hpux 9.01 has it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105# define SIGWINCH SIGWINDOW
106#endif
107
108#ifdef FEAT_X11
109# include <X11/Xlib.h>
110# include <X11/Xutil.h>
111# include <X11/Xatom.h>
112# ifdef FEAT_XCLIPBOARD
113# include <X11/Intrinsic.h>
114# include <X11/Shell.h>
115# include <X11/StringDefs.h>
116static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100117static void clip_update(void);
118static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119# endif
120
121# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
122Window x11_window = 0;
123# endif
124Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125#endif
126
Bram Moolenaar5c3128e2020-05-11 20:54:42 +0200127static int ignore_sigtstp = FALSE;
128
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100130static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131
132static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200133static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +0200134static int unix_did_set_title = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135static char_u *oldicon = NULL;
136static int did_set_icon = FALSE;
137#endif
138
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100139static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140
Bram Moolenaar205b8862011-09-07 15:04:31 +0200141#ifdef HAVE_UNION_WAIT
142typedef union wait waitstatus;
143#else
144typedef int waitstatus;
145#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200146static int WaitForChar(long msec, int *interrupted, int ignore_input);
147static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar041c7102020-05-30 18:14:57 +0200148#ifdef VMS
Bram Moolenaarcda77642016-06-04 13:32:35 +0200149int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200151static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152#endif
153
154#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100155static int do_xterm_trace(void);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100156# define XT_TRACE_DELAY 50 // delay for xterm tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157#endif
158
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100159static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160
161#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100162static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163#endif
164#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100165static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200167#if defined(SIGUSR1)
168static RETSIGTYPE catch_sigusr1 SIGPROTOARG;
169#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100171static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172#endif
173#if defined(SIGALRM) && defined(FEAT_X11) \
174 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
175# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100176static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100177// volatile because it is used in signal handler sig_alarm().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200178static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100180static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100182static void catch_int_signal(void);
183static void set_signals(void);
184static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200185#ifdef HAVE_SIGPROCMASK
186# define SIGSET_DECL(set) sigset_t set;
187# define BLOCK_SIGNALS(set) block_signals(set)
188# define UNBLOCK_SIGNALS(set) unblock_signals(set)
189#else
190# define SIGSET_DECL(set)
191# define BLOCK_SIGNALS(set) do { /**/ } while (0)
192# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
193#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100194static int have_wildcard(int, char_u **);
195static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100197static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198
199#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000200# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#endif
202
Bram Moolenaar0f873732019-12-05 20:28:46 +0100203// volatile because it is used in signal handler sig_winch().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200204static volatile sig_atomic_t do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205static char_u *extra_shell_arg = NULL;
206static int show_shell_mess = TRUE;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100207// volatile because it is used in signal handler deathtrap().
208static volatile sig_atomic_t deadly_signal = 0; // The signal we caught
209// volatile because it is used in signal handler deathtrap().
210static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100212#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
213static int dont_check_job_ended = 0;
214#endif
215
Bram Moolenaar26e86442020-05-17 14:06:16 +0200216// Current terminal mode from mch_settmode(). Can differ from cur_tmode.
217static tmode_T mch_cur_tmode = TMODE_COOK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218
219#ifdef USE_XSMP
220typedef struct
221{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100222 SmcConn smcconn; // The SM connection ID
223 IceConn iceconn; // The ICE connection ID
224 char *clientid; // The client ID for the current smc session
225 Bool save_yourself; // If we're in the middle of a save_yourself
226 Bool shutdown; // If we're in shutdown mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227} xsmp_config_T;
228
229static xsmp_config_T xsmp;
230#endif
231
232#ifdef SYS_SIGLIST_DECLARED
233/*
234 * I have seen
235 * extern char *_sys_siglist[NSIG];
236 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
237 * that describe the signals. That is nearly what we want here. But
238 * autoconf does only check for sys_siglist (without the underscore), I
239 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100240 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 */
242#endif
243
244static struct signalinfo
245{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100246 int sig; // Signal number, eg. SIGSEGV etc
247 char *name; // Signal name (not char_u!).
248 char deadly; // Catch as a deadly signal?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249} signal_info[] =
250{
251#ifdef SIGHUP
252 {SIGHUP, "HUP", TRUE},
253#endif
254#ifdef SIGQUIT
255 {SIGQUIT, "QUIT", TRUE},
256#endif
257#ifdef SIGILL
258 {SIGILL, "ILL", TRUE},
259#endif
260#ifdef SIGTRAP
261 {SIGTRAP, "TRAP", TRUE},
262#endif
263#ifdef SIGABRT
264 {SIGABRT, "ABRT", TRUE},
265#endif
266#ifdef SIGEMT
267 {SIGEMT, "EMT", TRUE},
268#endif
269#ifdef SIGFPE
270 {SIGFPE, "FPE", TRUE},
271#endif
272#ifdef SIGBUS
273 {SIGBUS, "BUS", TRUE},
274#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100275#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100276 // MzScheme uses SEGV in its garbage collector
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 {SIGSEGV, "SEGV", TRUE},
278#endif
279#ifdef SIGSYS
280 {SIGSYS, "SYS", TRUE},
281#endif
282#ifdef SIGALRM
Bram Moolenaar0f873732019-12-05 20:28:46 +0100283 {SIGALRM, "ALRM", FALSE}, // Perl's alarm() can trigger it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284#endif
285#ifdef SIGTERM
286 {SIGTERM, "TERM", TRUE},
287#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100288#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 {SIGVTALRM, "VTALRM", TRUE},
290#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000291#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100292 // MzScheme uses SIGPROF for its own needs; On Linux with profiling
293 // this makes Vim exit. WE_ARE_PROFILING is defined in Makefile.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294 {SIGPROF, "PROF", TRUE},
295#endif
296#ifdef SIGXCPU
297 {SIGXCPU, "XCPU", TRUE},
298#endif
299#ifdef SIGXFSZ
300 {SIGXFSZ, "XFSZ", TRUE},
301#endif
302#ifdef SIGUSR1
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200303 {SIGUSR1, "USR1", FALSE},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000304#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000305#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100306 // Used for sysmouse handling
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 {SIGUSR2, "USR2", TRUE},
308#endif
309#ifdef SIGINT
310 {SIGINT, "INT", FALSE},
311#endif
312#ifdef SIGWINCH
313 {SIGWINCH, "WINCH", FALSE},
314#endif
315#ifdef SIGTSTP
316 {SIGTSTP, "TSTP", FALSE},
317#endif
318#ifdef SIGPIPE
319 {SIGPIPE, "PIPE", FALSE},
320#endif
321 {-1, "Unknown!", FALSE}
322};
323
Bram Moolenaar25724922009-07-14 15:38:41 +0000324 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100325mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000326{
327 if (p_verbose >= 5)
328 {
329 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100330 smsg("chdir(%s)", path);
Bram Moolenaar25724922009-07-14 15:38:41 +0000331 verbose_leave();
332 }
333# ifdef VMS
334 return chdir(vms_fixfilename(path));
335# else
336 return chdir(path);
337# endif
338}
339
Bram Moolenaar0f873732019-12-05 20:28:46 +0100340// Why is NeXT excluded here (and not in os_unixx.h)?
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +0100341#if defined(ECHOE) && defined(ICANON) \
342 && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
343 && !defined(__NeXT__)
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200344# define NEW_TTY_SYSTEM
345#endif
346
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000347/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100348 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000349 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100351mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200353 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100354 if (p_wd) // Unix is too fast, slow down a bit more
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100355 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356}
357
358/*
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100359 * Function passed to inchar_loop() to handle window resizing.
360 * If "check_only" is TRUE: Return whether there was a resize.
361 * If "check_only" is FALSE: Deal with the window resized.
362 */
363 static int
364resize_func(int check_only)
365{
366 if (check_only)
367 return do_resize;
368 while (do_resize)
369 handle_resize();
370 return FALSE;
371}
372
373/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000374 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 * Get a characters from the keyboard.
376 * Return the number of characters that are available.
377 * If wtime == 0 do not wait for characters.
378 * If wtime == n wait a short time for characters.
379 * If wtime == -1 wait forever for characters.
380 */
381 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100382mch_inchar(
383 char_u *buf,
384 int maxlen,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100385 long wtime, // don't use "time", MIPS cannot handle it
Bram Moolenaar05540972016-01-30 20:31:25 +0100386 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387{
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100388 return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
389 WaitForChar, resize_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390}
391
392 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100393handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394{
395 do_resize = FALSE;
396 shell_resized();
397}
398
399/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200400 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401 */
402 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100403mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200405 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406}
407
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200408#if defined(FEAT_TERMINAL) || defined(PROTO)
409/*
410 * Check for any pending input or messages.
411 */
412 int
413mch_check_messages(void)
414{
415 return WaitForChar(0L, NULL, TRUE);
416}
417#endif
418
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
420# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000421# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422# endif
423# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
424# include <sys/sysctl.h>
425# endif
426# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
427# include <sys/sysinfo.h>
428# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100429# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100430# include <mach/mach_host.h>
431# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100432# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433
434/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000435 * Return total amount of memory available in Kbyte.
436 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100439mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 long_u mem = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100442 long_u shiftright = 10; // how much to shift "mem" right for Kbyte
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
Bram Moolenaar362dc332018-03-05 21:59:37 +0100444# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100445 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100446 // Mac (Darwin) way of getting the amount of RAM available
Bram Moolenaar988615f2018-02-27 17:58:20 +0100447 mach_port_t host = mach_host_self();
448 kern_return_t kret;
449# ifdef HOST_VM_INFO64
450 struct vm_statistics64 vm_stat;
451 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452
Bram Moolenaar988615f2018-02-27 17:58:20 +0100453 kret = host_statistics64(host, HOST_VM_INFO64,
454 (host_info64_t)&vm_stat, &count);
455# else
456 struct vm_statistics vm_stat;
457 natural_t count = HOST_VM_INFO_COUNT;
458
459 kret = host_statistics(host, HOST_VM_INFO,
460 (host_info_t)&vm_stat, &count);
461# endif
462 if (kret == KERN_SUCCESS)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100463 // get the amount of user memory by summing each usage
Bram Moolenaar988615f2018-02-27 17:58:20 +0100464 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
465 + vm_stat.inactive_count
466# ifdef MAC_OS_X_VERSION_10_9
467 + vm_stat.compressor_page_count
468# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100469 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100470 mach_port_deallocate(mach_task_self(), host);
471 }
472# endif
473
474# ifdef HAVE_SYSCTL
475 if (mem == 0)
476 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100477 // BSD way of getting the amount of RAM available.
Bram Moolenaar988615f2018-02-27 17:58:20 +0100478 int mib[2];
479 size_t len = sizeof(long_u);
480# ifdef HW_USERMEM64
481 long_u physmem;
482# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100483 // sysctl() may return 32 bit or 64 bit, accept both
Bram Moolenaar988615f2018-02-27 17:58:20 +0100484 union {
485 int_u u32;
486 long_u u64;
487 } physmem;
488# endif
489
490 mib[0] = CTL_HW;
491# ifdef HW_USERMEM64
492 mib[1] = HW_USERMEM64;
493# else
494 mib[1] = HW_USERMEM;
495# endif
496 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
497 {
498# ifdef HW_USERMEM64
499 mem = (long_u)physmem;
500# else
501 if (len == sizeof(physmem.u64))
502 mem = (long_u)physmem.u64;
503 else
504 mem = (long_u)physmem.u32;
505# endif
506 }
507 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200508# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200510# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 if (mem == 0)
512 {
513 struct sysinfo sinfo;
514
Bram Moolenaar0f873732019-12-05 20:28:46 +0100515 // Linux way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000517 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200518# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100519 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000520 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
521 {
522 sinfo.mem_unit = sinfo.mem_unit >> 1;
523 --shiftright;
524 }
525 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200526# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200528# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000529 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200531# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200533# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 if (mem == 0)
535 {
536 long pagesize, pagecount;
537
Bram Moolenaar0f873732019-12-05 20:28:46 +0100538 // Solaris way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539 pagesize = sysconf(_SC_PAGESIZE);
540 pagecount = sysconf(_SC_PHYS_PAGES);
541 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000542 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100543 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000544 while (shiftright > 0 && (pagesize & 1) == 0)
545 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000546 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000547 --shiftright;
548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200552# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553
Bram Moolenaar0f873732019-12-05 20:28:46 +0100554 // Return the minimum of the physical memory and the user limit, because
555 // using more than the user limit may cause Vim to be terminated.
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200556# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 {
558 struct rlimit rlp;
559
560 if (getrlimit(RLIMIT_DATA, &rlp) == 0
561 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200562# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200564# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000565 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000567 {
568 mem = (long_u)rlp.rlim_cur;
569 shiftright = 10;
570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200572# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573
574 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000575 return mem >> shiftright;
576 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577}
578#endif
579
Bram Moolenaar0981c872020-08-23 14:28:37 +0200580/*
581 * "flags": MCH_DELAY_IGNOREINPUT - don't read input
582 * MCH_DELAY_SETTMODE - use settmode() even for short delays
583 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 void
Bram Moolenaar0981c872020-08-23 14:28:37 +0200585mch_delay(long msec, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586{
Bram Moolenaar26e86442020-05-17 14:06:16 +0200587 tmode_T old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000588#ifdef FEAT_MZSCHEME
Bram Moolenaar0f873732019-12-05 20:28:46 +0100589 long total = msec; // remember original value
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000590#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591
Bram Moolenaar0981c872020-08-23 14:28:37 +0200592 if (flags & MCH_DELAY_IGNOREINPUT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100594 // Go to cooked mode without echo, to allow SIGINT interrupting us
595 // here. But we don't want QUIT to kill us (CTRL-\ used in a
596 // shell may produce SIGQUIT).
Bram Moolenaar26e86442020-05-17 14:06:16 +0200597 // Only do this if sleeping for more than half a second.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000598 in_mch_delay = TRUE;
Bram Moolenaar26e86442020-05-17 14:06:16 +0200599 old_tmode = mch_cur_tmode;
Bram Moolenaar0981c872020-08-23 14:28:37 +0200600 if (mch_cur_tmode == TMODE_RAW
601 && (msec > 500 || (flags & MCH_DELAY_SETTMODE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 settmode(TMODE_SLEEP);
603
604 /*
605 * Everybody sleeps in a different way...
606 * Prefer nanosleep(), some versions of usleep() can only sleep up to
607 * one second.
608 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000609#ifdef FEAT_MZSCHEME
610 do
611 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100612 // if total is large enough, wait by portions in p_mzq
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000613 if (total > p_mzq)
614 msec = p_mzq;
615 else
616 msec = total;
617 total -= msec;
618#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619#ifdef HAVE_NANOSLEEP
620 {
621 struct timespec ts;
622
623 ts.tv_sec = msec / 1000;
624 ts.tv_nsec = (msec % 1000) * 1000000;
625 (void)nanosleep(&ts, NULL);
626 }
627#else
628# ifdef HAVE_USLEEP
629 while (msec >= 1000)
630 {
631 usleep((unsigned int)(999 * 1000));
632 msec -= 999;
633 }
634 usleep((unsigned int)(msec * 1000));
635# else
636# ifndef HAVE_SELECT
637 poll(NULL, 0, (int)msec);
638# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 {
640 struct timeval tv;
641
642 tv.tv_sec = msec / 1000;
643 tv.tv_usec = (msec % 1000) * 1000;
Bram Moolenaar0981c872020-08-23 14:28:37 +0200644 // NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
645 // a patch from Sun to fix this. Reported by Gunnar Pedersen.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 select(0, NULL, NULL, NULL, &tv);
647 }
Bram Moolenaar0f873732019-12-05 20:28:46 +0100648# endif // HAVE_SELECT
649# endif // HAVE_NANOSLEEP
650#endif // HAVE_USLEEP
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000651#ifdef FEAT_MZSCHEME
652 }
653 while (total > 0);
654#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655
Bram Moolenaar0981c872020-08-23 14:28:37 +0200656 if (msec > 500 || (flags & MCH_DELAY_SETTMODE))
Bram Moolenaar26e86442020-05-17 14:06:16 +0200657 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000658 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659 }
660 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200661 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662}
663
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000664#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
666# define HAVE_CHECK_STACK_GROWTH
667/*
668 * Support for checking for an almost-out-of-stack-space situation.
669 */
670
671/*
672 * Return a pointer to an item on the stack. Used to find out if the stack
673 * grows up or down.
674 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675static int stack_grows_downwards;
676
677/*
678 * Find out if the stack grows upwards or downwards.
679 * "p" points to a variable on the stack of the caller.
680 */
681 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100682check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683{
684 int i;
685
686 stack_grows_downwards = (p > (char *)&i);
687}
688#endif
689
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000690#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691static char *stack_limit = NULL;
692
693#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
694# include <pthread.h>
695# include <pthread_np.h>
696#endif
697
698/*
699 * Find out until how var the stack can grow without getting into trouble.
700 * Called when starting up and when switching to the signal stack in
701 * deathtrap().
702 */
703 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100704get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705{
706 struct rlimit rlp;
707 int i;
708 long lim;
709
Bram Moolenaar0f873732019-12-05 20:28:46 +0100710 // Set the stack limit to 15/16 of the allowable size. Skip this when the
711 // limit doesn't fit in a long (rlim_cur might be "long long").
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712 if (getrlimit(RLIMIT_STACK, &rlp) == 0
713 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
714# ifdef RLIM_INFINITY
715 && rlp.rlim_cur != RLIM_INFINITY
716# endif
717 )
718 {
719 lim = (long)rlp.rlim_cur;
720#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
721 {
722 pthread_attr_t attr;
723 size_t size;
724
Bram Moolenaar0f873732019-12-05 20:28:46 +0100725 // On FreeBSD the initial thread always has a fixed stack size, no
726 // matter what the limits are set to. Normally it's 1 Mbyte.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 pthread_attr_init(&attr);
728 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
729 {
730 pthread_attr_getstacksize(&attr, &size);
731 if (lim > (long)size)
732 lim = (long)size;
733 }
734 pthread_attr_destroy(&attr);
735 }
736#endif
737 if (stack_grows_downwards)
738 {
739 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
740 if (stack_limit >= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100741 // overflow, set to 1/16 of current stack position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 stack_limit = (char *)((long)&i / 16L);
743 }
744 else
745 {
746 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
747 if (stack_limit <= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100748 stack_limit = NULL; // overflow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 }
750 }
751}
752
753/*
754 * Return FAIL when running out of stack space.
755 * "p" must point to any variable local to the caller that's on the stack.
756 */
757 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100758mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759{
760 if (stack_limit != NULL)
761 {
762 if (stack_grows_downwards)
763 {
764 if (p < stack_limit)
765 return FAIL;
766 }
767 else if (p > stack_limit)
768 return FAIL;
769 }
770 return OK;
771}
772#endif
773
774#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
775/*
776 * Support for using the signal stack.
777 * This helps when we run out of stack space, which causes a SIGSEGV. The
778 * signal handler then must run on another stack, since the normal stack is
779 * completely full.
780 */
781
782#ifndef SIGSTKSZ
Bram Moolenaar0f873732019-12-05 20:28:46 +0100783# define SIGSTKSZ 8000 // just a guess of how much stack is needed...
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784#endif
785
786# ifdef HAVE_SIGALTSTACK
Bram Moolenaar0f873732019-12-05 20:28:46 +0100787static stack_t sigstk; // for sigaltstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100789static struct sigstack sigstk; // for sigstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790# endif
791
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792static char *signal_stack;
793
794 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100795init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796{
797 if (signal_stack != NULL)
798 {
799# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800# ifdef HAVE_SS_BASE
801 sigstk.ss_base = signal_stack;
802# else
803 sigstk.ss_sp = signal_stack;
804# endif
805 sigstk.ss_size = SIGSTKSZ;
806 sigstk.ss_flags = 0;
807 (void)sigaltstack(&sigstk, NULL);
808# else
809 sigstk.ss_sp = signal_stack;
810 if (stack_grows_downwards)
811 sigstk.ss_sp += SIGSTKSZ - 1;
812 sigstk.ss_onstack = 0;
813 (void)sigstack(&sigstk, NULL);
814# endif
815 }
816}
817#endif
818
819/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000820 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 * will barf when the second argument to signal() is ``wrong''.
822 * Let me try it with a few tricky defines from my own osdef.h (jw).
823 */
824#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 static RETSIGTYPE
826sig_winch SIGDEFARG(sigarg)
827{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100828 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
830 do_resize = TRUE;
831 SIGRETURN;
832}
833#endif
834
835#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 static RETSIGTYPE
837catch_sigint SIGDEFARG(sigarg)
838{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100839 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000840 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
841 got_int = TRUE;
842 SIGRETURN;
843}
844#endif
845
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200846#if defined(SIGUSR1)
847 static RETSIGTYPE
848catch_sigusr1 SIGDEFARG(sigarg)
849{
850 // this is not required on all systems, but it doesn't hurt anybody
851 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
852 got_sigusr1 = TRUE;
853 SIGRETURN;
854}
855#endif
856
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 static RETSIGTYPE
859catch_sigpwr SIGDEFARG(sigarg)
860{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100861 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000862 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 /*
864 * I'm not sure we get the SIGPWR signal when the system is really going
865 * down or when the batteries are almost empty. Just preserve the swap
866 * files and don't exit, that can't do any harm.
867 */
868 ml_sync_all(FALSE, FALSE);
869 SIGRETURN;
870}
871#endif
872
873#ifdef SET_SIG_ALARM
874/*
875 * signal function for alarm().
876 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 static RETSIGTYPE
878sig_alarm SIGDEFARG(sigarg)
879{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100880 // doesn't do anything, just to break a system call
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881 sig_alarm_called = TRUE;
882 SIGRETURN;
883}
884#endif
885
Bram Moolenaaredce7422019-01-20 18:39:30 +0100886#if (defined(HAVE_SETJMP_H) \
887 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
888 || defined(FEAT_LIBCALL))) \
889 || defined(PROTO)
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100890# define USING_SETJMP 1
Bram Moolenaaredce7422019-01-20 18:39:30 +0100891
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100892// argument to SETJMP()
893static JMP_BUF lc_jump_env;
894
895# ifdef SIGHASARG
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100896// Caught signal number, 0 when no signal was caught; used for mch_libcall().
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100897// Volatile because it is used in signal handlers.
898static volatile sig_atomic_t lc_signal;
899# endif
900
901// TRUE when lc_jump_env is valid.
902// Volatile because it is used in signal handler deathtrap().
903static volatile sig_atomic_t lc_active INIT(= FALSE);
904
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905/*
906 * A simplistic version of setjmp() that only allows one level of using.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100907 * Used to protect areas where we could crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908 * Don't call twice before calling mch_endjmp()!.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100909 *
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910 * Usage:
911 * mch_startjmp();
912 * if (SETJMP(lc_jump_env) != 0)
913 * {
914 * mch_didjmp();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100915 * emsg("crash!");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 * }
917 * else
918 * {
919 * do_the_work;
920 * mch_endjmp();
921 * }
922 * Note: Can't move SETJMP() here, because a function calling setjmp() must
923 * not return before the saved environment is used.
924 * Returns OK for normal return, FAIL when the protected code caused a
925 * problem and LONGJMP() was used.
926 */
Bram Moolenaar113e1072019-01-20 15:30:40 +0100927 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100928mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000929{
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100930# ifdef SIGHASARG
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 lc_signal = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100932# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 lc_active = TRUE;
934}
935
Bram Moolenaar113e1072019-01-20 15:30:40 +0100936 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100937mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938{
939 lc_active = FALSE;
940}
941
Bram Moolenaar113e1072019-01-20 15:30:40 +0100942 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100943mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944{
945# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100946 // On FreeBSD the signal stack has to be reset after using siglongjmp(),
947 // otherwise catching the signal only works once.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948 init_signal_stack();
949# endif
950}
951#endif
952
953/*
954 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200955 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200957 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
958 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 */
960 static RETSIGTYPE
961deathtrap SIGDEFARG(sigarg)
962{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100963 static int entered = 0; // count the number of times we got here.
964 // Note: when memory has been corrupted
965 // this may get an arbitrary value!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966#ifdef SIGHASARG
967 int i;
968#endif
969
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100970#if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 /*
972 * Catch a crash in protected code.
973 * Restores the environment saved in lc_jump_env, which looks like
974 * SETJMP() returns 1.
975 */
976 if (lc_active)
977 {
978# if defined(SIGHASARG)
979 lc_signal = sigarg;
980# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +0100981 lc_active = FALSE; // don't jump again
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982 LONGJMP(lc_jump_env, 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100983 // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984 }
985#endif
986
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000987#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000988# ifdef SIGQUIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100989 // While in mch_delay() we go to cooked mode to allow a CTRL-C to
990 // interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
991 // pressing CTRL-\, but we don't want Vim to exit then.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000992 if (in_mch_delay && sigarg == SIGQUIT)
993 SIGRETURN;
994# endif
995
Bram Moolenaar0f873732019-12-05 20:28:46 +0100996 // When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
997 // here. This avoids that a non-reentrant function is interrupted, e.g.,
998 // free(). Calling free() again may then cause a crash.
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000999 if (entered == 0
1000 && (0
1001# ifdef SIGHUP
1002 || sigarg == SIGHUP
1003# endif
1004# ifdef SIGQUIT
1005 || sigarg == SIGQUIT
1006# endif
1007# ifdef SIGTERM
1008 || sigarg == SIGTERM
1009# endif
1010# ifdef SIGPWR
1011 || sigarg == SIGPWR
1012# endif
1013# ifdef SIGUSR1
1014 || sigarg == SIGUSR1
1015# endif
1016# ifdef SIGUSR2
1017 || sigarg == SIGUSR2
1018# endif
1019 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001020 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001021 SIGRETURN;
1022#endif
1023
Bram Moolenaar0f873732019-12-05 20:28:46 +01001024 // Remember how often we have been called.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025 ++entered;
1026
Bram Moolenaar0f873732019-12-05 20:28:46 +01001027 // Executing autocommands is likely to use more stack space than we have
1028 // available in the signal stack.
Bram Moolenaare429e702016-06-10 19:49:14 +02001029 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001030
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031#ifdef FEAT_EVAL
Bram Moolenaar0f873732019-12-05 20:28:46 +01001032 // Set the v:dying variable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 set_vim_var_nr(VV_DYING, (long)entered);
1034#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001035 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001037#ifdef HAVE_STACK_LIMIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001038 // Since we are now using the signal stack, need to reset the stack
1039 // limit. Otherwise using a regexp will fail.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 get_stack_limit();
1041#endif
1042
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001043#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01001044 // This is for opening gdb the moment Vim crashes.
1045 // You need to manually adjust the file name and Vim executable name.
1046 // Suggested by SungHyun Nam.
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001047 {
1048# define VI_GDB_FILE "/tmp/vimgdb"
1049# define VIM_NAME "/usr/bin/vim"
1050 FILE *fp = fopen(VI_GDB_FILE, "w");
1051 if (fp)
1052 {
1053 fprintf(fp,
1054 "file %s\n"
1055 "attach %d\n"
1056 "set height 1000\n"
1057 "bt full\n"
1058 , VIM_NAME, getpid());
1059 fclose(fp);
1060 system("xterm -e gdb -x "VI_GDB_FILE);
1061 unlink(VI_GDB_FILE);
1062 }
1063 }
1064#endif
1065
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066#ifdef SIGHASARG
Bram Moolenaar0f873732019-12-05 20:28:46 +01001067 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 for (i = 0; signal_info[i].sig != -1; i++)
1069 if (sigarg == signal_info[i].sig)
1070 break;
1071 deadly_signal = sigarg;
1072#endif
1073
Bram Moolenaar0f873732019-12-05 20:28:46 +01001074 full_screen = FALSE; // don't write message to the GUI, it might be
1075 // part of the problem...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 /*
1077 * If something goes wrong after entering here, we may get here again.
1078 * When this happens, give a message and try to exit nicely (resetting the
1079 * terminal mode, etc.)
1080 * When this happens twice, just exit, don't even try to give a message,
1081 * stack may be corrupt or something weird.
1082 * When this still happens again (or memory was corrupted in such a way
1083 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1084 */
1085 if (entered >= 3)
1086 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001087 reset_signals(); // don't catch any signals anymore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 may_core_dump();
1089 if (entered >= 4)
1090 _exit(8);
1091 exit(7);
1092 }
1093 if (entered == 2)
1094 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001095 // No translation, it may call malloc().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001096 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 out_flush();
1098 getout(1);
1099 }
1100
Bram Moolenaar0f873732019-12-05 20:28:46 +01001101 // No translation, it may call malloc().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102#ifdef SIGHASARG
Bram Moolenaar69212b12020-05-10 14:14:03 +02001103 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 signal_info[i].name);
1105#else
Bram Moolenaar69212b12020-05-10 14:14:03 +02001106 sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001108
Bram Moolenaar0f873732019-12-05 20:28:46 +01001109 // Preserve files and exit. This sets the really_exiting flag to prevent
1110 // calling free().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001111 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112
Bram Moolenaar0f873732019-12-05 20:28:46 +01001113 // NOTREACHED
Bram Moolenaare429e702016-06-10 19:49:14 +02001114
Bram Moolenaar009b2592004-10-24 19:18:58 +00001115#ifdef NBDEBUG
1116 reset_signals();
1117 may_core_dump();
1118 abort();
1119#endif
1120
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 SIGRETURN;
1122}
1123
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001125 * Invoked after receiving SIGCONT. We don't know what happened while
1126 * sleeping, deal with part of that.
1127 */
1128 static void
1129after_sigcont(void)
1130{
1131# ifdef FEAT_TITLE
1132 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1133 // again later.
1134 oldtitle_outdated = TRUE;
1135# endif
1136 settmode(TMODE_RAW);
1137 need_check_timestamps = TRUE;
1138 did_check_timestamps = FALSE;
1139}
1140
1141#if defined(SIGCONT)
1142static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001143static volatile sig_atomic_t in_mch_suspend = FALSE;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001144
1145/*
1146 * With multi-threading, suspending might not work immediately. Catch the
1147 * SIGCONT signal, which will be used as an indication whether the suspending
1148 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001149 *
1150 * On Linux, signal is not always handled immediately either.
1151 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001152 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001153 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001154 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001156static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001157static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158
1159/*
1160 * signal handler for SIGCONT
1161 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162 static RETSIGTYPE
1163sigcont_handler SIGDEFARG(sigarg)
1164{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001165 if (in_mch_suspend)
1166 {
1167 sigcont_received = TRUE;
1168 }
1169 else
1170 {
1171 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1172 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1173 // back to a sane mode. We should redraw, but we can't really do that
1174 // in a signal handler, do a redraw later.
1175 after_sigcont();
1176 redraw_later(CLEAR);
1177 cursor_on_force();
1178 out_flush();
1179 }
1180
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 SIGRETURN;
1182}
1183#endif
1184
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001185#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001186# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001187static void *clip_star_save = NULL;
1188static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001189# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001190
1191/*
1192 * Called when Vim is going to sleep or execute a shell command.
1193 * We can't respond to requests for the X selections. Lose them, otherwise
1194 * other applications will hang. But first copy the text to cut buffer 0.
1195 */
1196 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001197loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001198{
1199 if (clip_star.owned || clip_plus.owned)
1200 {
1201 x11_export_final_selection();
1202 if (clip_star.owned)
1203 clip_lose_selection(&clip_star);
1204 if (clip_plus.owned)
1205 clip_lose_selection(&clip_plus);
1206 if (x11_display != NULL)
1207 XFlush(x11_display);
1208 }
1209}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001210
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001211# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001212/*
1213 * Save clipboard text to restore later.
1214 */
1215 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001216save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001217{
1218 if (clip_star.owned)
1219 clip_star_save = get_register('*', TRUE);
1220 if (clip_plus.owned)
1221 clip_plus_save = get_register('+', TRUE);
1222}
1223
1224/*
1225 * Restore clipboard text if no one own the X selection.
1226 */
1227 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001228restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001229{
1230 if (clip_star_save != NULL)
1231 {
1232 if (!clip_gen_owner_exists(&clip_star))
1233 put_register('*', clip_star_save);
1234 else
1235 free_register(clip_star_save);
1236 clip_star_save = NULL;
1237 }
1238 if (clip_plus_save != NULL)
1239 {
1240 if (!clip_gen_owner_exists(&clip_plus))
1241 put_register('+', clip_plus_save);
1242 else
1243 free_register(clip_plus_save);
1244 clip_plus_save = NULL;
1245 }
1246}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001247# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001248#endif
1249
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250/*
1251 * If the machine has job control, use it to suspend the program,
1252 * otherwise fake it by starting a new shell.
1253 */
1254 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001255mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256{
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001257 if (ignore_sigtstp)
1258 return;
1259
Bram Moolenaar041c7102020-05-30 18:14:57 +02001260#if defined(SIGTSTP)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001261 in_mch_suspend = TRUE;
1262
Bram Moolenaar0f873732019-12-05 20:28:46 +01001263 out_flush(); // needed to make cursor visible on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264 settmode(TMODE_COOK);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001265 out_flush(); // needed to disable mouse on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266
1267# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001268 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001270# if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 sigcont_received = FALSE;
1272# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001273
Bram Moolenaar0f873732019-12-05 20:28:46 +01001274 kill(0, SIGTSTP); // send ourselves a STOP signal
Bram Moolenaar2e310482018-08-21 13:09:10 +02001275
1276# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001277 /*
1278 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001279 * immediately, but somehow not all the time, probably because it's handled
1280 * in another thread. Do not call pause() because there would be race
1281 * condition which would hang Vim if signal happened in between the test of
1282 * sigcont_received and the call to pause(). If signal is not yet received,
1283 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1284 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001285 */
1286 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001287 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001288
Bram Moolenaar262735e2009-07-14 10:20:22 +00001289 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar0981c872020-08-23 14:28:37 +02001290 mch_delay(wait_time, 0);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001291 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001293 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294
Bram Moolenaar2e310482018-08-21 13:09:10 +02001295 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296#else
1297 suspend_shell();
1298#endif
1299}
1300
1301 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001302mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303{
1304 Columns = 80;
1305 Rows = 24;
1306
1307 out_flush();
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001308
1309#ifdef SIGTSTP
1310 // Check whether we were invoked with SIGTSTP set to be ignored. If it is
1311 // that indicates the shell (or program) that launched us does not support
1312 // tty job control and thus we should ignore that signal. If invoked as a
1313 // restricted editor (e.g., as "rvim") SIGTSTP is always ignored.
1314 ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR);
1315#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001317
Bram Moolenaar56718732006-03-15 22:53:57 +00001318#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001319 mac_conv_init();
1320#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001321#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1322 win_clip_init();
1323#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001324}
1325
1326 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001327set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328{
1329#if defined(SIGWINCH)
1330 /*
1331 * WINDOW CHANGE signal is handled with sig_winch().
1332 */
1333 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1334#endif
1335
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336#ifdef SIGTSTP
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001337 // See mch_init() for the conditions under which we ignore SIGTSTP.
1338 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001340#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 signal(SIGCONT, sigcont_handler);
1342#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001343#ifdef SIGPIPE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344 /*
1345 * We want to ignore breaking of PIPEs.
1346 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001347 signal(SIGPIPE, SIG_IGN);
1348#endif
1349
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001351 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352#endif
1353
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001354#ifdef SIGUSR1
1355 /*
1356 * Call user's handler on SIGUSR1
1357 */
1358 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
1359#endif
1360
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361 /*
1362 * Ignore alarm signals (Perl's alarm() generates it).
1363 */
1364#ifdef SIGALRM
1365 signal(SIGALRM, SIG_IGN);
1366#endif
1367
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001368#ifdef SIGPWR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369 /*
1370 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1371 * work will be lost.
1372 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1374#endif
1375
1376 /*
1377 * Arrange for other signals to gracefully shutdown Vim.
1378 */
1379 catch_signals(deathtrap, SIG_ERR);
1380
1381#if defined(FEAT_GUI) && defined(SIGHUP)
1382 /*
1383 * When the GUI is running, ignore the hangup signal.
1384 */
1385 if (gui.in_use)
1386 signal(SIGHUP, SIG_IGN);
1387#endif
1388}
1389
Bram Moolenaardf177f62005-02-22 08:39:57 +00001390#if defined(SIGINT) || defined(PROTO)
1391/*
1392 * Catch CTRL-C (only works while in Cooked mode).
1393 */
1394 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001395catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001396{
1397 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1398}
1399#endif
1400
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001402reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403{
1404 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001405#if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001406 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 signal(SIGCONT, SIG_DFL);
1408#endif
1409}
1410
1411 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001412catch_signals(
1413 RETSIGTYPE (*func_deadly)(),
1414 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415{
1416 int i;
1417
1418 for (i = 0; signal_info[i].sig != -1; i++)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001419 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001420 if (signal_info[i].deadly)
1421 {
1422#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1423 struct sigaction sa;
1424
Bram Moolenaar0f873732019-12-05 20:28:46 +01001425 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426 sa.sa_handler = func_deadly;
1427 sigemptyset(&sa.sa_mask);
1428# if defined(__linux__) && defined(_REENTRANT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001429 // On Linux, with glibc compiled for kernel 2.2, there is a bug in
1430 // thread handling in combination with using the alternate stack:
1431 // pthread library functions try to use the stack pointer to
1432 // identify the current thread, causing a SEGV signal, which
1433 // recursively calls deathtrap() and hangs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001434 sa.sa_flags = 0;
1435# else
1436 sa.sa_flags = SA_ONSTACK;
1437# endif
1438 sigaction(signal_info[i].sig, &sa, NULL);
1439#else
1440# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1441 struct sigvec sv;
1442
Bram Moolenaar0f873732019-12-05 20:28:46 +01001443 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001444 sv.sv_handler = func_deadly;
1445 sv.sv_mask = 0;
1446 sv.sv_flags = SV_ONSTACK;
1447 sigvec(signal_info[i].sig, &sv, NULL);
1448# else
1449 signal(signal_info[i].sig, func_deadly);
1450# endif
1451#endif
1452 }
1453 else if (func_other != SIG_ERR)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001454 {
1455 // Deal with non-deadly signals.
1456#ifdef SIGTSTP
1457 signal(signal_info[i].sig,
1458 signal_info[i].sig == SIGTSTP && ignore_sigtstp
1459 ? SIG_IGN : func_other);
1460#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461 signal(signal_info[i].sig, func_other);
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001462#endif
1463 }
1464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465}
1466
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001467#ifdef HAVE_SIGPROCMASK
1468 static void
1469block_signals(sigset_t *set)
1470{
1471 sigset_t newset;
1472 int i;
1473
1474 sigemptyset(&newset);
1475
1476 for (i = 0; signal_info[i].sig != -1; i++)
1477 sigaddset(&newset, signal_info[i].sig);
1478
Bram Moolenaar2e310482018-08-21 13:09:10 +02001479# if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001480 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001481 sigaddset(&newset, SIGCONT);
1482# endif
1483
1484 sigprocmask(SIG_BLOCK, &newset, set);
1485}
1486
1487 static void
1488unblock_signals(sigset_t *set)
1489{
1490 sigprocmask(SIG_SETMASK, set, NULL);
1491}
1492#endif
1493
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001495 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001496 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1497 * return TRUE
1498 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1499 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001500 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001501 * Returns TRUE when Vim should exit.
1502 */
1503 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001504vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001505{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001506 static int got_signal = 0;
1507 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001508
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001509 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001510 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001511 case SIGNAL_BLOCK: blocked = TRUE;
1512 break;
1513
1514 case SIGNAL_UNBLOCK: blocked = FALSE;
1515 if (got_signal != 0)
1516 {
1517 kill(getpid(), got_signal);
1518 got_signal = 0;
1519 }
1520 break;
1521
1522 default: if (!blocked)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001523 return TRUE; // exit!
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001524 got_signal = sig;
1525#ifdef SIGPWR
1526 if (sig != SIGPWR)
1527#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001528 got_int = TRUE; // break any loops
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001529 break;
1530 }
1531 return FALSE;
1532}
1533
1534/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535 * Check_win checks whether we have an interactive stdout.
1536 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001538mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 if (isatty(1))
1541 return OK;
1542 return FAIL;
1543}
1544
1545/*
1546 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1547 */
1548 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001549mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550{
1551 if (isatty(read_cmd_fd))
1552 return TRUE;
1553 return FALSE;
1554}
1555
1556#ifdef FEAT_X11
1557
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001558# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1560
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561/*
1562 * Give a message about the elapsed time for opening the X window.
1563 */
1564 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001565xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001567 smsg(_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568}
1569# endif
1570#endif
1571
1572#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1573/*
1574 * A few functions shared by X11 title and clipboard code.
1575 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576
1577static int got_x_error = FALSE;
1578
1579/*
1580 * X Error handler, otherwise X just exits! (very rude) -- webb
1581 */
1582 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001583x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001584{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001585 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586 STRCAT(IObuff, _("\nVim: Got X error\n"));
1587
Bram Moolenaarb1062eb2020-05-09 16:11:33 +02001588 // In the GUI we cannot print a message and continue, because no X calls
1589 // are allowed here (causes my system to hang). Silently continuing seems
1590 // like the best alternative. Do preserve files, in case we crash.
1591 ml_sync_all(FALSE, FALSE);
1592
1593#ifdef FEAT_GUI
1594 if (!gui.in_use)
1595#endif
1596 msg((char *)IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597
Bram Moolenaar0f873732019-12-05 20:28:46 +01001598 return 0; // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001599}
1600
1601/*
1602 * Another X Error handler, just used to check for errors.
1603 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001605x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606{
1607 got_x_error = TRUE;
1608 return 0;
1609}
1610
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001611/*
1612 * Return TRUE when connection to the X server is desired.
1613 */
1614 static int
1615x_connect_to_server(void)
1616{
1617 // No point in connecting if we are exiting or dying.
1618 if (exiting || v_dying)
1619 return FALSE;
1620
1621#if defined(FEAT_CLIENTSERVER)
1622 if (x_force_connect)
1623 return TRUE;
1624#endif
1625 if (x_no_connect)
1626 return FALSE;
1627
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001628 // Check for a match with "exclude:" from 'clipboard'.
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001629 if (clip_exclude_prog != NULL)
1630 {
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001631 // Just in case we get called recursively, return FALSE. This could
1632 // happen if vpeekc() is used while executing the prog and it causes a
1633 // related callback to be invoked.
1634 if (regprog_in_use(clip_exclude_prog))
1635 return FALSE;
1636
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001637 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
1638 return FALSE;
1639 }
1640 return TRUE;
1641}
1642
Bram Moolenaar071d4272004-06-13 20:20:40 +00001643#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001644# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645/*
1646 * An X IO Error handler, used to catch error while opening the display.
1647 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001649x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001651 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001652 LONGJMP(lc_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001653# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001654 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001655# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656}
1657# endif
1658
1659/*
1660 * An X IO Error handler, used to catch terminal errors.
1661 */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001662static int xterm_dpy_retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001665x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666{
1667 xterm_dpy = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001668 xterm_dpy_retry_count = 5; // Try reconnecting five times
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669 x11_window = 0;
1670 x11_display = NULL;
1671 xterm_Shell = (Widget)0;
1672
Bram Moolenaar0f873732019-12-05 20:28:46 +01001673 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 LONGJMP(x_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001675# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001676 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001677# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001679
1680/*
1681 * If the X11 connection was lost try to restore it.
1682 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001683 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001684 */
1685 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001686may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001687{
Bram Moolenaar01e51e52018-12-29 13:09:46 +01001688 // No point in restoring the connecting if we are exiting or dying.
1689 if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001690 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001691 --xterm_dpy_retry_count;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001692
1693# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01001694 // This has been reported to avoid Vim getting stuck.
Bram Moolenaar527a6782014-12-17 17:59:31 +01001695 if (app_context != (XtAppContext)NULL)
1696 {
1697 XtDestroyApplicationContext(app_context);
1698 app_context = (XtAppContext)NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001699 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaar527a6782014-12-17 17:59:31 +01001700 }
1701# endif
1702
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001703 setup_term_clip();
1704 get_x11_title(FALSE);
1705 }
1706}
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001707
1708 void
1709ex_xrestore(exarg_T *eap)
1710{
1711 if (eap->arg != NULL && STRLEN(eap->arg) > 0)
1712 {
1713 if (xterm_display_allocated)
1714 vim_free(xterm_display);
1715 xterm_display = (char *)vim_strsave(eap->arg);
1716 xterm_display_allocated = TRUE;
1717 }
1718 smsg(_("restoring display %s"), xterm_display == NULL
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +01001719 ? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001720
1721 clear_xterm_clip();
1722 x11_window = 0;
1723 xterm_dpy_retry_count = 5; // Try reconnecting five times
1724 may_restore_clipboard();
1725}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726#endif
1727
1728/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 * Test if "dpy" and x11_window are valid by getting the window title.
1730 * I don't actually want it yet, so there may be a simpler call to use, but
1731 * this will cause the error handler x_error_check() to be called if anything
1732 * is wrong, such as the window pointer being invalid (as can happen when the
1733 * user changes his DISPLAY, but not his WINDOWID) -- webb
1734 */
1735 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001736test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737{
1738 int (*old_handler)();
1739 XTextProperty text_prop;
1740
1741 old_handler = XSetErrorHandler(x_error_check);
1742 got_x_error = FALSE;
1743 if (XGetWMName(dpy, x11_window, &text_prop))
1744 XFree((void *)text_prop.value);
1745 XSync(dpy, False);
1746 (void)XSetErrorHandler(old_handler);
1747
1748 if (p_verbose > 0 && got_x_error)
Bram Moolenaar32526b32019-01-19 17:43:09 +01001749 verb_msg(_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750
1751 return (got_x_error ? FAIL : OK);
1752}
1753#endif
1754
1755#ifdef FEAT_TITLE
1756
1757#ifdef FEAT_X11
1758
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001759static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760
1761/*
1762 * try to get x11 window and display
1763 *
1764 * return FAIL for failure, OK otherwise
1765 */
1766 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001767get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768{
1769 char *winid;
1770 static int result = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001771#define XD_NONE 0 // x11_display not set here
1772#define XD_HERE 1 // x11_display opened here
1773#define XD_GUI 2 // x11_display used from gui.dpy
1774#define XD_XTERM 3 // x11_display used from xterm_dpy
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775 static int x11_display_from = XD_NONE;
1776 static int did_set_error_handler = FALSE;
1777
1778 if (!did_set_error_handler)
1779 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001780 // X just exits if it finds an error otherwise!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 (void)XSetErrorHandler(x_error_handler);
1782 did_set_error_handler = TRUE;
1783 }
1784
Bram Moolenaar9372a112005-12-06 19:59:18 +00001785#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786 if (gui.in_use)
1787 {
1788 /*
1789 * If the X11 display was opened here before, for the window where Vim
1790 * was started, close that one now to avoid a memory leak.
1791 */
1792 if (x11_display_from == XD_HERE && x11_display != NULL)
1793 {
1794 XCloseDisplay(x11_display);
1795 x11_display_from = XD_NONE;
1796 }
1797 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1798 {
1799 x11_display_from = XD_GUI;
1800 return OK;
1801 }
1802 x11_display = NULL;
1803 return FAIL;
1804 }
1805 else if (x11_display_from == XD_GUI)
1806 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001807 // GUI must have stopped somehow, clear x11_display
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 x11_window = 0;
1809 x11_display = NULL;
1810 x11_display_from = XD_NONE;
1811 }
1812#endif
1813
Bram Moolenaar0f873732019-12-05 20:28:46 +01001814 // When started with the "-X" argument, don't try connecting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 if (!x_connect_to_server())
1816 return FAIL;
1817
1818 /*
1819 * If WINDOWID not set, should try another method to find out
1820 * what the current window number is. The only code I know for
1821 * this is very complicated.
1822 * We assume that zero is invalid for WINDOWID.
1823 */
1824 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1825 x11_window = (Window)atol(winid);
1826
1827#ifdef FEAT_XCLIPBOARD
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001828 if (xterm_dpy == x11_display)
1829 // x11_display may have been set to xterm_dpy elsewhere
1830 x11_display_from = XD_XTERM;
1831
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 if (xterm_dpy != NULL && x11_window != 0)
1833 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001834 // We may have checked it already, but Gnome terminal can move us to
1835 // another window, so we need to check every time.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001836 if (x11_display_from != XD_XTERM)
1837 {
1838 /*
1839 * If the X11 display was opened here before, for the window where
1840 * Vim was started, close that one now to avoid a memory leak.
1841 */
1842 if (x11_display_from == XD_HERE && x11_display != NULL)
1843 XCloseDisplay(x11_display);
1844 x11_display = xterm_dpy;
1845 x11_display_from = XD_XTERM;
1846 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 if (test_x11_window(x11_display) == FAIL)
1848 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001849 // probably bad $WINDOWID
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 x11_window = 0;
1851 x11_display = NULL;
1852 x11_display_from = XD_NONE;
1853 return FAIL;
1854 }
1855 return OK;
1856 }
1857#endif
1858
1859 if (x11_window == 0 || x11_display == NULL)
1860 result = -1;
1861
Bram Moolenaar0f873732019-12-05 20:28:46 +01001862 if (result != -1) // Have already been here and set this
1863 return result; // Don't do all these X calls again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864
1865 if (x11_window != 0 && x11_display == NULL)
1866 {
1867#ifdef SET_SIG_ALARM
1868 RETSIGTYPE (*sig_save)();
1869#endif
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001870#ifdef ELAPSED_FUNC
1871 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872
1873 if (p_verbose > 0)
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001874 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875#endif
1876
1877#ifdef SET_SIG_ALARM
1878 /*
1879 * Opening the Display may hang if the DISPLAY setting is wrong, or
1880 * the network connection is bad. Set an alarm timer to get out.
1881 */
1882 sig_alarm_called = FALSE;
1883 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1884 (RETSIGTYPE (*)())sig_alarm);
1885 alarm(2);
1886#endif
1887 x11_display = XOpenDisplay(NULL);
1888
1889#ifdef SET_SIG_ALARM
1890 alarm(0);
1891 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1892 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaar563bbea2019-01-22 21:45:40 +01001893 verb_msg(_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894#endif
1895 if (x11_display != NULL)
1896 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001897# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001899 {
1900 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001901 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001902 verbose_leave();
1903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904# endif
1905 if (test_x11_window(x11_display) == FAIL)
1906 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001907 // Maybe window id is bad
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 x11_window = 0;
1909 XCloseDisplay(x11_display);
1910 x11_display = NULL;
1911 }
1912 else
1913 x11_display_from = XD_HERE;
1914 }
1915 }
1916 if (x11_window == 0 || x11_display == NULL)
1917 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001918
1919# ifdef FEAT_EVAL
1920 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1921# endif
1922
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 return (result = OK);
1924}
1925
1926/*
1927 * Determine original x11 Window Title
1928 */
1929 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001930get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001932 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933}
1934
1935/*
1936 * Determine original x11 Window icon
1937 */
1938 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001939get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940{
1941 int retval = FALSE;
1942
1943 retval = get_x11_thing(FALSE, test_only);
1944
Bram Moolenaar0f873732019-12-05 20:28:46 +01001945 // could not get old icon, use terminal name
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 if (oldicon == NULL && !test_only)
1947 {
1948 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001949 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001951 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 }
1953
1954 return retval;
1955}
1956
1957 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001958get_x11_thing(
Bram Moolenaar0f873732019-12-05 20:28:46 +01001959 int get_title, // get title string
Bram Moolenaar05540972016-01-30 20:31:25 +01001960 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961{
1962 XTextProperty text_prop;
1963 int retval = FALSE;
1964 Status status;
1965
1966 if (get_x11_windis() == OK)
1967 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001968 // Get window/icon name if any
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 if (get_title)
1970 status = XGetWMName(x11_display, x11_window, &text_prop);
1971 else
1972 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1973
1974 /*
1975 * If terminal is xterm, then x11_window may be a child window of the
1976 * outer xterm window that actually contains the window/icon name, so
1977 * keep traversing up the tree until a window with a title/icon is
1978 * found.
1979 */
Bram Moolenaar4b96df52020-01-26 22:00:26 +01001980 // Previously this was only done for xterm and alike. I don't see a
Bram Moolenaar0f873732019-12-05 20:28:46 +01001981 // reason why it would fail for other terminal emulators.
1982 // if (term_is_xterm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 {
1984 Window root;
1985 Window parent;
1986 Window win = x11_window;
1987 Window *children;
1988 unsigned int num_children;
1989
1990 while (!status || text_prop.value == NULL)
1991 {
1992 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1993 &num_children))
1994 break;
1995 if (children)
1996 XFree((void *)children);
1997 if (parent == root || parent == 0)
1998 break;
1999
2000 win = parent;
2001 if (get_title)
2002 status = XGetWMName(x11_display, win, &text_prop);
2003 else
2004 status = XGetWMIconName(x11_display, win, &text_prop);
2005 }
2006 }
2007 if (status && text_prop.value != NULL)
2008 {
2009 retval = TRUE;
2010 if (!test_only)
2011 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002012 if (get_title)
2013 vim_free(oldtitle);
2014 else
2015 vim_free(oldicon);
Bram Moolenaara12a1612019-01-24 16:39:02 +01002016 if (text_prop.encoding == XA_STRING && !has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 if (get_title)
2019 oldtitle = vim_strsave((char_u *)text_prop.value);
2020 else
2021 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022 }
2023 else
2024 {
2025 char **cl;
2026 Status transform_status;
2027 int n = 0;
2028
2029 transform_status = XmbTextPropertyToTextList(x11_display,
2030 &text_prop,
2031 &cl, &n);
2032 if (transform_status >= Success && n > 0 && cl[0])
2033 {
2034 if (get_title)
2035 oldtitle = vim_strsave((char_u *) cl[0]);
2036 else
2037 oldicon = vim_strsave((char_u *) cl[0]);
2038 XFreeStringList(cl);
2039 }
2040 else
2041 {
2042 if (get_title)
2043 oldtitle = vim_strsave((char_u *)text_prop.value);
2044 else
2045 oldicon = vim_strsave((char_u *)text_prop.value);
2046 }
2047 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 }
2049 XFree((void *)text_prop.value);
2050 }
2051 }
2052 return retval;
2053}
2054
Bram Moolenaar0f873732019-12-05 20:28:46 +01002055// Xutf8 functions are not available on older systems. Note that on some
2056// systems X_HAVE_UTF8_STRING may be defined in a header file but
2057// Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2058// that and defines HAVE_XUTF8SETWMPROPERTIES.
Bram Moolenaara12a1612019-01-24 16:39:02 +01002059#if defined(X_HAVE_UTF8_STRING)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002060# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061# define USE_UTF8_STRING
2062# endif
2063#endif
2064
2065/*
2066 * Set x11 Window Title
2067 *
2068 * get_x11_windis() must be called before this and have returned OK
2069 */
2070 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002071set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002073 // XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2074 // when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2075 // supported everywhere and STRING doesn't work for multi-byte titles.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076#ifdef USE_UTF8_STRING
2077 if (enc_utf8)
2078 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2079 NULL, NULL, 0, NULL, NULL, NULL);
2080 else
2081#endif
2082 {
2083#if XtSpecificationRelease >= 4
2084# ifdef FEAT_XFONTSET
2085 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2086 NULL, NULL, 0, NULL, NULL, NULL);
2087# else
2088 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002089 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090
Bram Moolenaar0f873732019-12-05 20:28:46 +01002091 // directly from example 3-18 "basicwin" of Xlib Programming Manual
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002092 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 XSetWMProperties(x11_display, x11_window, &text_prop,
2094 NULL, NULL, 0, NULL, NULL, NULL);
2095# endif
2096#else
2097 XStoreName(x11_display, x11_window, (char *)title);
2098#endif
2099 }
2100 XFlush(x11_display);
2101}
2102
2103/*
2104 * Set x11 Window icon
2105 *
2106 * get_x11_windis() must be called before this and have returned OK
2107 */
2108 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002109set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002111 // See above for comments about using X*SetWMProperties().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112#ifdef USE_UTF8_STRING
2113 if (enc_utf8)
2114 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2115 NULL, 0, NULL, NULL, NULL);
2116 else
2117#endif
2118 {
2119#if XtSpecificationRelease >= 4
2120# ifdef FEAT_XFONTSET
2121 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2122 NULL, 0, NULL, NULL, NULL);
2123# else
2124 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002125 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002127 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002128 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2129 NULL, 0, NULL, NULL, NULL);
2130# endif
2131#else
2132 XSetIconName(x11_display, x11_window, (char *)icon);
2133#endif
2134 }
2135 XFlush(x11_display);
2136}
2137
Bram Moolenaar0f873732019-12-05 20:28:46 +01002138#else // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002141get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142{
2143 return FALSE;
2144}
2145
2146 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002147get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148{
2149 if (!test_only)
2150 {
2151 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002152 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002154 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002155 }
2156 return FALSE;
2157}
2158
Bram Moolenaar0f873732019-12-05 20:28:46 +01002159#endif // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160
2161 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002162mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002163{
2164 return get_x11_title(TRUE);
2165}
2166
2167 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002168mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002169{
2170 return get_x11_icon(TRUE);
2171}
2172
2173/*
2174 * Set the window title and icon.
2175 */
2176 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002177mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178{
2179 int type = 0;
2180 static int recursive = 0;
2181
Bram Moolenaar0f873732019-12-05 20:28:46 +01002182 if (T_NAME == NULL) // no terminal name (yet)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 return;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002184 if (title == NULL && icon == NULL) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 return;
2186
Bram Moolenaar0f873732019-12-05 20:28:46 +01002187 // When one of the X11 functions causes a deadly signal, we get here again
2188 // recursively. Avoid hanging then (something is probably locked).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002189 if (recursive)
2190 return;
2191 ++recursive;
2192
2193 /*
2194 * if the window ID and the display is known, we may use X11 calls
2195 */
2196#ifdef FEAT_X11
2197 if (get_x11_windis() == OK)
2198 type = 1;
2199#else
Bram Moolenaar097148e2020-08-11 21:58:20 +02002200# if defined(FEAT_GUI_PHOTON) \
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002201 || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 if (gui.in_use)
2203 type = 1;
2204# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205#endif
2206
2207 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002208 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209 * than x11 calls, because the x11 calls don't always work
2210 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 if ((type || *T_TS != NUL) && title != NULL)
2212 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002213 if (oldtitle_outdated)
2214 {
2215 oldtitle_outdated = FALSE;
2216 VIM_CLEAR(oldtitle);
2217 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218 if (oldtitle == NULL
2219#ifdef FEAT_GUI
2220 && !gui.in_use
2221#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002222 ) // first call but not in GUI, save title
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 (void)get_x11_title(FALSE);
2224
Bram Moolenaar0f873732019-12-05 20:28:46 +01002225 if (*T_TS != NUL) // it's OK if t_fs is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 term_settitle(title);
2227#ifdef FEAT_X11
2228 else
2229# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002230 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002232 set_x11_title(title); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002234#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
Bram Moolenaar097148e2020-08-11 21:58:20 +02002235 || defined(FEAT_GUI_PHOTON)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 else
2237 gui_mch_settitle(title, icon);
2238#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02002239 unix_did_set_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002240 }
2241
2242 if ((type || *T_CIS != NUL) && icon != NULL)
2243 {
2244 if (oldicon == NULL
2245#ifdef FEAT_GUI
2246 && !gui.in_use
2247#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002248 ) // first call, save icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 get_x11_icon(FALSE);
2250
2251 if (*T_CIS != NUL)
2252 {
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002253 out_str(T_CIS); // set icon start
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 out_str_nf(icon);
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002255 out_str(T_CIE); // set icon end
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 out_flush();
2257 }
2258#ifdef FEAT_X11
2259 else
2260# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002261 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002263 set_x11_icon(icon); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264#endif
2265 did_set_icon = TRUE;
2266 }
2267 --recursive;
2268}
2269
2270/*
2271 * Restore the window/icon title.
2272 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002273 * SAVE_RESTORE_TITLE only restore title
2274 * SAVE_RESTORE_ICON only restore icon
2275 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 */
2277 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002278mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279{
Bram Moolenaardac13472019-09-16 21:06:21 +02002280 int do_push_pop = unix_did_set_title || did_set_icon;
Bram Moolenaare5c83282019-05-03 23:15:37 +02002281
Bram Moolenaar0f873732019-12-05 20:28:46 +01002282 // only restore the title or icon when it has been set
Bram Moolenaardac13472019-09-16 21:06:21 +02002283 mch_settitle(((which & SAVE_RESTORE_TITLE) && unix_did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002285 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2286
Bram Moolenaare5c83282019-05-03 23:15:37 +02002287 if (do_push_pop)
2288 {
2289 // pop and push from/to the stack
2290 term_pop_title(which);
2291 term_push_title(which);
2292 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293}
2294
Bram Moolenaar0f873732019-12-05 20:28:46 +01002295#endif // FEAT_TITLE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296
2297/*
2298 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002299 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 */
2301 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002302vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303{
2304 if (name == NULL)
2305 return FALSE;
2306 return (STRNICMP(name, "xterm", 5) == 0
2307 || STRNICMP(name, "nxterm", 6) == 0
2308 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002309 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002311 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 || STRCMP(name, "builtin_xterm") == 0);
2313}
2314
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002315#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2316/*
2317 * Return TRUE if "name" appears to be that of a terminal
2318 * known to support the xterm-style mouse protocol.
2319 * Relies on term_is_xterm having been set to its correct value.
2320 */
2321 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002322use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002323{
2324 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002325 && (term_is_xterm
2326 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002327 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002328 || STRICMP(name, "st") == 0
2329 || STRNICMP(name, "st-", 3) == 0
2330 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002331}
2332#endif
2333
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334/*
2335 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2336 * Return 1 for "xterm".
2337 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002338 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002339 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 */
2341 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002342use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002344 if (ttym_flags == TTYM_SGR)
2345 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002346 if (ttym_flags == TTYM_URXVT)
2347 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 if (ttym_flags == TTYM_XTERM2)
2349 return 2;
2350 if (ttym_flags == TTYM_XTERM)
2351 return 1;
2352 return 0;
2353}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354
2355 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002356vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357{
2358 if (name == NULL)
2359 return FALSE;
2360 return (STRNICMP(name, "iris-ansi", 9) == 0
2361 || STRCMP(name, "builtin_iris-ansi") == 0);
2362}
2363
2364 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002365vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366{
2367 if (name == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002368 return FALSE; // actually all ANSI comp. terminals should be here
2369 // catch VT100 - VT5xx
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002370 return ((STRNICMP(name, "vt", 2) == 0
2371 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 || STRCMP(name, "builtin_vt320") == 0);
2373}
2374
2375/*
2376 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2377 * This should include all windowed terminal emulators.
2378 */
2379 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002380vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381{
2382 if (name == NULL)
2383 return FALSE;
2384 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2385 return TRUE;
2386 return ( STRNICMP(name, "hpterm", 6) == 0
2387 || STRNICMP(name, "sun-cmd", 7) == 0
2388 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002389 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 || STRNICMP(name, "dtterm", 6) == 0);
2391}
2392
2393/*
2394 * Insert user name in s[len].
2395 * Return OK if a name found.
2396 */
2397 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002398mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399{
2400#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002401 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 return OK;
2403#else
2404 return mch_get_uname(getuid(), s, len);
2405#endif
2406}
2407
2408/*
2409 * Insert user name for "uid" in s[len].
2410 * Return OK if a name found.
2411 */
2412 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002413mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414{
2415#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2416 struct passwd *pw;
2417
2418 if ((pw = getpwuid(uid)) != NULL
2419 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2420 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002421 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422 return OK;
2423 }
2424#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002425 sprintf((char *)s, "%d", (int)uid); // assumes s is long enough
2426 return FAIL; // a number is not a name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427}
2428
2429/*
2430 * Insert host name is s[len].
2431 */
2432
2433#ifdef HAVE_SYS_UTSNAME_H
2434 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002435mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436{
2437 struct utsname vutsname;
2438
2439 if (uname(&vutsname) < 0)
2440 *s = NUL;
2441 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002442 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002444#else // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445
2446# ifdef HAVE_SYS_SYSTEMINFO_H
2447# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2448# endif
2449
2450 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002451mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452{
2453# ifdef VAXC
2454 vaxc$gethostname((char *)s, len);
2455# else
2456 gethostname((char *)s, len);
2457# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002458 s[len - 1] = NUL; // make sure it's terminated
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002460#endif // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461
2462/*
2463 * return process ID
2464 */
2465 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002466mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467{
2468 return (long)getpid();
2469}
2470
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002471/*
2472 * return TRUE if process "pid" is still running
2473 */
2474 int
Bram Moolenaar1b243ea2019-04-28 22:50:40 +02002475mch_process_running(long pid)
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002476{
2477 // EMX kill() not working correctly, it seems
2478 return kill(pid, 0) == 0;
2479}
2480
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002483strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484{
2485 extern int sys_nerr;
2486 extern char *sys_errlist[];
2487 static char er[20];
2488
2489 if (err > 0 && err < sys_nerr)
2490 return (sys_errlist[err]);
2491 sprintf(er, "Error %d", err);
2492 return er;
2493}
2494#endif
2495
2496/*
Bram Moolenaar964b3742019-05-24 18:54:09 +02002497 * Get name of current directory into buffer "buf" of length "len" bytes.
2498 * "len" must be at least PATH_MAX.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 * Return OK for success, FAIL for failure.
2500 */
2501 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002502mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503{
2504#if defined(USE_GETCWD)
2505 if (getcwd((char *)buf, len) == NULL)
2506 {
2507 STRCPY(buf, strerror(errno));
2508 return FAIL;
2509 }
2510 return OK;
2511#else
2512 return (getwd((char *)buf) != NULL ? OK : FAIL);
2513#endif
2514}
2515
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002517 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 *
2519 * return FAIL for failure, OK for success
2520 */
2521 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002522mch_FullName(
2523 char_u *fname,
2524 char_u *buf,
2525 int len,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002526 int force) // also expand when already absolute path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527{
2528 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002529#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530 int fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002531 static int dont_fchdir = FALSE; // TRUE when fchdir() doesn't work
Bram Moolenaar38323e42007-03-06 19:22:53 +00002532#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 char_u olddir[MAXPATHL];
2534 char_u *p;
2535 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002536#ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01002537 char_u posix_fname[MAXPATHL]; // Cygwin docs mention MAX_PATH, but
2538 // it's not always defined
Bram Moolenaarbf820722008-06-21 11:12:49 +00002539#endif
2540
Bram Moolenaar38323e42007-03-06 19:22:53 +00002541#ifdef VMS
2542 fname = vms_fixfilename(fname);
2543#endif
2544
Bram Moolenaara2442432007-04-26 14:26:37 +00002545#ifdef __CYGWIN__
2546 /*
2547 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2548 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002549# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01002550 // Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2551 // a forward slash.
Bram Moolenaar06b07342015-12-31 22:26:28 +01002552 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2553 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002554# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002555 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002556# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002557 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002558#endif
2559
Bram Moolenaar0f873732019-12-05 20:28:46 +01002560 // Expand it if forced or not an absolute path.
2561 // Do not do it for "/file", the result is always "/".
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002562 if ((force || !mch_isFullName(fname))
2563 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 {
2565 /*
2566 * If the file name has a path, change to that directory for a moment,
Bram Moolenaar964b3742019-05-24 18:54:09 +02002567 * and then get the directory (and get back to where we were).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 * This will get the correct path name with "../" things.
2569 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002570 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002572#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 /*
2574 * Use fchdir() if possible, it's said to be faster and more
2575 * reliable. But on SunOS 4 it might not work. Check this by
2576 * doing a fchdir() right now.
2577 */
2578 if (!dont_fchdir)
2579 {
2580 fd = open(".", O_RDONLY | O_EXTRA, 0);
2581 if (fd >= 0 && fchdir(fd) < 0)
2582 {
2583 close(fd);
2584 fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002585 dont_fchdir = TRUE; // don't try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 }
2587 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002588#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589
Bram Moolenaar0f873732019-12-05 20:28:46 +01002590 // Only change directory when we are sure we can return to where
2591 // we are now. After doing "su" chdir(".") might not work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002593#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002595#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 (mch_dirname(olddir, MAXPATHL) == FAIL
2597 || mch_chdir((char *)olddir) != 0))
2598 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002599 p = NULL; // can't get current dir: don't chdir
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600 retval = FAIL;
2601 }
2602 else
2603 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002604 // The directory is copied into buf[], to be able to remove
2605 // the file name without changing it (could be a string in
2606 // read-only memory)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 if (p - fname >= len)
2608 retval = FAIL;
2609 else
2610 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002611 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 if (mch_chdir((char *)buf))
2613 retval = FAIL;
2614 else
2615 fname = p + 1;
2616 *buf = NUL;
2617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 }
2619 }
2620 if (mch_dirname(buf, len) == FAIL)
2621 {
2622 retval = FAIL;
2623 *buf = NUL;
2624 }
2625 if (p != NULL)
2626 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002627#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 if (fd >= 0)
2629 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002630 if (p_verbose >= 5)
2631 {
2632 verbose_enter();
Bram Moolenaar32526b32019-01-19 17:43:09 +01002633 msg("fchdir() to previous dir");
Bram Moolenaar25724922009-07-14 15:38:41 +00002634 verbose_leave();
2635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 l = fchdir(fd);
2637 close(fd);
2638 }
2639 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002640#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 l = mch_chdir((char *)olddir);
2642 if (l != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002643 emsg(_(e_prev_dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 }
2645
2646 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002647 if (l >= len - 1)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002648 retval = FAIL; // no space for trailing "/"
Bram Moolenaar38323e42007-03-06 19:22:53 +00002649#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002650 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002652 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002653#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002655
Bram Moolenaar0f873732019-12-05 20:28:46 +01002656 // Catch file names which are too long.
Bram Moolenaar78a15312009-05-15 19:33:18 +00002657 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 return FAIL;
2659
Bram Moolenaar0f873732019-12-05 20:28:46 +01002660 // Do not append ".", "/dir/." is equal to "/dir".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 if (STRCMP(fname, ".") != 0)
2662 STRCAT(buf, fname);
2663
2664 return OK;
2665}
2666
2667/*
2668 * Return TRUE if "fname" does not depend on the current directory.
2669 */
2670 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002671mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002673#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 return ( fname[0] == '/' || fname[0] == '.' ||
2675 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2676 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2677 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002678#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680#endif
2681}
2682
Bram Moolenaar24552be2005-12-10 20:17:30 +00002683#if defined(USE_FNAME_CASE) || defined(PROTO)
2684/*
2685 * Set the case of the file name, if it already exists. This will cause the
2686 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002687 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002688 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002689 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002690fname_case(
2691 char_u *name,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002692 int len UNUSED) // buffer size, only used when name gets longer
Bram Moolenaar24552be2005-12-10 20:17:30 +00002693{
2694 struct stat st;
2695 char_u *slash, *tail;
2696 DIR *dirp;
2697 struct dirent *dp;
2698
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002699 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002700 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002701 // Open the directory where the file is located.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002702 slash = vim_strrchr(name, '/');
2703 if (slash == NULL)
2704 {
2705 dirp = opendir(".");
2706 tail = name;
2707 }
2708 else
2709 {
2710 *slash = NUL;
2711 dirp = opendir((char *)name);
2712 *slash = '/';
2713 tail = slash + 1;
2714 }
2715
2716 if (dirp != NULL)
2717 {
2718 while ((dp = readdir(dirp)) != NULL)
2719 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002720 // Only accept names that differ in case and are the same byte
2721 // length. TODO: accept different length name.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002722 if (STRICMP(tail, dp->d_name) == 0
2723 && STRLEN(tail) == STRLEN(dp->d_name))
2724 {
2725 char_u newname[MAXPATHL + 1];
2726 struct stat st2;
2727
Bram Moolenaar0f873732019-12-05 20:28:46 +01002728 // Verify the inode is equal.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002729 vim_strncpy(newname, name, MAXPATHL);
2730 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2731 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002732 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002733 && st.st_ino == st2.st_ino
2734 && st.st_dev == st2.st_dev)
2735 {
2736 STRCPY(tail, dp->d_name);
2737 break;
2738 }
2739 }
2740 }
2741
2742 closedir(dirp);
2743 }
2744 }
2745}
2746#endif
2747
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748/*
2749 * Get file permissions for 'name'.
2750 * Returns -1 when it doesn't exist.
2751 */
2752 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002753mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754{
2755 struct stat statb;
2756
Bram Moolenaar0f873732019-12-05 20:28:46 +01002757 // Keep the #ifdef outside of stat(), it may be a macro.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758#ifdef VMS
2759 if (stat((char *)vms_fixfilename(name), &statb))
2760#else
2761 if (stat((char *)name, &statb))
2762#endif
2763 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002764#ifdef __INTERIX
Bram Moolenaar0f873732019-12-05 20:28:46 +01002765 // The top bit makes the value negative, which means the file doesn't
2766 // exist. Remove the bit, we don't use it.
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002767 return statb.st_mode & ~S_ADDACE;
2768#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002770#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771}
2772
2773/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002774 * Set file permission for "name" to "perm".
2775 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 */
2777 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002778mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779{
2780 return (chmod((char *)
2781#ifdef VMS
2782 vms_fixfilename(name),
2783#else
2784 name,
2785#endif
2786 (mode_t)perm) == 0 ? OK : FAIL);
2787}
2788
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002789#if defined(HAVE_FCHMOD) || defined(PROTO)
2790/*
2791 * Set file permission for open file "fd" to "perm".
2792 * Return FAIL for failure, OK otherwise.
2793 */
2794 int
2795mch_fsetperm(int fd, long perm)
2796{
2797 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2798}
2799#endif
2800
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801#if defined(HAVE_ACL) || defined(PROTO)
2802# ifdef HAVE_SYS_ACL_H
2803# include <sys/acl.h>
2804# endif
2805# ifdef HAVE_SYS_ACCESS_H
2806# include <sys/access.h>
2807# endif
2808
2809# ifdef HAVE_SOLARIS_ACL
2810typedef struct vim_acl_solaris_T {
2811 int acl_cnt;
2812 aclent_t *acl_entry;
2813} vim_acl_solaris_T;
2814# endif
2815
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002816#if defined(HAVE_SELINUX) || defined(PROTO)
2817/*
2818 * Copy security info from "from_file" to "to_file".
2819 */
2820 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002821mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002822{
2823 if (from_file == NULL)
2824 return;
2825
2826 if (selinux_enabled == -1)
2827 selinux_enabled = is_selinux_enabled();
2828
2829 if (selinux_enabled > 0)
2830 {
2831 security_context_t from_context = NULL;
2832 security_context_t to_context = NULL;
2833
2834 if (getfilecon((char *)from_file, &from_context) < 0)
2835 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002836 // If the filesystem doesn't support extended attributes,
2837 // the original had no special security context and the
2838 // target cannot have one either.
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002839 if (errno == EOPNOTSUPP)
2840 return;
2841
Bram Moolenaar32526b32019-01-19 17:43:09 +01002842 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002843 msg_outtrans(from_file);
2844 msg_putchar('\n');
2845 return;
2846 }
2847 if (getfilecon((char *)to_file, &to_context) < 0)
2848 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002849 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002850 msg_outtrans(to_file);
2851 msg_putchar('\n');
2852 freecon (from_context);
2853 return ;
2854 }
2855 if (strcmp(from_context, to_context) != 0)
2856 {
2857 if (setfilecon((char *)to_file, from_context) < 0)
2858 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002859 msg_puts(_("\nCould not set security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002860 msg_outtrans(to_file);
2861 msg_putchar('\n');
2862 }
2863 }
2864 freecon(to_context);
2865 freecon(from_context);
2866 }
2867}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002868#endif // HAVE_SELINUX
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002869
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002870#if defined(HAVE_SMACK) && !defined(PROTO)
2871/*
2872 * Copy security info from "from_file" to "to_file".
2873 */
2874 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002875mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002876{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002877 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002878 {
2879 XATTR_NAME_SMACK,
2880 XATTR_NAME_SMACKEXEC,
2881 XATTR_NAME_SMACKMMAP
2882 };
2883
2884 char buffer[SMACK_LABEL_LEN];
2885 const char *name;
2886 int index;
2887 int ret;
2888 ssize_t size;
2889
2890 if (from_file == NULL)
2891 return;
2892
2893 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2894 / sizeof(smack_copied_attributes)[0]) ; index++)
2895 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002896 // get the name of the attribute to copy
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002897 name = smack_copied_attributes[index];
2898
Bram Moolenaar0f873732019-12-05 20:28:46 +01002899 // get the value of the attribute in buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002900 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2901 if (size >= 0)
2902 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002903 // copy the attribute value of buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002904 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2905 if (ret < 0)
2906 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002907 vim_snprintf((char *)IObuff, IOSIZE,
2908 _("Could not set security context %s for %s"),
2909 name, to_file);
2910 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002911 msg_putchar('\n');
2912 }
2913 }
2914 else
2915 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002916 // what reason of not having the attribute value?
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002917 switch (errno)
2918 {
2919 case ENOTSUP:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002920 // extended attributes aren't supported or enabled
2921 // should a message be echoed? not sure...
2922 return; // leave because it isn't useful to continue
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002923
2924 case ERANGE:
2925 default:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002926 // no enough size OR unexpected error
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002927 vim_snprintf((char *)IObuff, IOSIZE,
2928 _("Could not get security context %s for %s. Removing it!"),
2929 name, from_file);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002930 msg_puts((char *)IObuff);
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002931 msg_putchar('\n');
Bram Moolenaar0f873732019-12-05 20:28:46 +01002932 // FALLTHROUGH to remove the attribute
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002933
2934 case ENODATA:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002935 // no attribute of this name
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002936 ret = removexattr((char*)to_file, name);
Bram Moolenaar0f873732019-12-05 20:28:46 +01002937 // Silently ignore errors, apparently this happens when
2938 // smack is not actually being used.
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002939 break;
2940 }
2941 }
2942 }
2943}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002944#endif // HAVE_SMACK
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002945
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946/*
2947 * Return a pointer to the ACL of file "fname" in allocated memory.
2948 * Return NULL if the ACL is not available for whatever reason.
2949 */
2950 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002951mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952{
2953 vim_acl_T ret = NULL;
2954#ifdef HAVE_POSIX_ACL
2955 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2956#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002957#ifdef HAVE_SOLARIS_ZFS_ACL
2958 acl_t *aclent;
2959
2960 if (acl_get((char *)fname, 0, &aclent) < 0)
2961 return NULL;
2962 ret = (vim_acl_T)aclent;
2963#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964#ifdef HAVE_SOLARIS_ACL
2965 vim_acl_solaris_T *aclent;
2966
2967 aclent = malloc(sizeof(vim_acl_solaris_T));
2968 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2969 {
2970 free(aclent);
2971 return NULL;
2972 }
2973 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2974 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2975 {
2976 free(aclent->acl_entry);
2977 free(aclent);
2978 return NULL;
2979 }
2980 ret = (vim_acl_T)aclent;
2981#else
2982#if defined(HAVE_AIX_ACL)
2983 int aclsize;
2984 struct acl *aclent;
2985
2986 aclsize = sizeof(struct acl);
2987 aclent = malloc(aclsize);
2988 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2989 {
2990 if (errno == ENOSPC)
2991 {
2992 aclsize = aclent->acl_len;
2993 aclent = realloc(aclent, aclsize);
2994 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2995 {
2996 free(aclent);
2997 return NULL;
2998 }
2999 }
3000 else
3001 {
3002 free(aclent);
3003 return NULL;
3004 }
3005 }
3006 ret = (vim_acl_T)aclent;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003007#endif // HAVE_AIX_ACL
3008#endif // HAVE_SOLARIS_ACL
3009#endif // HAVE_SOLARIS_ZFS_ACL
3010#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 return ret;
3012}
3013
3014/*
3015 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3016 */
3017 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003018mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019{
3020 if (aclent == NULL)
3021 return;
3022#ifdef HAVE_POSIX_ACL
3023 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3024#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003025#ifdef HAVE_SOLARIS_ZFS_ACL
3026 acl_set((char *)fname, (acl_t *)aclent);
3027#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028#ifdef HAVE_SOLARIS_ACL
3029 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3030 ((vim_acl_solaris_T *)aclent)->acl_entry);
3031#else
3032#ifdef HAVE_AIX_ACL
3033 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003034#endif // HAVE_AIX_ACL
3035#endif // HAVE_SOLARIS_ACL
3036#endif // HAVE_SOLARIS_ZFS_ACL
3037#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038}
3039
3040 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003041mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042{
3043 if (aclent == NULL)
3044 return;
3045#ifdef HAVE_POSIX_ACL
3046 acl_free((acl_t)aclent);
3047#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003048#ifdef HAVE_SOLARIS_ZFS_ACL
3049 acl_free((acl_t *)aclent);
3050#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051#ifdef HAVE_SOLARIS_ACL
3052 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3053 free(aclent);
3054#else
3055#ifdef HAVE_AIX_ACL
3056 free(aclent);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003057#endif // HAVE_AIX_ACL
3058#endif // HAVE_SOLARIS_ACL
3059#endif // HAVE_SOLARIS_ZFS_ACL
3060#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061}
3062#endif
3063
3064/*
3065 * Set hidden flag for "name".
3066 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003068mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069{
Bram Moolenaar0f873732019-12-05 20:28:46 +01003070 // can't hide a file
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071}
3072
3073/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003074 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 * return FALSE if "name" is not a directory
3076 * return FALSE for error
3077 */
3078 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003079mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080{
3081 struct stat statb;
3082
Bram Moolenaar0f873732019-12-05 20:28:46 +01003083 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 return FALSE;
3085 if (stat((char *)name, &statb))
3086 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088}
3089
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003090/*
3091 * return TRUE if "name" is a directory, NOT a symlink to a directory
3092 * return FALSE if "name" is not a directory
3093 * return FALSE for error
3094 */
3095 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003096mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003097{
3098 struct stat statb;
3099
Bram Moolenaar0f873732019-12-05 20:28:46 +01003100 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003101 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003102 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003103 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003104 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003105}
3106
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107/*
3108 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3109 */
3110 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003111executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112{
3113 struct stat st;
3114
3115 if (stat((char *)name, &st))
3116 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003117#ifdef VMS
Bram Moolenaar0f873732019-12-05 20:28:46 +01003118 // Like on Unix system file can have executable rights but not necessarily
3119 // be an executable, but on Unix is not a default for an ordinary file to
3120 // have an executable flag - on VMS it is in most cases.
3121 // Therefore, this check does not have any sense - let keep us to the
3122 // conventions instead:
3123 // *.COM and *.EXE files are the executables - the rest are not. This is
3124 // not ideal but better then it was.
Bram Moolenaar206f0112014-03-12 16:51:55 +01003125 int vms_executable = 0;
3126 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3127 {
3128 if (strstr(vms_tolower((char*)name),".exe") != NULL
3129 || strstr(vms_tolower((char*)name),".com")!= NULL)
3130 vms_executable = 1;
3131 }
3132 return vms_executable;
3133#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003135#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136}
3137
3138/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003139 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003140 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 * Return -1 if unknown.
3142 */
3143 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003144mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145{
3146 char_u *buf;
3147 char_u *p, *e;
3148 int retval;
3149
Bram Moolenaar0f873732019-12-05 20:28:46 +01003150 // When "use_path" is false and if it's an absolute or relative path don't
3151 // need to use $PATH.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003152 if (!use_path || gettail(name) != name)
Bram Moolenaar206f0112014-03-12 16:51:55 +01003153 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003154 // There must be a path separator, files in the current directory
3155 // can't be executed.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003156 if ((use_path || gettail(name) != name) && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003157 {
3158 if (path != NULL)
3159 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003160 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003161 *path = FullName_save(name, TRUE);
3162 else
3163 *path = vim_strsave(name);
3164 }
3165 return TRUE;
3166 }
3167 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003168 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169
3170 p = (char_u *)getenv("PATH");
3171 if (p == NULL || *p == NUL)
3172 return -1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02003173 buf = alloc(STRLEN(name) + STRLEN(p) + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 if (buf == NULL)
3175 return -1;
3176
3177 /*
3178 * Walk through all entries in $PATH to check if "name" exists there and
3179 * is an executable file.
3180 */
3181 for (;;)
3182 {
3183 e = (char_u *)strchr((char *)p, ':');
3184 if (e == NULL)
3185 e = p + STRLEN(p);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003186 if (e - p <= 1) // empty entry means current dir
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 STRCPY(buf, "./");
3188 else
3189 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003190 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191 add_pathsep(buf);
3192 }
3193 STRCAT(buf, name);
3194 retval = executable_file(buf);
3195 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003196 {
3197 if (path != NULL)
3198 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003199 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003200 *path = FullName_save(buf, TRUE);
3201 else
3202 *path = vim_strsave(buf);
3203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003205 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206
3207 if (*e != ':')
3208 break;
3209 p = e + 1;
3210 }
3211
3212 vim_free(buf);
3213 return retval;
3214}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215
3216/*
3217 * Check what "name" is:
3218 * NODE_NORMAL: file or directory (or doesn't exist)
3219 * NODE_WRITABLE: writable device, socket, fifo, etc.
3220 * NODE_OTHER: non-writable things
3221 */
3222 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003223mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224{
3225 struct stat st;
3226
3227 if (stat((char *)name, &st))
3228 return NODE_NORMAL;
3229 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3230 return NODE_NORMAL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003231 if (S_ISBLK(st.st_mode)) // block device isn't writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 return NODE_OTHER;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003233 // Everything else is writable?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 return NODE_WRITABLE;
3235}
3236
3237 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003238mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239{
3240#ifdef HAVE_CHECK_STACK_GROWTH
3241 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243 check_stack_growth((char *)&i);
3244
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003245# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 get_stack_limit();
3247# endif
3248
3249#endif
3250
3251 /*
3252 * Setup an alternative stack for signals. Helps to catch signals when
3253 * running out of stack space.
3254 * Use of sigaltstack() is preferred, it's more portable.
3255 * Ignore any errors.
3256 */
3257#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003258 signal_stack = alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259 init_signal_stack();
3260#endif
3261}
3262
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003263#if defined(EXITFREE) || defined(PROTO)
3264 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003265mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003266{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003267# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3268 if (clip_star.owned)
3269 clip_lose_selection(&clip_star);
3270 if (clip_plus.owned)
3271 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003272# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003273# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003274 if (xterm_Shell != (Widget)0)
3275 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003276# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01003277 // Lesstif crashes here, lose some memory
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003278 if (xterm_dpy != NULL)
3279 XtCloseDisplay(xterm_dpy);
3280 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003281 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003282 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003283# ifdef FEAT_X11
Bram Moolenaar0f873732019-12-05 20:28:46 +01003284 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaare8208012008-06-20 09:59:25 +00003285# endif
3286 }
3287# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003288# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003289# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003290 if (x11_display != NULL
3291# ifdef FEAT_XCLIPBOARD
3292 && x11_display != xterm_dpy
3293# endif
3294 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003295 XCloseDisplay(x11_display);
3296# endif
3297# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003298 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003299# endif
3300# ifdef FEAT_TITLE
3301 vim_free(oldtitle);
3302 vim_free(oldicon);
3303# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003304}
3305#endif
3306
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307/*
3308 * Output a newline when exiting.
3309 * Make sure the newline goes to the same stream as the text.
3310 */
3311 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003312exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003314 if (silent_mode)
3315 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 if (newline_on_exit || msg_didout)
3317 {
3318 if (msg_use_printf())
3319 {
3320 if (info_message)
3321 mch_msg("\n");
3322 else
3323 mch_errmsg("\r\n");
3324 }
3325 else
3326 out_char('\n');
3327 }
3328 else
3329 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003330 restore_cterm_colors(); // get original colors back
3331 msg_clr_eos_force(); // clear the rest of the display
3332 windgoto((int)Rows - 1, 0); // may have moved the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333 }
3334}
3335
Bram Moolenaarb4151682020-05-11 22:13:28 +02003336#ifdef USE_GCOV_FLUSH
3337extern void __gcov_flush();
3338#endif
3339
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003341mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342{
3343 exiting = TRUE;
3344
3345#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3346 x11_export_final_selection();
3347#endif
3348
3349#ifdef FEAT_GUI
3350 if (!gui.in_use)
3351#endif
3352 {
3353 settmode(TMODE_COOK);
3354#ifdef FEAT_TITLE
Bram Moolenaar40385db2018-08-07 22:31:44 +02003355 // restore xterm title and icon name
3356 mch_restore_title(SAVE_RESTORE_BOTH);
3357 term_pop_title(SAVE_RESTORE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358#endif
3359 /*
3360 * When t_ti is not empty but it doesn't cause swapping terminal
3361 * pages, need to output a newline when msg_didout is set. But when
3362 * t_ti does swap pages it should not go to the shell page. Do this
3363 * before stoptermcap().
3364 */
3365 if (swapping_screen() && !newline_on_exit)
3366 exit_scroll();
3367
Bram Moolenaar0f873732019-12-05 20:28:46 +01003368 // Stop termcap: May need to check for T_CRV response, which
3369 // requires RAW mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 stoptermcap();
3371
3372 /*
3373 * A newline is only required after a message in the alternate screen.
3374 * This is set to TRUE by wait_return().
3375 */
3376 if (!swapping_screen() || newline_on_exit)
3377 exit_scroll();
3378
Bram Moolenaar0f873732019-12-05 20:28:46 +01003379 // Cursor may have been switched off without calling starttermcap()
3380 // when doing "vim -u vimrc" and vimrc contains ":q".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 if (full_screen)
3382 cursor_on();
3383 }
3384 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01003385 ml_close_all(TRUE); // remove all memfiles
Bram Moolenaarb4151682020-05-11 22:13:28 +02003386
3387#ifdef USE_GCOV_FLUSH
3388 // Flush coverage info before possibly being killed by a deadly signal.
3389 __gcov_flush();
3390#endif
3391
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 may_core_dump();
3393#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 gui_exit(r);
3396#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003397
Bram Moolenaar56718732006-03-15 22:53:57 +00003398#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003399 mac_conv_cleanup();
3400#endif
3401
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402#ifdef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01003403 // A core dump won't be created if the signal handler
3404 // doesn't return, so we can't call exit()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 if (deadly_signal != 0)
3406 return;
3407#endif
3408
Bram Moolenaar009b2592004-10-24 19:18:58 +00003409#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003410 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003411#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003412
3413#ifdef EXITFREE
3414 free_all_mem();
3415#endif
3416
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417 exit(r);
3418}
3419
3420 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003421may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422{
3423 if (deadly_signal != 0)
3424 {
3425 signal(deadly_signal, SIG_DFL);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003426 kill(getpid(), deadly_signal); // Die using the signal we caught
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 }
3428}
3429
3430#ifndef VMS
3431
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003432/*
3433 * Get the file descriptor to use for tty operations.
3434 */
3435 static int
3436get_tty_fd(int fd)
3437{
3438 int tty_fd = fd;
3439
3440#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
3441 // On SunOS: Get the terminal parameters from "fd", or the slave device of
3442 // "fd" when it is a master device.
3443 if (mch_isatty(fd) > 1)
3444 {
3445 char *name;
3446
3447 name = ptsname(fd);
3448 if (name == NULL)
3449 return -1;
3450
3451 tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
3452 if (tty_fd < 0)
3453 return -1;
3454 }
3455#endif
3456 return tty_fd;
3457}
3458
3459 static int
3460mch_tcgetattr(int fd, void *term)
3461{
3462 int tty_fd;
3463 int retval = -1;
3464
3465 tty_fd = get_tty_fd(fd);
3466 if (tty_fd >= 0)
3467 {
3468#ifdef NEW_TTY_SYSTEM
3469# ifdef HAVE_TERMIOS_H
3470 retval = tcgetattr(tty_fd, (struct termios *)term);
3471# else
3472 retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
3473# endif
3474#else
3475 // for "old" tty systems
3476 retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
3477#endif
3478 if (tty_fd != fd)
3479 close(tty_fd);
3480 }
3481 return retval;
3482}
3483
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 void
Bram Moolenaar26e86442020-05-17 14:06:16 +02003485mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486{
3487 static int first = TRUE;
3488
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003489#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003490# ifdef HAVE_TERMIOS_H
3491 static struct termios told;
3492 struct termios tnew;
3493# else
3494 static struct termio told;
3495 struct termio tnew;
3496# endif
3497
3498 if (first)
3499 {
3500 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003501 mch_tcgetattr(read_cmd_fd, &told);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 }
3503
3504 tnew = told;
3505 if (tmode == TMODE_RAW)
3506 {
Bram Moolenaar041c7102020-05-30 18:14:57 +02003507 // ~ICRNL enables typing ^V^M
Bram Moolenaar928eec62020-05-31 13:09:47 +02003508 // ~IXON disables CTRL-S stopping output, so that it can be mapped.
3509 tnew.c_iflag &= ~(ICRNL | IXON);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
Bram Moolenaare3f915d2020-07-14 23:02:44 +02003511# if defined(IEXTEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003512 | IEXTEN // IEXTEN enables typing ^V on SOLARIS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513# endif
3514 );
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003515# ifdef ONLCR
3516 // Don't map NL -> CR NL, we do it ourselves.
3517 // Also disable expanding tabs if possible.
3518# ifdef XTABS
3519 tnew.c_oflag &= ~(ONLCR | XTABS);
3520# else
3521# ifdef TAB3
3522 tnew.c_oflag &= ~(ONLCR | TAB3);
3523# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 tnew.c_oflag &= ~ONLCR;
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003525# endif
3526# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527# endif
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003528 tnew.c_cc[VMIN] = 1; // return after 1 char
3529 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 }
3531 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003532 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003533 // Also reset ICANON here, otherwise on Solaris select() won't see
3534 // typeahead characters.
Bram Moolenaar40de4562016-07-01 15:03:46 +02003535 tnew.c_lflag &= ~(ICANON | ECHO);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003536 tnew.c_cc[VMIN] = 1; // return after 1 char
3537 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar40de4562016-07-01 15:03:46 +02003538 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539
3540# if defined(HAVE_TERMIOS_H)
3541 {
3542 int n = 10;
3543
Bram Moolenaar0f873732019-12-05 20:28:46 +01003544 // A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3545 // few times.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3547 && errno == EINTR && n > 0)
3548 --n;
3549 }
3550# else
3551 ioctl(read_cmd_fd, TCSETA, &tnew);
3552# endif
3553
3554#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 /*
3556 * for "old" tty systems
3557 */
3558# ifndef TIOCSETN
Bram Moolenaar0f873732019-12-05 20:28:46 +01003559# define TIOCSETN TIOCSETP // for hpux 9.0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560# endif
3561 static struct sgttyb ttybold;
3562 struct sgttyb ttybnew;
3563
3564 if (first)
3565 {
3566 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003567 mch_tcgetattr(read_cmd_fd, &ttybold);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568 }
3569
3570 ttybnew = ttybold;
3571 if (tmode == TMODE_RAW)
3572 {
3573 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3574 ttybnew.sg_flags |= RAW;
3575 }
3576 else if (tmode == TMODE_SLEEP)
3577 ttybnew.sg_flags &= ~(ECHO);
3578 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3579#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02003580 mch_cur_tmode = tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581}
3582
3583/*
3584 * Try to get the code for "t_kb" from the stty setting
3585 *
3586 * Even if termcap claims a backspace key, the user's setting *should*
3587 * prevail. stty knows more about reality than termcap does, and if
3588 * somebody's usual erase key is DEL (which, for most BSD users, it will
3589 * be), they're going to get really annoyed if their erase key starts
3590 * doing forward deletes for no reason. (Eric Fischer)
3591 */
3592 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003593get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003595 ttyinfo_T info;
3596 char_u buf[2];
3597 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003599 if (get_tty_info(read_cmd_fd, &info) == OK)
3600 {
3601 intr_char = info.interrupt;
3602 buf[0] = info.backspace;
3603 buf[1] = NUL;
3604 add_termcode((char_u *)"kb", buf, FALSE);
3605
Bram Moolenaar0f873732019-12-05 20:28:46 +01003606 // If <BS> and <DEL> are now the same, redefine <DEL>.
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003607 p = find_termcode((char_u *)"kD");
3608 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3609 do_fixdel(NULL);
3610 }
3611}
3612
3613/*
3614 * Obtain the characters that Backspace and Enter produce on "fd".
3615 * Returns OK or FAIL.
3616 */
3617 int
3618get_tty_info(int fd, ttyinfo_T *info)
3619{
3620#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003621# ifdef HAVE_TERMIOS_H
3622 struct termios keys;
3623# else
3624 struct termio keys;
3625# endif
3626
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003627 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003629 info->backspace = keys.c_cc[VERASE];
3630 info->interrupt = keys.c_cc[VINTR];
3631 if (keys.c_iflag & ICRNL)
3632 info->enter = NL;
3633 else
3634 info->enter = CAR;
3635 if (keys.c_oflag & ONLCR)
3636 info->nl_does_cr = TRUE;
3637 else
3638 info->nl_does_cr = FALSE;
3639 return OK;
3640 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01003642 // for "old" tty systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 struct sgttyb keys;
3644
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003645 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003647 info->backspace = keys.sg_erase;
3648 info->interrupt = keys.sg_kill;
3649 info->enter = CAR;
3650 info->nl_does_cr = TRUE;
3651 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003652 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003654 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655}
3656
Bram Moolenaar0f873732019-12-05 20:28:46 +01003657#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003659static int mouse_ison = FALSE;
3660
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661/*
3662 * Set mouse clicks on or off.
3663 */
3664 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003665mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003666{
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003667#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003668 static int bevalterm_ison = FALSE;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003669#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 int xterm_mouse_vers;
3671
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003672#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaara06afc72018-08-27 23:24:16 +02003673 if (!on)
3674 // Make sure not tracing mouse movements. Important when a button-down
3675 // was received but no release yet.
3676 stop_xterm_trace();
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003677#endif
Bram Moolenaara06afc72018-08-27 23:24:16 +02003678
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003679 if (on == mouse_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003680#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003681 && p_bevalterm == bevalterm_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003682#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003683 )
Bram Moolenaar0f873732019-12-05 20:28:46 +01003684 // return quickly if nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 return;
3686
3687 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003688
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003689#ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003690 if (ttym_flags == TTYM_URXVT)
3691 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003692 out_str_nf((char_u *)
3693 (on
3694 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3695 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003696 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003697 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003698#endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003699
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003700 if (ttym_flags == TTYM_SGR)
3701 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003702 // SGR mode supports columns above 223
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003703 out_str_nf((char_u *)
3704 (on
3705 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3706 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003707 mouse_ison = on;
3708 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003709
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003710#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003711 if (bevalterm_ison != (p_bevalterm && on))
3712 {
3713 bevalterm_ison = (p_bevalterm && on);
3714 if (xterm_mouse_vers > 1 && !bevalterm_ison)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003715 // disable mouse movement events, enabling is below
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003716 out_str_nf((char_u *)
3717 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003718 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003719#endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003720
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 if (xterm_mouse_vers > 0)
3722 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003723 if (on) // enable mouse events, use mouse tracking if available
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 out_str_nf((char_u *)
3725 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003726 ? (
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003727#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003728 bevalterm_ison
3729 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003730#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003731 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
Bram Moolenaar0f873732019-12-05 20:28:46 +01003733 else // disable mouse events, could probably always send the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 out_str_nf((char_u *)
3735 (xterm_mouse_vers > 1
3736 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3737 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003738 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 }
3740
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003741#ifdef FEAT_MOUSE_DEC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742 else if (ttym_flags == TTYM_DEC)
3743 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003744 if (on) // enable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
Bram Moolenaar0f873732019-12-05 20:28:46 +01003746 else // disable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003748 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003750#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003752#ifdef FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 else
3754 {
3755 if (on)
3756 {
3757 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003758 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759 }
3760 else
3761 {
3762 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003763 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 }
3765 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003766#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003768#ifdef FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003769 else
3770 {
3771 if (on)
3772 {
3773 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003774 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003775 }
3776 else
3777 {
3778 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003779 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003780 }
3781 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003782#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003783
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003784#ifdef FEAT_MOUSE_JSB
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 else
3786 {
3787 if (on)
3788 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003789 // D - Enable Mouse up/down messages
3790 // L - Enable Left Button Reporting
3791 // M - Enable Middle Button Reporting
3792 // R - Enable Right Button Reporting
3793 // K - Enable SHIFT and CTRL key Reporting
3794 // + - Enable Advanced messaging of mouse moves and up/down messages
3795 // Q - Quiet No Ack
3796 // # - Numeric value of mouse pointer required
3797 // 0 = Multiview 2000 cursor, used as standard
3798 // 1 = Windows Arrow
3799 // 2 = Windows I Beam
3800 // 3 = Windows Hour Glass
3801 // 4 = Windows Cross Hair
3802 // 5 = Windows UP Arrow
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003803# ifdef JSBTERM_MOUSE_NONADVANCED
Bram Moolenaar0f873732019-12-05 20:28:46 +01003804 // Disables full feedback of pointer movements
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3806 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003807# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3809 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003810# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003811 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 }
3813 else
3814 {
3815 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3816 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003817 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818 }
3819 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003820#endif
3821#ifdef FEAT_MOUSE_PTERM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 else
3823 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003824 // 1 = button press, 6 = release, 7 = drag, 1h...9l = right button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 if (on)
3826 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3827 else
3828 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003829 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003831#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832}
3833
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003834#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003835/*
3836 * Called when 'balloonevalterm' changed.
3837 */
3838 void
3839mch_bevalterm_changed(void)
3840{
3841 mch_setmouse(mouse_ison);
3842}
3843#endif
3844
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845/*
3846 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3847 */
3848 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003849check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850{
3851# ifdef FEAT_MOUSE_XTERM
3852 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003853# ifdef FEAT_MOUSE_URXVT
3854 && use_xterm_mouse() != 3
3855# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856# ifdef FEAT_GUI
3857 && !gui.in_use
3858# endif
3859 )
3860 {
3861 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003862 ? IF_EB("\233M", CSI_STR "M")
3863 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003864 if (*p_mouse != NUL)
3865 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003866 // force mouse off and maybe on to send possibly new mouse
3867 // activation sequence to the xterm, with(out) drag tracing.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 mch_setmouse(FALSE);
3869 setmouse();
3870 }
3871 }
3872 else
3873 del_mouse_termcode(KS_MOUSE);
3874# endif
3875
3876# ifdef FEAT_MOUSE_GPM
3877 if (!use_xterm_mouse()
3878# ifdef FEAT_GUI
3879 && !gui.in_use
3880# endif
3881 )
Bram Moolenaarbedf0912019-05-04 16:58:45 +02003882 set_mouse_termcode(KS_GPM_MOUSE,
3883 (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3884 else
3885 del_mouse_termcode(KS_GPM_MOUSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886# endif
3887
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003888# ifdef FEAT_SYSMOUSE
3889 if (!use_xterm_mouse()
3890# ifdef FEAT_GUI
3891 && !gui.in_use
3892# endif
3893 )
3894 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3895# endif
3896
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897# ifdef FEAT_MOUSE_JSB
Bram Moolenaar0f873732019-12-05 20:28:46 +01003898 // Conflicts with xterm mouse: "\033[" and "\033[M" ???
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 if (!use_xterm_mouse()
3900# ifdef FEAT_GUI
3901 && !gui.in_use
3902# endif
3903 )
3904 set_mouse_termcode(KS_JSBTERM_MOUSE,
3905 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3906 else
3907 del_mouse_termcode(KS_JSBTERM_MOUSE);
3908# endif
3909
3910# ifdef FEAT_MOUSE_NET
Bram Moolenaar0f873732019-12-05 20:28:46 +01003911 // There is no conflict, but one may type "ESC }" from Insert mode. Don't
3912 // define it in the GUI or when using an xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 if (!use_xterm_mouse()
3914# ifdef FEAT_GUI
3915 && !gui.in_use
3916# endif
3917 )
3918 set_mouse_termcode(KS_NETTERM_MOUSE,
3919 (char_u *)IF_EB("\033}", ESC_STR "}"));
3920 else
3921 del_mouse_termcode(KS_NETTERM_MOUSE);
3922# endif
3923
3924# ifdef FEAT_MOUSE_DEC
Bram Moolenaar0f873732019-12-05 20:28:46 +01003925 // Conflicts with xterm mouse: "\033[" and "\033[M"
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003926 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927# ifdef FEAT_GUI
3928 && !gui.in_use
3929# endif
3930 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003931 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3932 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 else
3934 del_mouse_termcode(KS_DEC_MOUSE);
3935# endif
3936# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar0f873732019-12-05 20:28:46 +01003937 // same conflict as the dec mouse
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003938 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003939# ifdef FEAT_GUI
3940 && !gui.in_use
3941# endif
3942 )
3943 set_mouse_termcode(KS_PTERM_MOUSE,
3944 (char_u *) IF_EB("\033[", ESC_STR "["));
3945 else
3946 del_mouse_termcode(KS_PTERM_MOUSE);
3947# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003948# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003949 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003950# ifdef FEAT_GUI
3951 && !gui.in_use
3952# endif
3953 )
3954 {
3955 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003956 ? IF_EB("\233*M", CSI_STR "*M")
3957 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003958
3959 if (*p_mouse != NUL)
3960 {
3961 mch_setmouse(FALSE);
3962 setmouse();
3963 }
3964 }
3965 else
3966 del_mouse_termcode(KS_URXVT_MOUSE);
3967# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003968 if (use_xterm_mouse() == 4
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003969# ifdef FEAT_GUI
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003970 && !gui.in_use
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003971# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003972 )
3973 {
3974 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003975 ? IF_EB("\233<*M", CSI_STR "<*M")
3976 : IF_EB("\033[<*M", ESC_STR "[<*M")));
3977
3978 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
3979 ? IF_EB("\233<*m", CSI_STR "<*m")
3980 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003981
3982 if (*p_mouse != NUL)
3983 {
3984 mch_setmouse(FALSE);
3985 setmouse();
3986 }
3987 }
3988 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02003989 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003990 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02003991 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
3992 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995#ifndef VMS
3996
3997/*
3998 * Try to get the current window size:
3999 * 1. with an ioctl(), most accurate method
4000 * 2. from the environment variables LINES and COLUMNS
4001 * 3. from the termcap
4002 * 4. keep using the old values
4003 * Return OK when size could be determined, FAIL otherwise.
4004 */
4005 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004006mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004007{
4008 long rows = 0;
4009 long columns = 0;
4010 char_u *p;
4011
4012 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 * 1. try using an ioctl. It is the most accurate method.
4014 *
4015 * Try using TIOCGWINSZ first, some systems that have it also define
4016 * TIOCGSIZE but don't have a struct ttysize.
4017 */
4018# ifdef TIOCGWINSZ
4019 {
4020 struct winsize ws;
4021 int fd = 1;
4022
Bram Moolenaar0f873732019-12-05 20:28:46 +01004023 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 if (!isatty(fd) && isatty(read_cmd_fd))
4025 fd = read_cmd_fd;
4026 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4027 {
4028 columns = ws.ws_col;
4029 rows = ws.ws_row;
4030 }
4031 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004032# else // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033# ifdef TIOCGSIZE
4034 {
4035 struct ttysize ts;
4036 int fd = 1;
4037
Bram Moolenaar0f873732019-12-05 20:28:46 +01004038 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 if (!isatty(fd) && isatty(read_cmd_fd))
4040 fd = read_cmd_fd;
4041 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4042 {
4043 columns = ts.ts_cols;
4044 rows = ts.ts_lines;
4045 }
4046 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004047# endif // TIOCGSIZE
4048# endif // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004049
4050 /*
4051 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004052 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4053 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004055 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 {
4057 if ((p = (char_u *)getenv("LINES")))
4058 rows = atoi((char *)p);
4059 if ((p = (char_u *)getenv("COLUMNS")))
4060 columns = atoi((char *)p);
4061 }
4062
4063#ifdef HAVE_TGETENT
4064 /*
4065 * 3. try reading "co" and "li" entries from termcap
4066 */
4067 if (columns == 0 || rows == 0)
4068 getlinecol(&columns, &rows);
4069#endif
4070
4071 /*
4072 * 4. If everything fails, use the old values
4073 */
4074 if (columns <= 0 || rows <= 0)
4075 return FAIL;
4076
4077 Rows = rows;
4078 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004079 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 return OK;
4081}
4082
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004083#if defined(FEAT_TERMINAL) || defined(PROTO)
4084/*
4085 * Report the windows size "rows" and "cols" to tty "fd".
4086 */
4087 int
4088mch_report_winsize(int fd, int rows, int cols)
4089{
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004090 int tty_fd;
4091 int retval = -1;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004092
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004093 tty_fd = get_tty_fd(fd);
4094 if (tty_fd >= 0)
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004095 {
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004096# if defined(TIOCSWINSZ)
4097 struct winsize ws;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004098
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004099 ws.ws_col = cols;
4100 ws.ws_row = rows;
4101 ws.ws_xpixel = cols * 5;
4102 ws.ws_ypixel = rows * 10;
4103 retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
4104 ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
4105 retval == 0 ? "success" : "failed");
4106# elif defined(TIOCSSIZE)
4107 struct ttysize ts;
4108
4109 ts.ts_cols = cols;
4110 ts.ts_lines = rows;
4111 retval = ioctl(tty_fd, TIOCSSIZE, &ts);
4112 ch_log(NULL, "ioctl(TIOCSSIZE) %s",
4113 retval == 0 ? "success" : "failed");
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004114# endif
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004115 if (tty_fd != fd)
4116 close(tty_fd);
4117 }
4118 return retval == 0 ? OK : FAIL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004119}
4120#endif
4121
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122/*
4123 * Try to set the window size to Rows and Columns.
4124 */
4125 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004126mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127{
4128 if (*T_CWS)
4129 {
4130 /*
4131 * NOTE: if you get an error here that term_set_winsize() is
4132 * undefined, check the output of configure. It could probably not
4133 * find a ncurses, termcap or termlib library.
4134 */
4135 term_set_winsize((int)Rows, (int)Columns);
4136 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01004137 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 }
4139}
4140
Bram Moolenaar0f873732019-12-05 20:28:46 +01004141#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142
4143/*
4144 * Rows and/or Columns has changed.
4145 */
4146 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004147mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148{
Bram Moolenaar0f873732019-12-05 20:28:46 +01004149 // Nothing to do.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150}
4151
Bram Moolenaar205b8862011-09-07 15:04:31 +02004152/*
4153 * Wait for process "child" to end.
4154 * Return "child" if it exited properly, <= 0 on error.
4155 */
4156 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004157wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004158{
4159 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004160 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004161
4162 while (wait_pid != child)
4163 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004164 // When compiled with Python threads are probably used, in which case
4165 // wait() sometimes hangs for no obvious reason. Use waitpid()
4166 // instead and loop (like the GUI). Also needed for other interfaces,
4167 // they might call system().
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004168# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004169 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004170# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004171 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004172# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004173 if (wait_pid == 0)
4174 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004175 // Wait for 1 to 10 msec before trying again.
Bram Moolenaar0981c872020-08-23 14:28:37 +02004176 mch_delay(delay_msec, MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004177 if (++delay_msec > 10)
4178 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004179 continue;
4180 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004181 if (wait_pid <= 0
4182# ifdef ECHILD
4183 && errno == ECHILD
4184# endif
4185 )
4186 break;
4187 }
4188 return wait_pid;
4189}
4190
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004191#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004192/*
4193 * Set the environment for a child process.
4194 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004195 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004196set_child_environment(
4197 long rows,
4198 long columns,
4199 char *term,
4200 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004201{
4202# ifdef HAVE_SETENV
4203 char envbuf[50];
4204# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004205 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004206 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004207 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004208 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004209 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004210# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004211 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004212# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004213# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004214 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004215# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004216# endif
4217
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004218# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004219 setenv("TERM", term, 1);
4220 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004221 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004222 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004223 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004224 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004225 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaar759d8152020-04-26 16:52:49 +02004226 sprintf((char *)envbuf, "%d", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004227 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004228# ifdef FEAT_TERMINAL
4229 if (is_terminal)
4230 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004231 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004232 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4233 }
4234# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004235# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004236 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004237# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004238# else
4239 /*
4240 * Putenv does not copy the string, it has to remain valid.
4241 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004242 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004243 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004244 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4245 putenv(envbuf_Term);
4246 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004247 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004248 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4249 putenv(envbuf_Lines);
4250 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4251 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004252 putenv(envbuf_Columns);
Bram Moolenaaraffc8fd2020-04-28 21:58:29 +02004253 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004254 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004255# ifdef FEAT_TERMINAL
4256 if (is_terminal)
4257 {
4258 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004259 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004260 putenv(envbuf_Version);
4261 }
4262# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004263# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004264 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4265 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4266 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004267# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004268# endif
4269}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004270
4271 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004272set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004273{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004274 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004275}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004276#endif
4277
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004278#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004279/*
4280 * Open a PTY, with FD for the master and slave side.
4281 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
Bram Moolenaar59386482019-02-10 22:43:46 +01004282 * When successful both file descriptors are stored and the allocated pty name
4283 * is stored in both "*name1" and "*name2".
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004284 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004285 static void
Bram Moolenaar59386482019-02-10 22:43:46 +01004286open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004287{
4288 char *tty_name;
4289
Bram Moolenaar59386482019-02-10 22:43:46 +01004290 if (name1 != NULL)
4291 *name1 = NULL;
4292 if (name2 != NULL)
4293 *name2 = NULL;
4294
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004295 *pty_master_fd = mch_openpty(&tty_name); // open pty
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004296 if (*pty_master_fd >= 0)
4297 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004298 // Leaving out O_NOCTTY may lead to waitpid() always returning
4299 // 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4300 // adding O_NOCTTY always works when defined.
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004301#ifdef O_NOCTTY
4302 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4303#else
4304 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4305#endif
4306 if (*pty_slave_fd < 0)
4307 {
4308 close(*pty_master_fd);
4309 *pty_master_fd = -1;
4310 }
Bram Moolenaar59386482019-02-10 22:43:46 +01004311 else
4312 {
4313 if (name1 != NULL)
4314 *name1 = vim_strsave((char_u *)tty_name);
4315 if (name2 != NULL)
4316 *name2 = vim_strsave((char_u *)tty_name);
4317 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004318 }
4319}
4320#endif
4321
Bram Moolenaarfae42832017-08-01 22:24:26 +02004322/*
4323 * Send SIGINT to a child process if "c" is an interrupt character.
4324 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +02004325 static void
Bram Moolenaarfae42832017-08-01 22:24:26 +02004326may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4327{
4328# ifdef SIGINT
4329 if (c == Ctrl_C || c == intr_char)
4330 {
4331# ifdef HAVE_SETSID
4332 kill(-pid, SIGINT);
4333# else
4334 kill(0, SIGINT);
4335# endif
4336 if (wpid > 0)
4337 kill(wpid, SIGINT);
4338 }
4339# endif
4340}
4341
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004342#if !defined(USE_SYSTEM) || defined(FEAT_TERMINAL) || defined(PROTO)
Bram Moolenaar13568252018-03-16 20:46:58 +01004343
Bram Moolenaar0f873732019-12-05 20:28:46 +01004344/*
4345 * Parse "cmd" and return the result in "argvp" which is an allocated array of
4346 * pointers, the last one is NULL.
4347 * The "sh_tofree" and "shcf_tofree" must be later freed by the caller.
4348 */
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004349 int
4350unix_build_argv(
Bram Moolenaar13568252018-03-16 20:46:58 +01004351 char_u *cmd,
4352 char ***argvp,
4353 char_u **sh_tofree,
4354 char_u **shcf_tofree)
4355{
4356 char **argv = NULL;
4357 int argc;
4358
4359 *sh_tofree = vim_strsave(p_sh);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004360 if (*sh_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004361 return FAIL;
4362
4363 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4364 return FAIL;
4365 *argvp = argv;
4366
4367 if (cmd != NULL)
4368 {
4369 char_u *s;
4370 char_u *p;
4371
4372 if (extra_shell_arg != NULL)
4373 argv[argc++] = (char *)extra_shell_arg;
4374
Bram Moolenaar0f873732019-12-05 20:28:46 +01004375 // Break 'shellcmdflag' into white separated parts. This doesn't
4376 // handle quoted strings, they are very unlikely to appear.
Bram Moolenaar964b3742019-05-24 18:54:09 +02004377 *shcf_tofree = alloc(STRLEN(p_shcf) + 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004378 if (*shcf_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004379 return FAIL;
4380 s = *shcf_tofree;
4381 p = p_shcf;
4382 while (*p != NUL)
4383 {
4384 argv[argc++] = (char *)s;
4385 while (*p && *p != ' ' && *p != TAB)
4386 *s++ = *p++;
4387 *s++ = NUL;
4388 p = skipwhite(p);
4389 }
4390
4391 argv[argc++] = (char *)cmd;
4392 }
4393 argv[argc] = NULL;
4394 return OK;
4395}
4396#endif
4397
4398#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4399/*
4400 * Use a terminal window to run a shell command in.
4401 */
4402 static int
4403mch_call_shell_terminal(
4404 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004405 int options UNUSED) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004406{
4407 jobopt_T opt;
4408 char **argv = NULL;
4409 char_u *tofree1 = NULL;
4410 char_u *tofree2 = NULL;
4411 int retval = -1;
4412 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004413 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004414 aco_save_T aco;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004415 oparg_T oa; // operator arguments
Bram Moolenaar13568252018-03-16 20:46:58 +01004416
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004417 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar13568252018-03-16 20:46:58 +01004418 goto theend;
4419
4420 init_job_options(&opt);
4421 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4422 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004423 if (buf == NULL)
4424 goto theend;
4425
4426 job = term_getjob(buf->b_term);
4427 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004428
Bram Moolenaar0f873732019-12-05 20:28:46 +01004429 // Find a window to make "buf" curbuf.
Bram Moolenaar13568252018-03-16 20:46:58 +01004430 aucmd_prepbuf(&aco, buf);
4431
4432 clear_oparg(&oa);
4433 while (term_use_loop())
4434 {
4435 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4436 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004437 // If terminal_loop() returns OK we got a key that is handled
4438 // in Normal model. We don't do redrawing anyway.
Bram Moolenaar13568252018-03-16 20:46:58 +01004439 if (terminal_loop(TRUE) == OK)
4440 normal_cmd(&oa, TRUE);
4441 }
4442 else
4443 normal_cmd(&oa, TRUE);
4444 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004445 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004446 ch_log(NULL, "system command finished");
4447
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004448 job_unref(job);
4449
Bram Moolenaar0f873732019-12-05 20:28:46 +01004450 // restore curwin/curbuf and a few other things
Bram Moolenaar13568252018-03-16 20:46:58 +01004451 aucmd_restbuf(&aco);
4452
4453 wait_return(TRUE);
4454 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4455
4456theend:
4457 vim_free(argv);
4458 vim_free(tofree1);
4459 vim_free(tofree2);
4460 return retval;
4461}
4462#endif
4463
4464#ifdef USE_SYSTEM
4465/*
4466 * Use system() to start the shell: simple but slow.
4467 */
4468 static int
4469mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004470 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004471 int options) // SHELL_*, see vim.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472{
4473#ifdef VMS
4474 char *ifn = NULL;
4475 char *ofn = NULL;
4476#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02004477 tmode_T tmode = cur_tmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004478 char_u *newcmd; // only needed for unix
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004479 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480
4481 out_flush();
4482
4483 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004484 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485
Bram Moolenaar62b42182010-09-21 22:09:37 +02004486# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004487 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004488 loose_clipboard();
4489# endif
4490
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 if (cmd == NULL)
4492 x = system((char *)p_sh);
4493 else
4494 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004495# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 if (ofn = strchr((char *)cmd, '>'))
4497 *ofn++ = '\0';
4498 if (ifn = strchr((char *)cmd, '<'))
4499 {
4500 char *p;
4501
4502 *ifn++ = '\0';
Bram Moolenaar0f873732019-12-05 20:28:46 +01004503 p = strchr(ifn,' '); // chop off any trailing spaces
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504 if (p)
4505 *p = '\0';
4506 }
4507 if (ofn)
4508 x = vms_sys((char *)cmd, ofn, ifn);
4509 else
4510 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004511# else
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004512 newcmd = alloc(STRLEN(p_sh)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004514 + STRLEN(p_shcf) + STRLEN(cmd) + 4);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515 if (newcmd == NULL)
4516 x = 0;
4517 else
4518 {
4519 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4520 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4521 (char *)p_shcf,
4522 (char *)cmd);
4523 x = system((char *)newcmd);
4524 vim_free(newcmd);
4525 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004526# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 }
4528# ifdef VMS
4529 x = vms_sys_status(x);
4530# endif
4531 if (emsg_silent)
4532 ;
4533 else if (x == 127)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004534 msg_puts(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535 else if (x && !(options & SHELL_SILENT))
4536 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004537 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 msg_outnum((long)x);
4539 msg_putchar('\n');
4540 }
4541
4542 if (tmode == TMODE_RAW)
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004543 {
4544 // The shell may have messed with the mode, always set it.
4545 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004546 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548# ifdef FEAT_TITLE
4549 resettitle();
4550# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004551# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4552 restore_clipboard();
4553# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004555}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556
Bram Moolenaar0f873732019-12-05 20:28:46 +01004557#else // USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558
Bram Moolenaar0f873732019-12-05 20:28:46 +01004559# define EXEC_FAILED 122 // Exit code when shell didn't execute. Don't use
4560 // 127, some shells use that already
4561# define OPEN_NULL_FAILED 123 // Exit code if /dev/null can't be opened
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562
Bram Moolenaar13568252018-03-16 20:46:58 +01004563/*
4564 * Don't use system(), use fork()/exec().
4565 */
4566 static int
4567mch_call_shell_fork(
4568 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004569 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004570{
Bram Moolenaar26e86442020-05-17 14:06:16 +02004571 tmode_T tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004573 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574 pid_t wait_pid = 0;
4575# ifdef HAVE_UNION_WAIT
4576 union wait status;
4577# else
4578 int status = -1;
4579# endif
4580 int retval = -1;
4581 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004582 char_u *tofree1 = NULL;
4583 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 int i;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004585 int pty_master_fd = -1; // for pty's
Bram Moolenaardf177f62005-02-22 08:39:57 +00004586# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004588# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01004589 int fd_toshell[2]; // for pipes
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 int fd_fromshell[2];
4591 int pipe_error = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004592 int did_settmode = FALSE; // settmode(TMODE_RAW) called
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593
4594 out_flush();
4595 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004596 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004597 if (tmode == TMODE_RAW)
4598 // The shell may have messed with the mode, always set it later.
4599 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004601 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004602 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004603
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004605 * For the GUI, when writing the output into the buffer and when reading
4606 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4607 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004609 if ((options & (SHELL_READ|SHELL_WRITE))
4610# ifdef FEAT_GUI
4611 || (gui.in_use && show_shell_mess)
4612# endif
4613 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004615# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 /*
4617 * Try to open a master pty.
4618 * If this works, open the slave pty.
4619 * If the slave can't be opened, close the master pty.
4620 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004621 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar59386482019-02-10 22:43:46 +01004622 open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 /*
4624 * If not opening a pty or it didn't work, try using pipes.
4625 */
4626 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004627# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 {
4629 pipe_error = (pipe(fd_toshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004630 if (!pipe_error) // pipe create OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 {
4632 pipe_error = (pipe(fd_fromshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004633 if (pipe_error) // pipe create failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 {
4635 close(fd_toshell[0]);
4636 close(fd_toshell[1]);
4637 }
4638 }
4639 if (pipe_error)
4640 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004641 msg_puts(_("\nCannot create pipes\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 out_flush();
4643 }
4644 }
4645 }
4646
Bram Moolenaar0f873732019-12-05 20:28:46 +01004647 if (!pipe_error) // pty or pipe opened or not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004649 SIGSET_DECL(curset)
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004650 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004651 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004652 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004654 UNBLOCK_SIGNALS(&curset);
4655
Bram Moolenaar32526b32019-01-19 17:43:09 +01004656 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 Moolenaar0f873732019-12-05 20:28:46 +01004664 if (pty_master_fd >= 0) // close the pseudo tty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665 {
4666 close(pty_master_fd);
4667 close(pty_slave_fd);
4668 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004669 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 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004679 else if (pid == 0) // child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004681 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())
Bram Moolenaar0f873732019-12-05 20:28:46 +01004686 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01004687 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 Moolenaar0f873732019-12-05 20:28:46 +01004718 vim_ignored = dup(fd); // To replace stdin (fd 0)
4719 vim_ignored = dup(fd); // To replace stdout (fd 1)
4720 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721
Bram Moolenaar0f873732019-12-05 20:28:46 +01004722 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723 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 Moolenaar0f873732019-12-05 20:28:46 +01004734 // 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,
4736 // 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)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004741 // 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)
Bram Moolenaar07256082009-02-04 13:19:42 +00004745 signal(SIGHUP, SIG_IGN);
4746# endif
4747 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004748# endif
4749# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004750 if (pty_slave_fd >= 0)
4751 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004752 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004753 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004754 setup_slavepty(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01004756 // Try to become controlling tty (probably doesn't work,
4757 // unless run by root)
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004758 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004760 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004761# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004762 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763
Bram Moolenaara5792f52005-11-23 21:25:05 +00004764 /*
4765 * stderr is only redirected when using the GUI, so that a
4766 * program like gpg can still access the terminal to get a
4767 * passphrase using stderr.
4768 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004769# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 if (pty_master_fd >= 0)
4771 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004772 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773
Bram Moolenaar0f873732019-12-05 20:28:46 +01004774 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004776 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004778 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004779 if (gui.in_use)
4780 {
4781 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004782 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784
Bram Moolenaar0f873732019-12-05 20:28:46 +01004785 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 }
4787 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004788# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004790 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 close(fd_toshell[1]);
4792 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004793 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 close(fd_toshell[0]);
4795
Bram Moolenaar0f873732019-12-05 20:28:46 +01004796 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 close(fd_fromshell[0]);
4798 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004799 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800 close(fd_fromshell[1]);
4801
Bram Moolenaara5792f52005-11-23 21:25:05 +00004802# ifdef FEAT_GUI
4803 if (gui.in_use)
4804 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004805 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004806 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004807 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004808 }
4809# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 }
4811 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004812
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 /*
4814 * There is no type cast for the argv, because the type may be
4815 * different on different machines. This may cause a warning
4816 * message with strict compilers, don't worry about it.
4817 * Call _exit() instead of exit() to avoid closing the connection
4818 * to the X server (esp. with GTK, which uses atexit()).
4819 */
4820 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004821 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004823 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 {
4825 /*
4826 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004827 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 */
4829 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004830 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004831 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004832# ifdef FEAT_JOB_CHANNEL
4833 ++dont_check_job_ended;
4834# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835 /*
4836 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004837 * This is also used to pipe stdin/stdout to/from the external
4838 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004840 if ((options & (SHELL_READ|SHELL_WRITE))
4841# ifdef FEAT_GUI
4842 || (gui.in_use && show_shell_mess)
4843# endif
4844 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004845 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004846# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004847 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004848 int buffer_off = 0; // valid bytes in buffer[]
4849 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4850 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 int len;
4852 int p_more_save;
4853 int old_State;
4854 int c;
4855 int toshell_fd;
4856 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004857 garray_T ga;
4858 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004859# ifdef ELAPSED_FUNC
4860 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004861# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862
Bram Moolenaardf177f62005-02-22 08:39:57 +00004863# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004864 if (pty_master_fd >= 0)
4865 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 fromshell_fd = pty_master_fd;
4867 toshell_fd = dup(pty_master_fd);
4868 }
4869 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004870# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 {
4872 close(fd_toshell[0]);
4873 close(fd_fromshell[1]);
4874 toshell_fd = fd_toshell[1];
4875 fromshell_fd = fd_fromshell[0];
4876 }
4877
4878 /*
4879 * Write to the child if there are typed characters.
4880 * Read from the child if there are characters available.
4881 * Repeat the reading a few times if more characters are
4882 * available. Need to check for typed keys now and then, but
4883 * not too often (delays when no chars are available).
4884 * This loop is quit if no characters can be read from the pty
4885 * (WaitForChar detected special condition), or there are no
4886 * characters available and the child has exited.
4887 * Only check if the child has exited when there is no more
4888 * output. The child may exit before all the output has
4889 * been printed.
4890 *
4891 * Currently this busy loops!
4892 * This can probably dead-lock when the write blocks!
4893 */
4894 p_more_save = p_more;
4895 p_more = FALSE;
4896 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004897 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004899 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004900 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004901 // Fork a process that will write the lines to the
4902 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004903 if ((wpid = fork()) == -1)
4904 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004905 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004906 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004907 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004908 {
4909 linenr_T lnum = curbuf->b_op_start.lnum;
4910 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004911 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004912 size_t l;
4913
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004914 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004915 for (;;)
4916 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004917 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004918 if (l == 0)
4919 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004920 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004921 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00004922 len = write(toshell_fd, "", (size_t)1);
4923 else
4924 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004925 char_u *s = vim_strchr(lp + written, NL);
4926
Bram Moolenaar89d40322006-08-29 15:30:07 +00004927 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004928 s == NULL ? l
4929 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004930 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004931 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004932 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004933 // Finished a line, add a NL, unless this line
4934 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004935 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004936 || (!curbuf->b_p_bin
4937 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004938 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004939 && (lnum !=
4940 curbuf->b_ml.ml_line_count
4941 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02004942 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004943 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004944 ++lnum;
4945 if (lnum > curbuf->b_op_end.lnum)
4946 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004947 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00004948 close(toshell_fd);
4949 toshell_fd = -1;
4950 break;
4951 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004952 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004953 written = 0;
4954 }
4955 else if (len > 0)
4956 written += len;
4957 }
4958 _exit(0);
4959 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004960 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00004961 {
4962 close(toshell_fd);
4963 toshell_fd = -1;
4964 }
4965 }
4966
4967 if (options & SHELL_READ)
4968 ga_init2(&ga, 1, BUFLEN);
4969
4970 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004971# ifdef ELAPSED_FUNC
4972 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004973# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974 for (;;)
4975 {
4976 /*
4977 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004978 * if there are any.
4979 * Don't do this if we are expanding wild cards (would eat
4980 * typeahead).
4981 * Don't do this when filtering and terminal is in cooked
4982 * mode, the shell command will handle the I/O. Avoids
4983 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004984 * Don't get characters when the child has already
4985 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004986 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004987 * while (noread_cnt > 4), avoids that ":r !ls" eats
4988 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989 */
4990 len = 0;
4991 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004992 && ((options &
4993 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4994 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004995# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004996 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004997# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004998 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004999 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005000 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005002 if (ta_len == 0)
5003 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005004 // Get extra characters when we don't have any.
5005 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005006 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005007# ifdef ELAPSED_FUNC
5008 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005009# endif
5010 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5011 }
5012 if (ta_len > 0 || len > 0)
5013 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 /*
5015 * For pipes:
5016 * Check for CTRL-C: send interrupt signal to child.
5017 * Check for CTRL-D: EOF, close pipe to child.
5018 */
5019 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5020 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005021 /*
5022 * Send SIGINT to the child's group or all
5023 * processes in our group.
5024 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005025 may_send_sigint(ta_buf[ta_len], pid, wpid);
5026
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027 if (pty_master_fd < 0 && toshell_fd >= 0
5028 && ta_buf[ta_len] == Ctrl_D)
5029 {
5030 close(toshell_fd);
5031 toshell_fd = -1;
5032 }
5033 }
5034
Bram Moolenaarf4140482020-02-15 23:06:45 +01005035 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036
5037 /*
5038 * For pipes: echo the typed characters.
5039 * For a pty this does not seem to work.
5040 */
5041 if (pty_master_fd < 0)
5042 {
5043 for (i = ta_len; i < ta_len + len; ++i)
5044 {
5045 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5046 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 else if (has_mbyte)
5048 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005049 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005050
5051 msg_outtrans_len(ta_buf + i, l);
5052 i += l - 1;
5053 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 else
5055 msg_outtrans_len(ta_buf + i, 1);
5056 }
5057 windgoto(msg_row, msg_col);
5058 out_flush();
5059 }
5060
5061 ta_len += len;
5062
5063 /*
5064 * Write the characters to the child, unless EOF has
5065 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005066 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005067 * When writing buffer lines, drop the typed
5068 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005069 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005070 if (options & SHELL_WRITE)
5071 ta_len = 0;
5072 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005073 {
5074 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5075 if (len > 0)
5076 {
5077 ta_len -= len;
5078 mch_memmove(ta_buf, ta_buf + len, ta_len);
5079 }
5080 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005081 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005082 }
5083
Bram Moolenaardf177f62005-02-22 08:39:57 +00005084 if (got_int)
5085 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005086 // CTRL-C sends a signal to the child, we ignore it
5087 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005088# ifdef HAVE_SETSID
5089 kill(-pid, SIGINT);
5090# else
5091 kill(0, SIGINT);
5092# endif
5093 if (wpid > 0)
5094 kill(wpid, SIGINT);
5095 got_int = FALSE;
5096 }
5097
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 /*
5099 * Check if the child has any characters to be printed.
5100 * Read them and write them to our window. Repeat this as
5101 * long as there is something to do, avoid the 10ms wait
5102 * for mch_inchar(), or sending typeahead characters to
5103 * the external process.
5104 * TODO: This should handle escape sequences, compatible
5105 * to some terminal (vt52?).
5106 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005107 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005108 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005110 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005113 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005115
5116 noread_cnt = 0;
5117 if (options & SHELL_READ)
5118 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005119 // Do NUL -> NL translation, append NL separated
5120 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005121 for (i = 0; i < len; ++i)
5122 {
5123 if (buffer[i] == NL)
5124 append_ga_line(&ga);
5125 else if (buffer[i] == NUL)
5126 ga_append(&ga, NL);
5127 else
5128 ga_append(&ga, buffer[i]);
5129 }
5130 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005131 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 {
5133 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005134 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135
Bram Moolenaardf177f62005-02-22 08:39:57 +00005136 len += buffer_off;
5137 buffer[len] = NUL;
5138
Bram Moolenaar0f873732019-12-05 20:28:46 +01005139 // Check if the last character in buffer[] is
5140 // incomplete, keep these bytes for the next
5141 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142 for (p = buffer; p < buffer + len; p += l)
5143 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005144 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005146 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147 else if (MB_BYTE2LEN(*p) != l)
5148 break;
5149 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005150 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005151 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005152 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153 if (len >= 12)
5154 ++p;
5155 else
5156 {
5157 buffer_off = len;
5158 continue;
5159 }
5160 }
5161 c = *p;
5162 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005163 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005164 if (p < buffer + len)
5165 {
5166 *p = c;
5167 buffer_off = (buffer + len) - p;
5168 mch_memmove(buffer, p, buffer_off);
5169 continue;
5170 }
5171 buffer_off = 0;
5172 }
5173 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174 {
5175 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005176 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177 }
5178
5179 windgoto(msg_row, msg_col);
5180 cursor_on();
5181 out_flush();
5182 if (got_int)
5183 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005184
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005185# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005186 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005187 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005188 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005189
Bram Moolenaar0f873732019-12-05 20:28:46 +01005190 // Avoid that we keep looping here without
5191 // checking for a CTRL-C for a long time. Don't
5192 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005193 if (msec > 2000)
5194 {
5195 noread_cnt = 5;
5196 break;
5197 }
5198 }
5199# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 }
5201
Bram Moolenaar0f873732019-12-05 20:28:46 +01005202 // If we already detected the child has finished, continue
5203 // reading output for a short while. Some text may be
5204 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005205 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005206 {
5207 if (noread_cnt < 5)
5208 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005209 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005210 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005211
Bram Moolenaar071d4272004-06-13 20:20:40 +00005212 /*
5213 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005214 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005215 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005216# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005217 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005218# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005220# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5222 || (wait_pid == pid && WIFEXITED(status)))
5223 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005224 // Don't break the loop yet, try reading more
5225 // characters from "fromshell_fd" first. When using
5226 // pipes there might still be something to read and
5227 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005228 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005230 else
5231 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005232
Bram Moolenaar95a51352013-03-21 22:53:50 +01005233# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005234 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005235 clip_update();
5236# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 }
5238finished:
5239 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005240 if (options & SHELL_READ)
5241 {
5242 if (ga.ga_len > 0)
5243 {
5244 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005245 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005246 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005247 }
5248 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005249 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005250 ga_clear(&ga);
5251 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253 /*
5254 * Give all typeahead that wasn't used back to ui_inchar().
5255 */
5256 if (ta_len)
5257 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258 State = old_State;
5259 if (toshell_fd >= 0)
5260 close(toshell_fd);
5261 close(fromshell_fd);
5262 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005263# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005264 else
5265 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005266 long delay_msec = 1;
5267
Bram Moolenaar0981c872020-08-23 14:28:37 +02005268 out_str(T_CTE); // possibly disables modifyOtherKeys, so that
5269 // the system can recognize CTRL-C
5270
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005271 /*
5272 * Similar to the loop above, but only handle X events, no
5273 * I/O.
5274 */
5275 for (;;)
5276 {
5277 if (got_int)
5278 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005279 // CTRL-C sends a signal to the child, we ignore it
5280 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005281# ifdef HAVE_SETSID
5282 kill(-pid, SIGINT);
5283# else
5284 kill(0, SIGINT);
5285# endif
5286 got_int = FALSE;
5287 }
5288# ifdef __NeXT__
5289 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5290# else
5291 wait_pid = waitpid(pid, &status, WNOHANG);
5292# endif
5293 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5294 || (wait_pid == pid && WIFEXITED(status)))
5295 {
5296 wait_pid = pid;
5297 break;
5298 }
5299
Bram Moolenaar0f873732019-12-05 20:28:46 +01005300 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005301 clip_update();
5302
Bram Moolenaar0f873732019-12-05 20:28:46 +01005303 // Wait for 1 to 10 msec. 1 is faster but gives the child
Bram Moolenaar0981c872020-08-23 14:28:37 +02005304 // less time, gradually wait longer.
5305 mch_delay(delay_msec,
5306 MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005307 if (++delay_msec > 10)
5308 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005309 }
Bram Moolenaar0981c872020-08-23 14:28:37 +02005310
5311 out_str(T_CTI); // possibly enables modifyOtherKeys again
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005312 }
5313# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005314
5315 /*
5316 * Wait until our child has exited.
5317 * Ignore wait() returning pids of other children and returning
5318 * because of some signal like SIGWINCH.
5319 * Don't wait if wait_pid was already set above, indicating the
5320 * child already exited.
5321 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005322 if (wait_pid != pid)
5323 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005324
Bram Moolenaar624891f2010-10-13 16:22:09 +02005325# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005326 // Close slave side of pty. Only do this after the child has
5327 // exited, otherwise the child may hang when it tries to write on
5328 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005329 if (pty_master_fd >= 0)
5330 close(pty_slave_fd);
5331# endif
5332
Bram Moolenaar0f873732019-12-05 20:28:46 +01005333 // Make sure the child that writes to the external program is
5334 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005335 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005336 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005337 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005338 wait4pid(wpid, NULL);
5339 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005340
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005341# ifdef FEAT_JOB_CHANNEL
5342 --dont_check_job_ended;
5343# endif
5344
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345 /*
5346 * Set to raw mode right now, otherwise a CTRL-C after
5347 * catch_signals() will kill Vim.
5348 */
5349 if (tmode == TMODE_RAW)
5350 settmode(TMODE_RAW);
5351 did_settmode = TRUE;
5352 set_signals();
5353
5354 if (WIFEXITED(status))
5355 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005356 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005357 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005358 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005359 {
5360 if (retval == EXEC_FAILED)
5361 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005362 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363 msg_outtrans(p_sh);
5364 msg_putchar('\n');
5365 }
5366 else if (!(options & SHELL_SILENT))
5367 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005368 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005369 msg_outnum((long)retval);
5370 msg_putchar('\n');
5371 }
5372 }
5373 }
5374 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005375 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005376 }
5377 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378
5379error:
5380 if (!did_settmode)
5381 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005382 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005383# ifdef FEAT_TITLE
5384 resettitle();
5385# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005386 vim_free(argv);
5387 vim_free(tofree1);
5388 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005389
5390 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005391}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005392#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005393
5394 int
5395mch_call_shell(
5396 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005397 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005398{
5399#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5400 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5401 return mch_call_shell_terminal(cmd, options);
5402#endif
5403#ifdef USE_SYSTEM
5404 return mch_call_shell_system(cmd, options);
5405#else
5406 return mch_call_shell_fork(cmd, options);
5407#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005408}
5409
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005410#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005411 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005412mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005413{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005414 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005415 int fd_in[2] = {-1, -1}; // for stdin
5416 int fd_out[2] = {-1, -1}; // for stdout
5417 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005418 int pty_master_fd = -1;
5419 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005420 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005421 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5422 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5423 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005424 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005425 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5426 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005427 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005428 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005429 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005430
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005431 if (use_out_for_err && use_null_for_out)
5432 use_null_for_err = TRUE;
5433
Bram Moolenaar0f873732019-12-05 20:28:46 +01005434 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005435 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005436
Bram Moolenaarb2412082017-08-20 18:09:14 +02005437 if (options->jo_pty
5438 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005439 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005440 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005441 open_pty(&pty_master_fd, &pty_slave_fd,
5442 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005443
Bram Moolenaar0f873732019-12-05 20:28:46 +01005444 // TODO: without the channel feature connect the child to /dev/null?
5445 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005446 if (use_file_for_in)
5447 {
5448 char_u *fname = options->jo_io_name[PART_IN];
5449
5450 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5451 if (fd_in[0] < 0)
5452 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005453 semsg(_(e_notopen), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005454 goto failed;
5455 }
5456 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005457 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005458 // When writing buffer lines to the input don't use the pty, so that
5459 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005460 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5461 && pipe(fd_in) < 0)
5462 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005463
5464 if (use_file_for_out)
5465 {
5466 char_u *fname = options->jo_io_name[PART_OUT];
5467
5468 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5469 if (fd_out[1] < 0)
5470 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005471 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005472 goto failed;
5473 }
5474 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005475 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005476 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005477
5478 if (use_file_for_err)
5479 {
5480 char_u *fname = options->jo_io_name[PART_ERR];
5481
5482 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5483 if (fd_err[1] < 0)
5484 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005485 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005486 goto failed;
5487 }
5488 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005489 else if (!use_out_for_err && !use_null_for_err
5490 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005491 goto failed;
5492
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005493 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5494 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005495 if (options->jo_set & JO_CHANNEL)
5496 {
5497 channel = options->jo_channel;
5498 if (channel != NULL)
5499 ++channel->ch_refcount;
5500 }
5501 else
5502 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005503 if (channel == NULL)
5504 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005505 if (job->jv_tty_out != NULL)
5506 ch_log(channel, "using pty %s on fd %d",
5507 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005508 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005509
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005510 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005511 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005512 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005513 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005514 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005515 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005516 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005517 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005518 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005519 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005520 int null_fd = -1;
5521 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005522
Bram Moolenaar0f873732019-12-05 20:28:46 +01005523 // child
5524 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005525 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005526
Bram Moolenaar819524702018-02-27 19:10:00 +01005527# ifdef FEAT_JOB_CHANNEL
5528 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005529 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005530 ch_logfile((char_u *)"", (char_u *)"");
5531# endif
5532
Bram Moolenaar835dc632016-02-07 14:27:38 +01005533# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005534 // Create our own process group, so that the child and all its
5535 // children can be kill()ed. Don't do this when using pipes,
5536 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005537 (void)setsid();
5538# endif
5539
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005540# ifdef FEAT_TERMINAL
5541 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005542 {
5543 char *term = (char *)T_NAME;
5544
5545#ifdef FEAT_GUI
5546 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005547 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005548 term = getenv("TERM");
5549#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005550 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005551 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005552 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005553 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005554 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005555 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005556 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005557 else if (t_colors > 16)
5558 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005559 else
5560 term = "xterm";
5561 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005562 set_child_environment(
5563 (long)options->jo_term_rows,
5564 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005565 term,
5566 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005567 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005568 else
5569# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005570 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005571
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005572 if (options->jo_env != NULL)
5573 {
5574 dict_T *dict = options->jo_env;
5575 hashitem_T *hi;
5576 int todo = (int)dict->dv_hashtab.ht_used;
5577
5578 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5579 if (!HASHITEM_EMPTY(hi))
5580 {
5581 typval_T *item = &dict_lookup(hi)->di_tv;
5582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005583 vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005584 --todo;
5585 }
5586 }
5587
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005588 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005589 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005590 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005591 if (null_fd < 0)
5592 {
5593 perror("opening /dev/null failed");
5594 _exit(OPEN_NULL_FAILED);
5595 }
5596 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005597
Bram Moolenaar223896d2017-08-02 22:33:28 +02005598 if (pty_slave_fd >= 0)
5599 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005600 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005601 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005602# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005603 // Try to become controlling tty (probably doesn't work,
5604 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005605 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5606# endif
5607 }
5608
Bram Moolenaar0f873732019-12-05 20:28:46 +01005609 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005610 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005611 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005612 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005613 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005614 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005615 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005616 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005617
Bram Moolenaar0f873732019-12-05 20:28:46 +01005618 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005619 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005620 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005621 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005622 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005623 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005624 }
5625 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005626 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005627 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005628 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005629 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005630 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005631
Bram Moolenaar0f873732019-12-05 20:28:46 +01005632 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005633 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005634 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005635 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005636 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005637 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005638 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005639 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005640
5641 if (fd_in[0] >= 0)
5642 close(fd_in[0]);
5643 if (fd_in[1] >= 0)
5644 close(fd_in[1]);
5645 if (fd_out[0] >= 0)
5646 close(fd_out[0]);
5647 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005648 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005649 if (fd_err[0] >= 0)
5650 close(fd_err[0]);
5651 if (fd_err[1] >= 0)
5652 close(fd_err[1]);
5653 if (pty_master_fd >= 0)
5654 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005655 close(pty_master_fd); // not used in the child
5656 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005657 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005658
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005659 if (null_fd >= 0)
5660 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005661
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005662 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5663 _exit(EXEC_FAILED);
5664
Bram Moolenaar0f873732019-12-05 20:28:46 +01005665 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005666 execvp(argv[0], argv);
5667
Bram Moolenaar4694a172016-04-21 14:05:23 +02005668 if (stderr_works)
5669 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005670# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005671 // calling free_all_mem() here causes problems. Ignore valgrind
5672 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005673# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005674 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005675 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005676
Bram Moolenaar0f873732019-12-05 20:28:46 +01005677 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005678 UNBLOCK_SIGNALS(&curset);
5679
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005680 job->jv_pid = pid;
5681 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005682 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005683
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005684 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005685 close(pty_slave_fd); // not used in the parent
5686 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005687 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005688 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005689 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005690 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005691 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005692 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005693 if (channel != NULL)
5694 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005695 int in_fd = INVALID_FD;
5696 int out_fd = INVALID_FD;
5697 int err_fd = INVALID_FD;
5698
5699 if (!(use_file_for_in || use_null_for_in))
5700 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5701
5702 if (!(use_file_for_out || use_null_for_out))
5703 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5704
5705 // When using pty_master_fd only set it for stdout, do not duplicate
5706 // it for stderr, it only needs to be read once.
5707 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5708 {
5709 if (fd_err[0] >= 0)
5710 err_fd = fd_err[0];
5711 else if (out_fd != pty_master_fd)
5712 err_fd = pty_master_fd;
5713 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005714
5715 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005716 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005717 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005718 else
5719 {
5720 if (fd_in[1] >= 0)
5721 close(fd_in[1]);
5722 if (fd_out[0] >= 0)
5723 close(fd_out[0]);
5724 if (fd_err[0] >= 0)
5725 close(fd_err[0]);
5726 if (pty_master_fd >= 0)
5727 close(pty_master_fd);
5728 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005729
Bram Moolenaar0f873732019-12-05 20:28:46 +01005730 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005731 return;
5732
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005733failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005734 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005735 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005736 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005737 if (fd_in[1] >= 0)
5738 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005739 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005740 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005741 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005742 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005743 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005744 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005745 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005746 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005747 if (pty_master_fd >= 0)
5748 close(pty_master_fd);
5749 if (pty_slave_fd >= 0)
5750 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005751}
5752
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005753 static char_u *
5754get_signal_name(int sig)
5755{
5756 int i;
5757 char_u numbuf[NUMBUFLEN];
5758
5759 if (sig == SIGKILL)
5760 return vim_strsave((char_u *)"kill");
5761
5762 for (i = 0; signal_info[i].sig != -1; i++)
5763 if (sig == signal_info[i].sig)
5764 return strlow_save((char_u *)signal_info[i].name);
5765
5766 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5767 return vim_strsave(numbuf);
5768}
5769
Bram Moolenaar835dc632016-02-07 14:27:38 +01005770 char *
5771mch_job_status(job_T *job)
5772{
5773# ifdef HAVE_UNION_WAIT
5774 union wait status;
5775# else
5776 int status = -1;
5777# endif
5778 pid_t wait_pid = 0;
5779
5780# ifdef __NeXT__
5781 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5782# else
5783 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5784# endif
5785 if (wait_pid == -1)
5786 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005787 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005788 if (job->jv_status < JOB_ENDED)
5789 ch_log(job->jv_channel, "Job no longer exists: %s",
5790 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005791 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005792 }
5793 if (wait_pid == 0)
5794 return "run";
5795 if (WIFEXITED(status))
5796 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005797 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005798 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005799 if (job->jv_status < JOB_ENDED)
5800 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005801 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005802 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005803 if (WIFSIGNALED(status))
5804 {
5805 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005806 job->jv_termsig = get_signal_name(WTERMSIG(status));
5807 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5808 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5809 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005810 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005811 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005812 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005813
5814return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005815 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005816 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005817 return "dead";
5818}
5819
5820 job_T *
5821mch_detect_ended_job(job_T *job_list)
5822{
5823# ifdef HAVE_UNION_WAIT
5824 union wait status;
5825# else
5826 int status = -1;
5827# endif
5828 pid_t wait_pid = 0;
5829 job_T *job;
5830
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005831# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005832 // Do not do this when waiting for a shell command to finish, we would get
5833 // the exit value here (and discard it), the exit value obtained there
5834 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005835 if (dont_check_job_ended > 0)
5836 return NULL;
5837# endif
5838
Bram Moolenaar97792de2016-10-15 18:36:49 +02005839# ifdef __NeXT__
5840 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5841# else
5842 wait_pid = waitpid(-1, &status, WNOHANG);
5843# endif
5844 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005845 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005846 return NULL;
5847 for (job = job_list; job != NULL; job = job->jv_next)
5848 {
5849 if (job->jv_pid == wait_pid)
5850 {
5851 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005852 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005853 job->jv_exitval = WEXITSTATUS(status);
5854 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005855 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005856 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005857 job->jv_termsig = get_signal_name(WTERMSIG(status));
5858 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005859 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005860 {
5861 ch_log(job->jv_channel, "Job ended");
5862 job->jv_status = JOB_ENDED;
5863 }
5864 return job;
5865 }
5866 }
5867 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005868}
5869
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005870/*
5871 * Send a (deadly) signal to "job".
5872 * Return FAIL if "how" is not a valid name.
5873 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005874 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005875mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005876{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005877 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005878
Bram Moolenaar923d9262016-02-25 20:56:01 +01005879 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005880 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005881 else if (STRCMP(how, "hup") == 0)
5882 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005883 else if (STRCMP(how, "quit") == 0)
5884 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005885 else if (STRCMP(how, "int") == 0)
5886 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005887 else if (STRCMP(how, "kill") == 0)
5888 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005889#ifdef SIGWINCH
5890 else if (STRCMP(how, "winch") == 0)
5891 sig = SIGWINCH;
5892#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005893 else if (isdigit(*how))
5894 sig = atoi((char *)how);
5895 else
5896 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005897
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005898 // Never kill ourselves!
5899 if (job->jv_pid != 0)
5900 {
5901 // TODO: have an option to only kill the process, not the group?
5902 kill(-job->jv_pid, sig);
5903 kill(job->jv_pid, sig);
5904 }
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{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005915 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005916# 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 Moolenaar59386482019-02-10 22:43:46 +01005932 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaard0342202020-06-29 22:40:42 +02005933 if (pty_master_fd < 0 || pty_slave_fd < 0)
5934 return FAIL;
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 Moolenaar0f873732019-12-05 20:28:46 +01005946 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005947 channel->ch_keep_open = TRUE;
5948
Bram Moolenaar0f873732019-12-05 20:28:46 +01005949 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5950 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005951 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 Moolenaar26e86442020-05-17 14:06:16 +02005964 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005965 && 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 Moolenaar0f873732019-12-05 20:28:46 +01006012 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)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006016 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017 if (WantQueryMouse)
6018 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006019 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006020 if (!no_query_mouse_for_testing)
6021 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022 }
6023#endif
6024
6025 /*
6026 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6027 * events. This is a bit complicated, because they might both be defined.
6028 */
6029#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6030# ifdef FEAT_XCLIPBOARD
6031 rest = 0;
6032 if (do_xterm_trace())
6033 rest = msec;
6034# endif
6035 do
6036 {
6037# ifdef FEAT_XCLIPBOARD
6038 if (rest != 0)
6039 {
6040 msec = XT_TRACE_DELAY;
6041 if (rest >= 0 && rest < XT_TRACE_DELAY)
6042 msec = rest;
6043 if (rest >= 0)
6044 rest -= msec;
6045 }
6046# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006047# ifdef FEAT_SOUND_CANBERRA
6048 // Invoke any pending sound callbacks.
6049 if (has_sound_callback_in_queue())
6050 invoke_sound_callback();
6051# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006052# ifdef FEAT_MOUSE_GPM
6053 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006054 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006055 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006056 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006057# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006058 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006060# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006062 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063 return 1;
6064# ifdef FEAT_XCLIPBOARD
6065 if (rest == 0 || !do_xterm_trace())
6066# endif
6067 break;
6068 }
6069 }
6070 while (FALSE
6071# ifdef FEAT_MOUSE_GPM
6072 || (gpm_process_wanted && mch_gpm_process() == 0)
6073# endif
6074# ifdef FEAT_XCLIPBOARD
6075 || (!avail && rest != 0)
6076# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006077 )
6078 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079
6080#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006081 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006082#endif
6083 return avail;
6084}
6085
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006086#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006087/*
6088 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006089 * "msec" == 0 will check for characters once.
6090 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006093 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006094 * "interrupted" (if not NULL) is set to TRUE when no character is available
6095 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096 */
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006097 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02006098RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006099{
6100 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006101 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006102#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 static int busy = FALSE;
6104
Bram Moolenaar0f873732019-12-05 20:28:46 +01006105 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006106# define MAY_LOOP
6107
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006108# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006109 // Remember at what time we started, so that we know how much longer we
6110 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006111 long start_msec = msec;
6112 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006113
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006114 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006115 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006116# endif
6117
Bram Moolenaar0f873732019-12-05 20:28:46 +01006118 // Handle being called recursively. This may happen for the session
6119 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006120 if (busy)
6121 return 0;
6122#endif
6123
6124#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006125 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006126#endif
6127 {
6128#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006129 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006130# ifdef FEAT_MZSCHEME
6131 int mzquantum_used = FALSE;
6132# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133#endif
6134#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006135 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006136 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137 int nfd;
6138# ifdef FEAT_XCLIPBOARD
6139 int xterm_idx = -1;
6140# endif
6141# ifdef FEAT_MOUSE_GPM
6142 int gpm_idx = -1;
6143# endif
6144# ifdef USE_XSMP
6145 int xsmp_idx = -1;
6146# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006147 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006148
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006149# ifdef FEAT_MZSCHEME
6150 mzvim_check_threads();
6151 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6152 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006153 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006154 mzquantum_used = TRUE;
6155 }
6156# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006157 fds[0].fd = fd;
6158 fds[0].events = POLLIN;
6159 nfd = 1;
6160
Bram Moolenaar071d4272004-06-13 20:20:40 +00006161# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006162 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163 if (xterm_Shell != (Widget)0)
6164 {
6165 xterm_idx = nfd;
6166 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6167 fds[nfd].events = POLLIN;
6168 nfd++;
6169 }
6170# endif
6171# ifdef FEAT_MOUSE_GPM
6172 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6173 {
6174 gpm_idx = nfd;
6175 fds[nfd].fd = gpm_fd;
6176 fds[nfd].events = POLLIN;
6177 nfd++;
6178 }
6179# endif
6180# ifdef USE_XSMP
6181 if (xsmp_icefd != -1)
6182 {
6183 xsmp_idx = nfd;
6184 fds[nfd].fd = xsmp_icefd;
6185 fds[nfd].events = POLLIN;
6186 nfd++;
6187 }
6188# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006189#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006190 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006191#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006192 if (interrupted != NULL)
6193 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006195 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006196
6197 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006198 if (result == 0 && interrupted != NULL && ret > 0)
6199 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006200
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006201# ifdef FEAT_MZSCHEME
6202 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006203 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006204 finished = FALSE;
6205# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006206
Bram Moolenaar071d4272004-06-13 20:20:40 +00006207# ifdef FEAT_XCLIPBOARD
6208 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6209 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006210 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006212 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006213 finished = FALSE;
6214 }
6215# endif
6216# ifdef FEAT_MOUSE_GPM
6217 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006218 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006219# endif
6220# ifdef USE_XSMP
6221 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6222 {
6223 if (fds[xsmp_idx].revents & POLLIN)
6224 {
6225 busy = TRUE;
6226 xsmp_handle_requests();
6227 busy = FALSE;
6228 }
6229 else if (fds[xsmp_idx].revents & POLLHUP)
6230 {
6231 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006232 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006233 xsmp_close();
6234 }
6235 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006236 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237 }
6238# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006239#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006240 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006241 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006242 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006243#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244
Bram Moolenaar0f873732019-12-05 20:28:46 +01006245#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246
6247 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006248 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006249 // These are static because they can take 8 Kbyte each and cause the
6250 // signal stack to run out with -O3.
6251 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006252 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006253 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006255# ifdef FEAT_MZSCHEME
6256 mzvim_check_threads();
6257 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6258 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006259 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006260 mzquantum_used = TRUE;
6261 }
6262# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006263
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006264 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006265 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006266 tv.tv_sec = towait / 1000;
6267 tv.tv_usec = (towait % 1000) * (1000000/1000);
6268 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006269 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006270 else
6271 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272
6273 /*
6274 * Select on ready for reading and exceptional condition (end of file).
6275 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006276select_eintr:
6277 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006278 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006279 FD_ZERO(&efds);
6280 FD_SET(fd, &rfds);
6281# if !defined(__QNX__) && !defined(__CYGWIN32__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006282 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006283 FD_SET(fd, &efds);
6284# endif
6285 maxfd = fd;
6286
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006288 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289 if (xterm_Shell != (Widget)0)
6290 {
6291 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6292 if (maxfd < ConnectionNumber(xterm_dpy))
6293 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006294
Bram Moolenaar0f873732019-12-05 20:28:46 +01006295 // An event may have already been read but not handled. In
6296 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006297 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298 }
6299# endif
6300# ifdef FEAT_MOUSE_GPM
6301 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6302 {
6303 FD_SET(gpm_fd, &rfds);
6304 FD_SET(gpm_fd, &efds);
6305 if (maxfd < gpm_fd)
6306 maxfd = gpm_fd;
6307 }
6308# endif
6309# ifdef USE_XSMP
6310 if (xsmp_icefd != -1)
6311 {
6312 FD_SET(xsmp_icefd, &rfds);
6313 FD_SET(xsmp_icefd, &efds);
6314 if (maxfd < xsmp_icefd)
6315 maxfd = xsmp_icefd;
6316 }
6317# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006318# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006319 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006320# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006321 if (interrupted != NULL)
6322 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323
Bram Moolenaar643b6142018-09-12 20:29:09 +02006324 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6325 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006326 result = ret > 0 && FD_ISSET(fd, &rfds);
6327 if (result)
6328 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006329 else if (interrupted != NULL && ret > 0)
6330 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006331
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006332# ifdef EINTR
6333 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006334 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006335 // Check whether window has been resized, EINTR may be caused by
6336 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006337 if (do_resize)
6338 handle_resize();
6339
Bram Moolenaar0f873732019-12-05 20:28:46 +01006340 // Interrupted by a signal, need to try again. We ignore msec
6341 // here, because we do want to check even after a timeout if
6342 // characters are available. Needed for reading output of an
6343 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006344 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006345 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006346# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006347# ifdef __TANDEM
6348 if (ret == -1 && errno == ENOTSUP)
6349 {
6350 FD_ZERO(&rfds);
6351 FD_ZERO(&efds);
6352 ret = 0;
6353 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006354# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006355# ifdef FEAT_MZSCHEME
6356 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006357 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006358 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006359# endif
6360
Bram Moolenaar071d4272004-06-13 20:20:40 +00006361# ifdef FEAT_XCLIPBOARD
6362 if (ret > 0 && xterm_Shell != (Widget)0
6363 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6364 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006365 xterm_update(); // Maybe we should hand out clipboard
6366 // continue looping when we only got the X event and the input
6367 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006368 if (--ret == 0 && !input_available())
6369 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006370 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006371 finished = FALSE;
6372 }
6373 }
6374# endif
6375# ifdef FEAT_MOUSE_GPM
6376 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6377 {
6378 if (FD_ISSET(gpm_fd, &efds))
6379 gpm_close();
6380 else if (FD_ISSET(gpm_fd, &rfds))
6381 *check_for_gpm = 1;
6382 }
6383# endif
6384# ifdef USE_XSMP
6385 if (ret > 0 && xsmp_icefd != -1)
6386 {
6387 if (FD_ISSET(xsmp_icefd, &efds))
6388 {
6389 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006390 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006391 xsmp_close();
6392 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006393 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006394 }
6395 else if (FD_ISSET(xsmp_icefd, &rfds))
6396 {
6397 busy = TRUE;
6398 xsmp_handle_requests();
6399 busy = FALSE;
6400 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006401 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006402 }
6403 }
6404# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006405#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006406 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006407 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006408 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006409#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006410
Bram Moolenaar0f873732019-12-05 20:28:46 +01006411#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006412
6413#ifdef MAY_LOOP
6414 if (finished || msec == 0)
6415 break;
6416
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006417# ifdef FEAT_CLIENTSERVER
6418 if (server_waiting())
6419 break;
6420# endif
6421
Bram Moolenaar0f873732019-12-05 20:28:46 +01006422 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423 if (msec > 0)
6424 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006425# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006426 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006427 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006428# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006429 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006430 msec = msec / 2;
6431# endif
6432 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006433 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006434 }
6435#endif
6436 }
6437
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006438 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439}
6440
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006442 * Expand a path into all matching files and/or directories. Handles "*",
6443 * "?", "[a-z]", "**", etc.
6444 * "path" has backslashes before chars that are not to be expanded.
6445 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006446 */
6447 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006448mch_expandpath(
6449 garray_T *gap,
6450 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006451 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006452{
Bram Moolenaar02743632005-07-25 20:42:36 +00006453 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006454}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006455
6456/*
6457 * mch_expand_wildcards() - this code does wild-card pattern matching using
6458 * the shell
6459 *
6460 * return OK for success, FAIL for error (you may lose some memory) and put
6461 * an error message in *file.
6462 *
6463 * num_pat is number of input patterns
6464 * pat is array of pointers to input patterns
6465 * num_file is pointer to number of matched file names
6466 * file is pointer to array of pointers to matched file names
6467 */
6468
6469#ifndef SEEK_SET
6470# define SEEK_SET 0
6471#endif
6472#ifndef SEEK_END
6473# define SEEK_END 2
6474#endif
6475
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006476#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006477
Bram Moolenaar071d4272004-06-13 20:20:40 +00006478 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006479mch_expand_wildcards(
6480 int num_pat,
6481 char_u **pat,
6482 int *num_file,
6483 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006484 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006485{
6486 int i;
6487 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006488 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489 char_u *p;
6490 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006491
Bram Moolenaarc7247912008-01-13 12:54:11 +00006492 /*
6493 * This is the non-OS/2 implementation (really Unix).
6494 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006495 int j;
6496 char_u *tempname;
6497 char_u *command;
6498 FILE *fd;
6499 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006500#define STYLE_ECHO 0 // use "echo", the default
6501#define STYLE_GLOB 1 // use "glob", for csh
6502#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6503#define STYLE_PRINT 3 // use "print -N", for zsh
6504#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6505 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506 int shell_style = STYLE_ECHO;
6507 int check_spaces;
6508 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006509 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006510 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006511 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006512
Bram Moolenaar0f873732019-12-05 20:28:46 +01006513 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514 *file = NULL;
6515
6516 /*
6517 * If there are no wildcards, just copy the names to allocated memory.
6518 * Saves a lot of time, because we don't have to start a new shell.
6519 */
6520 if (!have_wildcard(num_pat, pat))
6521 return save_patterns(num_pat, pat, num_file, file);
6522
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006523# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006524 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006525 if (sandbox != 0 && check_secure())
6526 return FAIL;
6527# endif
6528
Bram Moolenaar071d4272004-06-13 20:20:40 +00006529 /*
6530 * Don't allow the use of backticks in secure and restricted mode.
6531 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006532 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 for (i = 0; i < num_pat; ++i)
6534 if (vim_strchr(pat[i], '`') != NULL
6535 && (check_restricted() || check_secure()))
6536 return FAIL;
6537
6538 /*
6539 * get a name for the temp file
6540 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006541 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006542 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006543 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006544 return FAIL;
6545 }
6546
6547 /*
6548 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006549 * file.
6550 * STYLE_BT: NL separated
6551 * If expanding `cmd` execute it directly.
6552 * STYLE_GLOB: NUL separated
6553 * If we use *csh, "glob" will work better than "echo".
6554 * STYLE_PRINT: NL or NUL separated
6555 * If we use *zsh, "print -N" will work better than "glob".
6556 * STYLE_VIMGLOB: NL separated
6557 * If we use *sh*, we define "vimglob()".
6558 * STYLE_ECHO: space separated.
6559 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560 */
6561 if (num_pat == 1 && *pat[0] == '`'
6562 && (len = STRLEN(pat[0])) > 2
6563 && *(pat[0] + len - 1) == '`')
6564 shell_style = STYLE_BT;
6565 else if ((len = STRLEN(p_sh)) >= 3)
6566 {
6567 if (STRCMP(p_sh + len - 3, "csh") == 0)
6568 shell_style = STYLE_GLOB;
6569 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6570 shell_style = STYLE_PRINT;
6571 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006572 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6573 "sh") != NULL)
6574 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006575
Bram Moolenaar0f873732019-12-05 20:28:46 +01006576 // Compute the length of the command. We need 2 extra bytes: for the
6577 // optional '&' and for the NUL.
6578 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006579 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006580 if (shell_style == STYLE_VIMGLOB)
6581 len += STRLEN(sh_vimglob_func);
6582
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006583 for (i = 0; i < num_pat; ++i)
6584 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006585 // Count the length of the patterns in the same way as they are put in
6586 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006587#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006588 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006589#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006590 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006591 for (j = 0; pat[i][j] != NUL; ++j)
6592 {
6593 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006594 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006595 ++len;
6596 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006597#endif
6598 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599 command = alloc(len);
6600 if (command == NULL)
6601 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006602 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006603 vim_free(tempname);
6604 return FAIL;
6605 }
6606
6607 /*
6608 * Build the shell command:
6609 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6610 * recognizes this).
6611 * - Add the shell command to print the expanded names.
6612 * - Add the temp file name.
6613 * - Add the file name patterns.
6614 */
6615 if (shell_style == STYLE_BT)
6616 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006617 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006618 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006619 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006620 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006621 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006622 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006623 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006624 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006625 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006626 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006627 *p = ' ';
6628 }
6629 STRCAT(command, ">");
6630 }
6631 else
6632 {
6633 if (flags & EW_NOTFOUND)
6634 STRCPY(command, "set nonomatch; ");
6635 else
6636 STRCPY(command, "unset nonomatch; ");
6637 if (shell_style == STYLE_GLOB)
6638 STRCAT(command, "glob >");
6639 else if (shell_style == STYLE_PRINT)
6640 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006641 else if (shell_style == STYLE_VIMGLOB)
6642 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006643 else
6644 STRCAT(command, "echo >");
6645 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006646
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006648
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649 if (shell_style != STYLE_BT)
6650 for (i = 0; i < num_pat; ++i)
6651 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006652 // When using system() always add extra quotes, because the shell
6653 // is started twice. Otherwise put a backslash before special
6654 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006655#ifdef USE_SYSTEM
6656 STRCAT(command, " \"");
6657 STRCAT(command, pat[i]);
6658 STRCAT(command, "\"");
6659#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006660 int intick = FALSE;
6661
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662 p = command + STRLEN(command);
6663 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006664 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006665 {
6666 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006667 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006668 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6669 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006670 // Remove a backslash, take char literally. But keep
6671 // backslash inside backticks, before a special character
6672 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006673 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006674 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6675 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006676 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006677 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006678 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006679 else if (!intick
6680 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6681 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006682 // Put a backslash before a special character, but not
6683 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6684 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006685 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006686
Bram Moolenaar0f873732019-12-05 20:28:46 +01006687 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006688 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006689 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690 *p = NUL;
6691#endif
6692 }
6693 if (flags & EW_SILENT)
6694 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006695 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006696 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006697
6698 /*
6699 * Using zsh -G: If a pattern has no matches, it is just deleted from
6700 * the argument list, otherwise zsh gives an error message and doesn't
6701 * expand any other pattern.
6702 */
6703 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006704 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006705
6706 /*
6707 * If we use -f then shell variables set in .cshrc won't get expanded.
6708 * vi can do it, so we will too, but it is only necessary if there is a "$"
6709 * in one of the patterns, otherwise we can still use the fast option.
6710 */
6711 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006712 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006713
6714 /*
6715 * execute the shell command
6716 */
6717 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6718
Bram Moolenaar0f873732019-12-05 20:28:46 +01006719 // When running in the background, give it some time to create the temp
6720 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006721 if (ampersand)
Bram Moolenaar0981c872020-08-23 14:28:37 +02006722 mch_delay(10L, MCH_DELAY_IGNOREINPUT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006723
Bram Moolenaar0f873732019-12-05 20:28:46 +01006724 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006725 show_shell_mess = TRUE;
6726 vim_free(command);
6727
Bram Moolenaar0f873732019-12-05 20:28:46 +01006728 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006729 {
6730 mch_remove(tempname);
6731 vim_free(tempname);
6732 /*
6733 * With interactive completion, the error message is not printed.
6734 * However with USE_SYSTEM, I don't know how to turn off error messages
6735 * from the shell, so screen may still get messed up -- webb.
6736 */
6737#ifndef USE_SYSTEM
6738 if (!(flags & EW_SILENT))
6739#endif
6740 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006741 redraw_later_clear(); // probably messed up screen
6742 msg_putchar('\n'); // clear bottom line quickly
6743 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744#ifdef USE_SYSTEM
6745 if (!(flags & EW_SILENT))
6746#endif
6747 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006748 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006749 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006750 }
6751 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006752 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6753 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754 if (shell_style == STYLE_BT)
6755 return FAIL;
6756 goto notfound;
6757 }
6758
6759 /*
6760 * read the names from the file into memory
6761 */
6762 fd = fopen((char *)tempname, READBIN);
6763 if (fd == NULL)
6764 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006765 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766 if (!(flags & EW_SILENT))
6767 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006768 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006769 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006770 }
6771 vim_free(tempname);
6772 goto notfound;
6773 }
6774 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006775 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006776 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006777 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006778 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006779 buffer = NULL;
6780 else
6781 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006782 if (buffer == NULL)
6783 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006784 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785 mch_remove(tempname);
6786 vim_free(tempname);
6787 fclose(fd);
6788 return FAIL;
6789 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006790 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006791 i = fread((char *)buffer, 1, len, fd);
6792 fclose(fd);
6793 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006794 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006795 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006796 // unexpected read error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006797 semsg(_(e_notread), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006798 vim_free(tempname);
6799 vim_free(buffer);
6800 return FAIL;
6801 }
6802 vim_free(tempname);
6803
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006804# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006805 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006806 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006807 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006808 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6809 *p++ = buffer[i];
6810 len = p - buffer;
6811# endif
6812
6813
Bram Moolenaar0f873732019-12-05 20:28:46 +01006814 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006815 if (shell_style == STYLE_ECHO)
6816 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006817 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006818 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006819 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006820 {
6821 while (*p != ' ' && *p != '\n')
6822 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006823 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006824 }
6825 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006826 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006827 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006828 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006829 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006830 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006831 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006832 {
6833 while (*p != '\n' && *p != NUL)
6834 ++p;
6835 if (*p != NUL)
6836 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006837 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006838 }
6839 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006840 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006841 else
6842 {
6843 /*
6844 * Some versions of zsh use spaces instead of NULs to separate
6845 * results. Only do this when there is no NUL before the end of the
6846 * buffer, otherwise we would never be able to use file names with
6847 * embedded spaces when zsh does use NULs.
6848 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6849 * don't check for spaces again.
6850 */
6851 check_spaces = FALSE;
6852 if (shell_style == STYLE_PRINT && !did_find_nul)
6853 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006854 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006855 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006856 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006857 did_find_nul = TRUE;
6858 else
6859 check_spaces = TRUE;
6860 }
6861
6862 /*
6863 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6864 * already is one, for STYLE_GLOB it needs to be added.
6865 */
6866 if (len && buffer[len - 1] == NUL)
6867 --len;
6868 else
6869 buffer[len] = NUL;
6870 i = 0;
6871 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006872 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006873 {
6874 ++i;
6875 *p = NUL;
6876 }
6877 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006878 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006879 }
6880 if (i == 0)
6881 {
6882 /*
6883 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6884 * /bin/sh will happily expand it to nothing rather than returning an
6885 * error; and hey, it's good to check anyway -- webb.
6886 */
6887 vim_free(buffer);
6888 goto notfound;
6889 }
6890 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006891 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006892 if (*file == NULL)
6893 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006894 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006895 vim_free(buffer);
6896 return FAIL;
6897 }
6898
6899 /*
6900 * Isolate the individual file names.
6901 */
6902 p = buffer;
6903 for (i = 0; i < *num_file; ++i)
6904 {
6905 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006906 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00006907 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6908 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006910 while (!(shell_style == STYLE_ECHO && *p == ' ')
6911 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006912 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006913 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006914 *p = NUL;
6915 else
6916 {
6917 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006918 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006919 }
6920 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006921 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006923 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006925 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 }
6927 }
6928
6929 /*
6930 * Move the file names to allocated memory.
6931 */
6932 for (j = 0, i = 0; i < *num_file; ++i)
6933 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006934 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00006935 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6936 continue;
6937
Bram Moolenaar0f873732019-12-05 20:28:46 +01006938 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00006939 dir = (mch_isdir((*file)[i]));
6940 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6941 continue;
6942
Bram Moolenaar0f873732019-12-05 20:28:46 +01006943 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01006944 if (!dir && (flags & EW_EXEC)
6945 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006946 continue;
6947
Bram Moolenaar964b3742019-05-24 18:54:09 +02006948 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006949 if (p)
6950 {
6951 STRCPY(p, (*file)[i]);
6952 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006953 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00006954 (*file)[j++] = p;
6955 }
6956 }
6957 vim_free(buffer);
6958 *num_file = j;
6959
Bram Moolenaar0f873732019-12-05 20:28:46 +01006960 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006962 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006963 goto notfound;
6964 }
6965
6966 return OK;
6967
6968notfound:
6969 if (flags & EW_NOTFOUND)
6970 return save_patterns(num_pat, pat, num_file, file);
6971 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006972}
6973
Bram Moolenaar0f873732019-12-05 20:28:46 +01006974#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006975
Bram Moolenaar071d4272004-06-13 20:20:40 +00006976 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006977save_patterns(
6978 int num_pat,
6979 char_u **pat,
6980 int *num_file,
6981 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006982{
6983 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006984 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006985
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006986 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006987 if (*file == NULL)
6988 return FAIL;
6989 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006990 {
6991 s = vim_strsave(pat[i]);
6992 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006993 // Be compatible with expand_filename(): halve the number of
6994 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00006995 backslash_halve(s);
6996 (*file)[i] = s;
6997 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006998 *num_file = num_pat;
6999 return OK;
7000}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007001
Bram Moolenaar071d4272004-06-13 20:20:40 +00007002/*
7003 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7004 * expand.
7005 */
7006 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007007mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007009 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007010 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007011 if (*p == '\\' && p[1] != NUL)
7012 ++p;
7013 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007014 if (vim_strchr((char_u *)
7015#ifdef VMS
7016 "*?%"
7017#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007018 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007019#endif
7020 , *p) != NULL)
7021 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007022 }
7023 return FALSE;
7024}
7025
7026/*
7027 * Return TRUE if the string "p" contains a wildcard.
7028 * Don't recognize '~' at the end as a wildcard.
7029 */
7030 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007031mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007032{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007033 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007035 if (*p == '\\' && p[1] != NUL)
7036 ++p;
7037 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038 if (vim_strchr((char_u *)
7039#ifdef VMS
7040 "*?%$"
7041#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007043#endif
7044 , *p) != NULL
7045 || (*p == '~' && p[1] != NUL))
7046 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007047 }
7048 return FALSE;
7049}
7050
Bram Moolenaar071d4272004-06-13 20:20:40 +00007051 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007052have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053{
7054 int i;
7055
7056 for (i = 0; i < num; i++)
7057 if (mch_has_wildcard(file[i]))
7058 return 1;
7059 return 0;
7060}
7061
7062 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007063have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007064{
7065 int i;
7066
7067 for (i = 0; i < num; i++)
7068 if (vim_strchr(file[i], '$') != NULL)
7069 return TRUE;
7070 return FALSE;
7071}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007072
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007073#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074/*
7075 * Scaled-down version of rename(), which is missing in Xenix.
7076 * This version can only move regular files and will fail if the
7077 * destination exists.
7078 */
7079 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007080mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007081{
7082 struct stat st;
7083
Bram Moolenaar0f873732019-12-05 20:28:46 +01007084 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007086 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007087 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007088 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089 return 0;
7090 return -1;
7091}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007092#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007093
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007094#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095/*
7096 * Initializes connection with gpm (if it isn't already opened)
7097 * Return 1 if succeeded (or connection already opened), 0 if failed
7098 */
7099 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007100gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007101{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007102 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103
7104 if (!gpm_flag)
7105 {
7106 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7107 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007108 // Default handling for mouse move
7109 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007110 gpm_connect.maxMod = 0xffff;
7111 if (Gpm_Open(&gpm_connect, 0) > 0)
7112 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007113 // gpm library tries to handling TSTP causes
7114 // problems. Anyways, we close connection to Gpm whenever
7115 // we are going to suspend or starting an external process
7116 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007117# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007118 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007119# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007120 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121 }
7122 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007123 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124 return 0;
7125 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007126 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007127}
7128
7129/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007130 * Returns TRUE if the GPM mouse is enabled.
7131 */
7132 int
7133gpm_enabled(void)
7134{
7135 return gpm_flag && gpm_fd >= 0;
7136}
7137
7138/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007139 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007140 */
7141 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007142gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007143{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007144 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 Gpm_Close();
7146}
7147
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007148/*
7149 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007150 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007151 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152 */
7153 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007154mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007155{
7156 int button;
7157 static Gpm_Event gpm_event;
7158 char_u string[6];
7159 int_u vim_modifiers;
7160 int row,col;
7161 unsigned char buttons_mask;
7162 unsigned char gpm_modifiers;
7163 static unsigned char old_buttons = 0;
7164
7165 Gpm_GetEvent(&gpm_event);
7166
7167#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007168 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007169 if (hold_gui_events)
7170 return 0;
7171#endif
7172
7173 row = gpm_event.y - 1;
7174 col = gpm_event.x - 1;
7175
Bram Moolenaar0f873732019-12-05 20:28:46 +01007176 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007177 string[1] = 'M';
7178 string[2] = 'G';
7179 switch (GPM_BARE_EVENTS(gpm_event.type))
7180 {
7181 case GPM_DRAG:
7182 string[3] = MOUSE_DRAG;
7183 break;
7184 case GPM_DOWN:
7185 buttons_mask = gpm_event.buttons & ~old_buttons;
7186 old_buttons = gpm_event.buttons;
7187 switch (buttons_mask)
7188 {
7189 case GPM_B_LEFT:
7190 button = MOUSE_LEFT;
7191 break;
7192 case GPM_B_MIDDLE:
7193 button = MOUSE_MIDDLE;
7194 break;
7195 case GPM_B_RIGHT:
7196 button = MOUSE_RIGHT;
7197 break;
7198 default:
7199 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007200 // Don't know what to do. Can more than one button be
7201 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007202 }
7203 string[3] = (char_u)(button | 0x20);
7204 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7205 break;
7206 case GPM_UP:
7207 string[3] = MOUSE_RELEASE;
7208 old_buttons &= ~gpm_event.buttons;
7209 break;
7210 default:
7211 return 0;
7212 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007213 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007214 gpm_modifiers = gpm_event.modifiers;
7215 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007216 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7217 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7218 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007219 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7220 vim_modifiers |= MOUSE_SHIFT;
7221
7222 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7223 vim_modifiers |= MOUSE_CTRL;
7224 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7225 vim_modifiers |= MOUSE_ALT;
7226 string[3] |= vim_modifiers;
7227 string[4] = (char_u)(col + ' ' + 1);
7228 string[5] = (char_u)(row + ' ' + 1);
7229 add_to_input_buf(string, 6);
7230 return 6;
7231}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007232#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007233
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007234#ifdef FEAT_SYSMOUSE
7235/*
7236 * Initialize connection with sysmouse.
7237 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7238 * output, any sysmouse output than will be processed via sig_sysmouse().
7239 * Return OK if succeeded, FAIL if failed.
7240 */
7241 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007242sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007243{
7244 struct mouse_info mouse;
7245
7246 mouse.operation = MOUSE_MODE;
7247 mouse.u.mode.mode = 0;
7248 mouse.u.mode.signal = SIGUSR2;
7249 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7250 {
7251 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7252 mouse.operation = MOUSE_SHOW;
7253 ioctl(1, CONS_MOUSECTL, &mouse);
7254 return OK;
7255 }
7256 return FAIL;
7257}
7258
7259/*
7260 * Stop processing SIGUSR2 signals, and also make sure that
7261 * virtual console do not send us any sysmouse related signal.
7262 */
7263 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007264sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007265{
7266 struct mouse_info mouse;
7267
7268 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7269 mouse.operation = MOUSE_MODE;
7270 mouse.u.mode.mode = 0;
7271 mouse.u.mode.signal = 0;
7272 ioctl(1, CONS_MOUSECTL, &mouse);
7273}
7274
7275/*
7276 * Gets info from sysmouse and adds special keys to input buf.
7277 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007278 static RETSIGTYPE
7279sig_sysmouse SIGDEFARG(sigarg)
7280{
7281 struct mouse_info mouse;
7282 struct video_info video;
7283 char_u string[6];
7284 int row, col;
7285 int button;
7286 int buttons;
7287 static int oldbuttons = 0;
7288
7289#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007290 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007291 if (hold_gui_events)
7292 return;
7293#endif
7294
7295 mouse.operation = MOUSE_GETINFO;
7296 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7297 && ioctl(1, FBIO_MODEINFO, &video) != -1
7298 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7299 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7300 {
7301 row = mouse.u.data.y / video.vi_cheight;
7302 col = mouse.u.data.x / video.vi_cwidth;
7303 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007304 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007305 string[1] = 'M';
7306 string[2] = 'S';
7307 if (oldbuttons == buttons && buttons != 0)
7308 {
7309 button = MOUSE_DRAG;
7310 }
7311 else
7312 {
7313 switch (buttons)
7314 {
7315 case 0:
7316 button = MOUSE_RELEASE;
7317 break;
7318 case 1:
7319 button = MOUSE_LEFT;
7320 break;
7321 case 2:
7322 button = MOUSE_MIDDLE;
7323 break;
7324 case 4:
7325 button = MOUSE_RIGHT;
7326 break;
7327 default:
7328 return;
7329 }
7330 oldbuttons = buttons;
7331 }
7332 string[3] = (char_u)(button);
7333 string[4] = (char_u)(col + ' ' + 1);
7334 string[5] = (char_u)(row + ' ' + 1);
7335 add_to_input_buf(string, 6);
7336 }
7337 return;
7338}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007339#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007340
Bram Moolenaar071d4272004-06-13 20:20:40 +00007341#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007342typedef char_u * (*STRPROCSTR)(char_u *);
7343typedef char_u * (*INTPROCSTR)(int);
7344typedef int (*STRPROCINT)(char_u *);
7345typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007346
7347/*
7348 * Call a DLL routine which takes either a string or int param
7349 * and returns an allocated string.
7350 */
7351 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007352mch_libcall(
7353 char_u *libname,
7354 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007355 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007356 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007357 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007358 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007359{
7360# if defined(USE_DLOPEN)
7361 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007362 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007363# else
7364 shl_t hinstLib;
7365# endif
7366 STRPROCSTR ProcAdd;
7367 INTPROCSTR ProcAddI;
7368 char_u *retval_str = NULL;
7369 int retval_int = 0;
7370 int success = FALSE;
7371
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007372 /*
7373 * Get a handle to the DLL module.
7374 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007375# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007376 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007377 (void)dlerror();
7378
Bram Moolenaar071d4272004-06-13 20:20:40 +00007379 hinstLib = dlopen((char *)libname, RTLD_LAZY
7380# ifdef RTLD_LOCAL
7381 | RTLD_LOCAL
7382# endif
7383 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007384 if (hinstLib == NULL)
7385 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007386 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007387 dlerr = (char *)dlerror();
7388 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007389 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007391# else
7392 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7393# endif
7394
Bram Moolenaar0f873732019-12-05 20:28:46 +01007395 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007396 if (hinstLib != NULL)
7397 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007398# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007399 /*
7400 * Catch a crash when calling the library function. For example when
7401 * using a number where a string pointer is expected.
7402 */
7403 mch_startjmp();
7404 if (SETJMP(lc_jump_env) != 0)
7405 {
7406 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007407# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007408 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007409# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007410 mch_didjmp();
7411 }
7412 else
7413# endif
7414 {
7415 retval_str = NULL;
7416 retval_int = 0;
7417
7418 if (argstring != NULL)
7419 {
7420# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007421 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007422 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423# else
7424 if (shl_findsym(&hinstLib, (const char *)funcname,
7425 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7426 ProcAdd = NULL;
7427# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007428 if ((success = (ProcAdd != NULL
7429# if defined(USE_DLOPEN)
7430 && dlerr == NULL
7431# endif
7432 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007433 {
7434 if (string_result == NULL)
7435 retval_int = ((STRPROCINT)ProcAdd)(argstring);
7436 else
7437 retval_str = (ProcAdd)(argstring);
7438 }
7439 }
7440 else
7441 {
7442# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007443 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007444 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007445# else
7446 if (shl_findsym(&hinstLib, (const char *)funcname,
7447 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7448 ProcAddI = NULL;
7449# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007450 if ((success = (ProcAddI != NULL
7451# if defined(USE_DLOPEN)
7452 && dlerr == NULL
7453# endif
7454 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007455 {
7456 if (string_result == NULL)
7457 retval_int = ((INTPROCINT)ProcAddI)(argint);
7458 else
7459 retval_str = (ProcAddI)(argint);
7460 }
7461 }
7462
Bram Moolenaar0f873732019-12-05 20:28:46 +01007463 // Save the string before we free the library.
7464 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007465 if (string_result == NULL)
7466 *number_result = retval_int;
7467 else if (retval_str != NULL
7468 && retval_str != (char_u *)1
7469 && retval_str != (char_u *)-1)
7470 *string_result = vim_strsave(retval_str);
7471 }
7472
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007473# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007474 mch_endjmp();
7475# ifdef SIGHASARG
7476 if (lc_signal != 0)
7477 {
7478 int i;
7479
Bram Moolenaar0f873732019-12-05 20:28:46 +01007480 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007481 for (i = 0; signal_info[i].sig != -1; i++)
7482 if (lc_signal == signal_info[i].sig)
7483 break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007484 semsg("E368: got SIG%s in libcall()", signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007485 }
7486# endif
7487# endif
7488
Bram Moolenaar071d4272004-06-13 20:20:40 +00007489# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007490 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007491 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007492 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007493
Bram Moolenaar0f873732019-12-05 20:28:46 +01007494 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007495 (void)dlclose(hinstLib);
7496# else
7497 (void)shl_unload(hinstLib);
7498# endif
7499 }
7500
7501 if (!success)
7502 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007503 semsg(_(e_libcall), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007504 return FAIL;
7505 }
7506
7507 return OK;
7508}
7509#endif
7510
7511#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007512static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007513static int xterm_button;
7514
7515/*
7516 * Setup a dummy window for X selections in a terminal.
7517 */
7518 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007519setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007520{
7521 int z = 0;
7522 char *strp = "";
7523 Widget AppShell;
7524
7525 if (!x_connect_to_server())
7526 return;
7527
7528 open_app_context();
7529 if (app_context != NULL && xterm_Shell == (Widget)0)
7530 {
7531 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007532# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007533 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007534# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007535# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007536 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007537
7538 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007539 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007540# endif
7541
Bram Moolenaar0f873732019-12-05 20:28:46 +01007542 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007543 oldhandler = XSetErrorHandler(x_error_check);
7544
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007545# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007546 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7548 mch_startjmp();
7549 if (SETJMP(lc_jump_env) != 0)
7550 {
7551 mch_didjmp();
7552 xterm_dpy = NULL;
7553 }
7554 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007555# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007556 {
7557 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7558 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007559 if (xterm_dpy != NULL)
7560 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007561# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007562 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007563# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564 }
7565
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007566# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007567 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007568 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007569# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007570 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007571 (void)XSetErrorHandler(oldhandler);
7572
7573 if (xterm_dpy == NULL)
7574 {
7575 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007576 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007577 return;
7578 }
7579
Bram Moolenaar0f873732019-12-05 20:28:46 +01007580 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007581 (void)XSetIOErrorHandler(x_IOerror_handler);
7582
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007583# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007584 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007585 {
7586 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007587 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007588 verbose_leave();
7589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007590# endif
7591
Bram Moolenaar0f873732019-12-05 20:28:46 +01007592 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007593 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7594 applicationShellWidgetClass, xterm_dpy,
7595 NULL);
7596 if (AppShell == (Widget)0)
7597 return;
7598 xterm_Shell = XtVaCreatePopupShell("VIM",
7599 topLevelShellWidgetClass, AppShell,
7600 XtNmappedWhenManaged, 0,
7601 XtNwidth, 1,
7602 XtNheight, 1,
7603 NULL);
7604 if (xterm_Shell == (Widget)0)
7605 return;
7606
7607 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007608 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007609 if (x11_display == NULL)
7610 x11_display = xterm_dpy;
7611
7612 XtRealizeWidget(xterm_Shell);
7613 XSync(xterm_dpy, False);
7614 xterm_update();
7615 }
7616 if (xterm_Shell != (Widget)0)
7617 {
7618 clip_init(TRUE);
7619 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7620 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007621 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007622 if (test_x11_window(xterm_dpy) == FAIL)
7623 x11_window = 0;
7624 if (x11_window != 0)
7625 xterm_trace = 0;
7626 }
7627}
7628
7629 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007630start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007631{
7632 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7633 return;
7634 xterm_trace = 1;
7635 xterm_button = button;
7636 do_xterm_trace();
7637}
7638
7639
7640 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007641stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007642{
7643 if (xterm_trace < 0)
7644 return;
7645 xterm_trace = 0;
7646}
7647
7648/*
7649 * Query the xterm pointer and generate mouse termcodes if necessary
7650 * return TRUE if dragging is active, else FALSE
7651 */
7652 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007653do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007654{
7655 Window root, child;
7656 int root_x, root_y;
7657 int win_x, win_y;
7658 int row, col;
7659 int_u mask_return;
7660 char_u buf[50];
7661 char_u *strp;
7662 long got_hints;
7663 static char_u *mouse_code;
7664 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7665 static int prev_row = 0, prev_col = 0;
7666 static XSizeHints xterm_hints;
7667
7668 if (xterm_trace <= 0)
7669 return FALSE;
7670
7671 if (xterm_trace == 1)
7672 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007673 // Get the hints just before tracking starts. The font size might
7674 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007675 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7676 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007677 || xterm_hints.width_inc <= 1
7678 || xterm_hints.height_inc <= 1)
7679 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007680 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007681 return FALSE;
7682 }
7683
Bram Moolenaar0f873732019-12-05 20:28:46 +01007684 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007685 mouse_code = find_termcode(mouse_name);
7686 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007687 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007688 xterm_trace = 2;
7689
Bram Moolenaar0f873732019-12-05 20:28:46 +01007690 // Find the offset of the chars, there might be a scrollbar on the
7691 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007692 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7693 &win_x, &win_y, &mask_return);
7694 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7695 - (xterm_hints.height_inc / 2);
7696 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7697 xterm_hints.y = 2;
7698 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7699 - (xterm_hints.width_inc / 2);
7700 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7701 xterm_hints.x = 2;
7702 return TRUE;
7703 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007704 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007705 {
7706 xterm_trace = 0;
7707 return FALSE;
7708 }
7709
7710 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7711 &win_x, &win_y, &mask_return);
7712
7713 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7714 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7715 if (row == prev_row && col == prev_col)
7716 return TRUE;
7717
7718 STRCPY(buf, mouse_code);
7719 strp = buf + STRLEN(buf);
7720 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7721 *strp++ = (char_u)(col + ' ' + 1);
7722 *strp++ = (char_u)(row + ' ' + 1);
7723 *strp = 0;
7724 add_to_input_buf(buf, STRLEN(buf));
7725
7726 prev_row = row;
7727 prev_col = col;
7728 return TRUE;
7729}
7730
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007731# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007732/*
7733 * Destroy the display, window and app_context. Required for GTK.
7734 */
7735 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007736clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007737{
7738 if (xterm_Shell != (Widget)0)
7739 {
7740 XtDestroyWidget(xterm_Shell);
7741 xterm_Shell = (Widget)0;
7742 }
7743 if (xterm_dpy != NULL)
7744 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007745# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007746 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007747 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007748# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007749 if (x11_display == xterm_dpy)
7750 x11_display = NULL;
7751 xterm_dpy = NULL;
7752 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007753# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007754 if (app_context != (XtAppContext)NULL)
7755 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007756 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007757 XtDestroyApplicationContext(app_context);
7758 app_context = (XtAppContext)NULL;
7759 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007760# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007761}
7762# endif
7763
7764/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007765 * Catch up with GUI or X events.
7766 */
7767 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007768clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007769{
7770# ifdef FEAT_GUI
7771 if (gui.in_use)
7772 gui_mch_update();
7773 else
7774# endif
7775 if (xterm_Shell != (Widget)0)
7776 xterm_update();
7777}
7778
7779/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007780 * Catch up with any queued X events. This may put keyboard input into the
7781 * input buffer, call resize call-backs, trigger timers etc. If there is
7782 * nothing in the X event queue (& no timers pending), then we return
7783 * immediately.
7784 */
7785 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007786xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007787{
7788 XEvent event;
7789
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007790 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007791 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007792 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007793
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007794 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007795 break;
7796
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007797 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007799 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007800 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007801#ifdef FEAT_CLIENTSERVER
7802 {
7803 XPropertyEvent *e = (XPropertyEvent *)&event;
7804
7805 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007806 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007807 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007809#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007810 XtDispatchEvent(&event);
7811 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007812 else
7813 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007814 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007815 XtAppProcessEvent(app_context, mask);
7816 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007817 }
7818}
7819
7820 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007821clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007822{
7823 if (xterm_Shell != (Widget)0)
7824 return clip_x11_own_selection(xterm_Shell, cbd);
7825 return FAIL;
7826}
7827
7828 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007829clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007830{
7831 if (xterm_Shell != (Widget)0)
7832 clip_x11_lose_selection(xterm_Shell, cbd);
7833}
7834
7835 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007836clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007837{
7838 if (xterm_Shell != (Widget)0)
7839 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7840}
7841
7842 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007843clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007844{
7845 clip_x11_set_selection(cbd);
7846}
7847#endif
7848
7849
7850#if defined(USE_XSMP) || defined(PROTO)
7851/*
7852 * Code for X Session Management Protocol.
7853 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007854
7855# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007856/*
7857 * This is our chance to ask the user if they want to save,
7858 * or abort the logout
7859 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007860 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007861xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007862{
7863 cmdmod_T save_cmdmod;
7864 int cancel_shutdown = False;
7865
7866 save_cmdmod = cmdmod;
7867 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007868 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01007869 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00007870 cancel_shutdown = True;
7871 cmdmod = save_cmdmod;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007872 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00007873 out_flush();
7874
Bram Moolenaar0f873732019-12-05 20:28:46 +01007875 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00007876 SmcInteractDone(smc_conn, cancel_shutdown);
7877
Bram Moolenaar0f873732019-12-05 20:28:46 +01007878 // Finish off
7879 // Only end save-yourself here if we're not cancelling shutdown;
7880 // we'll get a cancelled callback later in which we'll end it.
7881 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007882 if (!cancel_shutdown)
7883 {
7884 xsmp.save_yourself = False;
7885 SmcSaveYourselfDone(smc_conn, True);
7886 }
7887}
7888# endif
7889
7890/*
7891 * Callback that starts save-yourself.
7892 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007893 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007894xsmp_handle_save_yourself(
7895 SmcConn smc_conn,
7896 SmPointer client_data UNUSED,
7897 int save_type UNUSED,
7898 Bool shutdown,
7899 int interact_style UNUSED,
7900 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007901{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007902 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00007903 if (xsmp.save_yourself)
7904 SmcSaveYourselfDone(smc_conn, True);
7905 xsmp.save_yourself = True;
7906 xsmp.shutdown = shutdown;
7907
Bram Moolenaar0f873732019-12-05 20:28:46 +01007908 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007909 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01007910 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007911
7912 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007913 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007914
7915# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007916 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007917 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007918 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00007919 SmcInteractRequest(smc_conn, SmDialogError,
7920 xsmp_handle_interaction, client_data);
7921 else
7922# endif
7923 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007924 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00007925 SmcSaveYourselfDone(smc_conn, True);
7926 xsmp.save_yourself = False;
7927 }
7928}
7929
7930
7931/*
7932 * Callback to warn us of imminent death.
7933 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007934 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007935xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936{
7937 xsmp_close();
7938
Bram Moolenaar0f873732019-12-05 20:28:46 +01007939 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00007940 getout_preserve_modified(0);
7941}
7942
7943
7944/*
7945 * Callback to tell us that save-yourself has completed.
7946 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007947 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007948xsmp_save_complete(
7949 SmcConn smc_conn UNUSED,
7950 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007951{
7952 xsmp.save_yourself = False;
7953}
7954
7955
7956/*
7957 * Callback to tell us that an instigated shutdown was cancelled
7958 * (maybe even by us)
7959 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007960 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007961xsmp_shutdown_cancelled(
7962 SmcConn smc_conn,
7963 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007964{
7965 if (xsmp.save_yourself)
7966 SmcSaveYourselfDone(smc_conn, True);
7967 xsmp.save_yourself = False;
7968 xsmp.shutdown = False;
7969}
7970
7971
7972/*
7973 * Callback to tell us that a new ICE connection has been established.
7974 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007975 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007976xsmp_ice_connection(
7977 IceConn iceConn,
7978 IcePointer clientData UNUSED,
7979 Bool opening,
7980 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007981{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007982 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00007983 if (opening)
7984 {
7985 xsmp_icefd = IceConnectionNumber(iceConn);
7986 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7987 }
7988}
7989
7990
Bram Moolenaar0f873732019-12-05 20:28:46 +01007991// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00007992 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007993xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007994{
7995 Bool rep;
7996
7997 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7998 == IceProcessMessagesIOError)
7999 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008000 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00008001 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008002 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008003 xsmp_close();
8004 return FAIL;
8005 }
8006 else
8007 return OK;
8008}
8009
8010static int dummy;
8011
Bram Moolenaar0f873732019-12-05 20:28:46 +01008012// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00008013 void
8014xsmp_init(void)
8015{
8016 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008017 SmcCallbacks smcallbacks;
8018#if 0
8019 SmPropValue smname;
8020 SmProp smnameprop;
8021 SmProp *smprops[1];
8022#endif
8023
8024 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008025 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008026
8027 xsmp.save_yourself = xsmp.shutdown = False;
8028
Bram Moolenaar0f873732019-12-05 20:28:46 +01008029 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008030 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8031 smcallbacks.save_yourself.client_data = NULL;
8032 smcallbacks.die.callback = xsmp_die;
8033 smcallbacks.die.client_data = NULL;
8034 smcallbacks.save_complete.callback = xsmp_save_complete;
8035 smcallbacks.save_complete.client_data = NULL;
8036 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8037 smcallbacks.shutdown_cancelled.client_data = NULL;
8038
Bram Moolenaar0f873732019-12-05 20:28:46 +01008039 // Set up a watch on ICE connection creations. The "dummy" argument is
8040 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008041 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8042 {
8043 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008044 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008045 return;
8046 }
8047
Bram Moolenaar0f873732019-12-05 20:28:46 +01008048 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008049 xsmp.smcconn = SmcOpenConnection(
8050 NULL,
8051 NULL,
8052 SmProtoMajor,
8053 SmProtoMinor,
8054 SmcSaveYourselfProcMask | SmcDieProcMask
8055 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8056 &smcallbacks,
8057 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008058 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008059 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008060 errorstring);
8061 if (xsmp.smcconn == NULL)
8062 {
8063 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00008064
Bram Moolenaar071d4272004-06-13 20:20:40 +00008065 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008066 {
8067 vim_snprintf(errorreport, sizeof(errorreport),
8068 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008069 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008070 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008071 return;
8072 }
8073 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8074
8075#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008076 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008077 smname.value = "vim";
8078 smname.length = 3;
8079 smnameprop.name = "SmProgram";
8080 smnameprop.type = "SmARRAY8";
8081 smnameprop.num_vals = 1;
8082 smnameprop.vals = &smname;
8083
8084 smprops[0] = &smnameprop;
8085 SmcSetProperties(xsmp.smcconn, 1, smprops);
8086#endif
8087}
8088
8089
Bram Moolenaar0f873732019-12-05 20:28:46 +01008090// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008091 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008092xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008093{
8094 if (xsmp_icefd != -1)
8095 {
8096 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008097 if (xsmp.clientid != NULL)
8098 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008099 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008100 xsmp_icefd = -1;
8101 }
8102}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008103#endif // USE_XSMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008104
8105
8106#ifdef EBCDIC
Bram Moolenaar0f873732019-12-05 20:28:46 +01008107// Translate character to its CTRL- value
Bram Moolenaar071d4272004-06-13 20:20:40 +00008108char CtrlTable[] =
8109{
8110/* 00 - 5E */
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, 0,
8114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8117/* ^ */ 0x1E,
8118/* - */ 0x1F,
8119/* 61 - 6C */
8120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8121/* _ */ 0x1F,
8122/* 6E - 80 */
8123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8124/* a */ 0x01,
8125/* b */ 0x02,
8126/* c */ 0x03,
8127/* d */ 0x37,
8128/* e */ 0x2D,
8129/* f */ 0x2E,
8130/* g */ 0x2F,
8131/* h */ 0x16,
8132/* i */ 0x05,
8133/* 8A - 90 */
8134 0, 0, 0, 0, 0, 0, 0,
8135/* j */ 0x15,
8136/* k */ 0x0B,
8137/* l */ 0x0C,
8138/* m */ 0x0D,
8139/* n */ 0x0E,
8140/* o */ 0x0F,
8141/* p */ 0x10,
8142/* q */ 0x11,
8143/* r */ 0x12,
8144/* 9A - A1 */
8145 0, 0, 0, 0, 0, 0, 0, 0,
8146/* s */ 0x13,
8147/* t */ 0x3C,
8148/* u */ 0x3D,
8149/* v */ 0x32,
8150/* w */ 0x26,
8151/* x */ 0x18,
8152/* y */ 0x19,
8153/* z */ 0x3F,
8154/* AA - AC */
8155 0, 0, 0,
8156/* [ */ 0x27,
8157/* AE - BC */
8158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8159/* ] */ 0x1D,
8160/* BE - C0 */ 0, 0, 0,
8161/* A */ 0x01,
8162/* B */ 0x02,
8163/* C */ 0x03,
8164/* D */ 0x37,
8165/* E */ 0x2D,
8166/* F */ 0x2E,
8167/* G */ 0x2F,
8168/* H */ 0x16,
8169/* I */ 0x05,
8170/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8171/* J */ 0x15,
8172/* K */ 0x0B,
8173/* L */ 0x0C,
8174/* M */ 0x0D,
8175/* N */ 0x0E,
8176/* O */ 0x0F,
8177/* P */ 0x10,
8178/* Q */ 0x11,
8179/* R */ 0x12,
8180/* DA - DF */ 0, 0, 0, 0, 0, 0,
8181/* \ */ 0x1C,
8182/* E1 */ 0,
8183/* S */ 0x13,
8184/* T */ 0x3C,
8185/* U */ 0x3D,
8186/* V */ 0x32,
8187/* W */ 0x26,
8188/* X */ 0x18,
8189/* Y */ 0x19,
8190/* Z */ 0x3F,
8191/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8193};
8194
8195char MetaCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008196{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008197 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8198 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8199 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8200 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8201};
8202
8203
Bram Moolenaar0f873732019-12-05 20:28:46 +01008204// TODO: Use characters NOT numbers!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +00008205char CtrlCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008206{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008207 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8208 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8209 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8210 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8211};
8212
8213
8214#endif