blob: 6f7a9a4cf910f655cbf51f4b0306be039cef6aee [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 Moolenaar76603ba2020-08-30 17:24:37 +02004686 {
4687 ch_log(NULL, "closing channel log in the child process");
Bram Moolenaar819524702018-02-27 19:10:00 +01004688 ch_logfile((char_u *)"", (char_u *)"");
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004689 }
Bram Moolenaar819524702018-02-27 19:10:00 +01004690# endif
4691
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 if (!show_shell_mess || (options & SHELL_EXPAND))
4693 {
4694 int fd;
4695
4696 /*
4697 * Don't want to show any message from the shell. Can't just
4698 * close stdout and stderr though, because some systems will
4699 * break if you try to write to them after that, so we must
4700 * use dup() to replace them with something else -- webb
4701 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4702 * waiting for input.
4703 */
4704 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4705 fclose(stdin);
4706 fclose(stdout);
4707 fclose(stderr);
4708
4709 /*
4710 * If any of these open()'s and dup()'s fail, we just continue
4711 * anyway. It's not fatal, and on most systems it will make
4712 * no difference at all. On a few it will cause the execvp()
4713 * to exit with a non-zero status even when the completion
4714 * could be done, which is nothing too serious. If the open()
4715 * or dup() failed we'd just do the same thing ourselves
4716 * anyway -- webb
4717 */
4718 if (fd >= 0)
4719 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004720 vim_ignored = dup(fd); // To replace stdin (fd 0)
4721 vim_ignored = dup(fd); // To replace stdout (fd 1)
4722 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723
Bram Moolenaar0f873732019-12-05 20:28:46 +01004724 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725 close(fd);
4726 }
4727 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004728 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004730 || gui.in_use
4731# endif
4732 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733 {
4734
Bram Moolenaardf177f62005-02-22 08:39:57 +00004735# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01004736 // Create our own process group, so that the child and all its
4737 // children can be kill()ed. Don't do this when using pipes,
4738 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004739 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004740 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004741 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004742# if defined(SIGHUP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004743 // When doing "!xterm&" and 'shell' is bash: the shell
4744 // will exit and send SIGHUP to all processes in its
4745 // group, killing the just started process. Ignore SIGHUP
4746 // to avoid that. (suggested by Simon Schubert)
Bram Moolenaar07256082009-02-04 13:19:42 +00004747 signal(SIGHUP, SIG_IGN);
4748# endif
4749 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004750# endif
4751# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004752 if (pty_slave_fd >= 0)
4753 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004754 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004755 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004756 setup_slavepty(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01004758 // Try to become controlling tty (probably doesn't work,
4759 // unless run by root)
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004760 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004762 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004763# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004764 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765
Bram Moolenaara5792f52005-11-23 21:25:05 +00004766 /*
4767 * stderr is only redirected when using the GUI, so that a
4768 * program like gpg can still access the terminal to get a
4769 * passphrase using stderr.
4770 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004771# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 if (pty_master_fd >= 0)
4773 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004774 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775
Bram Moolenaar0f873732019-12-05 20:28:46 +01004776 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004778 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004780 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004781 if (gui.in_use)
4782 {
4783 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004784 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004785 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786
Bram Moolenaar0f873732019-12-05 20:28:46 +01004787 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788 }
4789 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004790# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004792 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793 close(fd_toshell[1]);
4794 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004795 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796 close(fd_toshell[0]);
4797
Bram Moolenaar0f873732019-12-05 20:28:46 +01004798 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 close(fd_fromshell[0]);
4800 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004801 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004802 close(fd_fromshell[1]);
4803
Bram Moolenaara5792f52005-11-23 21:25:05 +00004804# ifdef FEAT_GUI
4805 if (gui.in_use)
4806 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004807 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004808 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004809 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004810 }
4811# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004812 }
4813 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004814
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 /*
4816 * There is no type cast for the argv, because the type may be
4817 * different on different machines. This may cause a warning
4818 * message with strict compilers, don't worry about it.
4819 * Call _exit() instead of exit() to avoid closing the connection
4820 * to the X server (esp. with GTK, which uses atexit()).
4821 */
4822 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004823 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004825 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 {
4827 /*
4828 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004829 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830 */
4831 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004832 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004833 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004834# ifdef FEAT_JOB_CHANNEL
4835 ++dont_check_job_ended;
4836# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 /*
4838 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004839 * This is also used to pipe stdin/stdout to/from the external
4840 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004841 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004842 if ((options & (SHELL_READ|SHELL_WRITE))
4843# ifdef FEAT_GUI
4844 || (gui.in_use && show_shell_mess)
4845# endif
4846 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004847 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004848# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004850 int buffer_off = 0; // valid bytes in buffer[]
4851 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4852 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 int len;
4854 int p_more_save;
4855 int old_State;
4856 int c;
4857 int toshell_fd;
4858 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004859 garray_T ga;
4860 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004861# ifdef ELAPSED_FUNC
4862 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004863# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004864
Bram Moolenaardf177f62005-02-22 08:39:57 +00004865# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 if (pty_master_fd >= 0)
4867 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 fromshell_fd = pty_master_fd;
4869 toshell_fd = dup(pty_master_fd);
4870 }
4871 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004872# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 {
4874 close(fd_toshell[0]);
4875 close(fd_fromshell[1]);
4876 toshell_fd = fd_toshell[1];
4877 fromshell_fd = fd_fromshell[0];
4878 }
4879
4880 /*
4881 * Write to the child if there are typed characters.
4882 * Read from the child if there are characters available.
4883 * Repeat the reading a few times if more characters are
4884 * available. Need to check for typed keys now and then, but
4885 * not too often (delays when no chars are available).
4886 * This loop is quit if no characters can be read from the pty
4887 * (WaitForChar detected special condition), or there are no
4888 * characters available and the child has exited.
4889 * Only check if the child has exited when there is no more
4890 * output. The child may exit before all the output has
4891 * been printed.
4892 *
4893 * Currently this busy loops!
4894 * This can probably dead-lock when the write blocks!
4895 */
4896 p_more_save = p_more;
4897 p_more = FALSE;
4898 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004899 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004901 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004902 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004903 // Fork a process that will write the lines to the
4904 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004905 if ((wpid = fork()) == -1)
4906 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004907 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004908 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004909 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004910 {
4911 linenr_T lnum = curbuf->b_op_start.lnum;
4912 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004913 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004914 size_t l;
4915
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004916 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004917 for (;;)
4918 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004919 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004920 if (l == 0)
4921 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004922 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004923 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00004924 len = write(toshell_fd, "", (size_t)1);
4925 else
4926 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004927 char_u *s = vim_strchr(lp + written, NL);
4928
Bram Moolenaar89d40322006-08-29 15:30:07 +00004929 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004930 s == NULL ? l
4931 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004932 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004933 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004934 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004935 // Finished a line, add a NL, unless this line
4936 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004937 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004938 || (!curbuf->b_p_bin
4939 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004940 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004941 && (lnum !=
4942 curbuf->b_ml.ml_line_count
4943 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02004944 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004945 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004946 ++lnum;
4947 if (lnum > curbuf->b_op_end.lnum)
4948 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004949 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00004950 close(toshell_fd);
4951 toshell_fd = -1;
4952 break;
4953 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004954 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004955 written = 0;
4956 }
4957 else if (len > 0)
4958 written += len;
4959 }
4960 _exit(0);
4961 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004962 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00004963 {
4964 close(toshell_fd);
4965 toshell_fd = -1;
4966 }
4967 }
4968
4969 if (options & SHELL_READ)
4970 ga_init2(&ga, 1, BUFLEN);
4971
4972 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004973# ifdef ELAPSED_FUNC
4974 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004975# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004976 for (;;)
4977 {
4978 /*
4979 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004980 * if there are any.
4981 * Don't do this if we are expanding wild cards (would eat
4982 * typeahead).
4983 * Don't do this when filtering and terminal is in cooked
4984 * mode, the shell command will handle the I/O. Avoids
4985 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004986 * Don't get characters when the child has already
4987 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004988 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004989 * while (noread_cnt > 4), avoids that ":r !ls" eats
4990 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991 */
4992 len = 0;
4993 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004994 && ((options &
4995 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4996 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004997# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004998 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004999# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005000 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005001 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005002 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005004 if (ta_len == 0)
5005 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005006 // Get extra characters when we don't have any.
5007 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005008 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005009# ifdef ELAPSED_FUNC
5010 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005011# endif
5012 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5013 }
5014 if (ta_len > 0 || len > 0)
5015 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 /*
5017 * For pipes:
5018 * Check for CTRL-C: send interrupt signal to child.
5019 * Check for CTRL-D: EOF, close pipe to child.
5020 */
5021 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5022 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023 /*
5024 * Send SIGINT to the child's group or all
5025 * processes in our group.
5026 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005027 may_send_sigint(ta_buf[ta_len], pid, wpid);
5028
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029 if (pty_master_fd < 0 && toshell_fd >= 0
5030 && ta_buf[ta_len] == Ctrl_D)
5031 {
5032 close(toshell_fd);
5033 toshell_fd = -1;
5034 }
5035 }
5036
Bram Moolenaarf4140482020-02-15 23:06:45 +01005037 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038
5039 /*
5040 * For pipes: echo the typed characters.
5041 * For a pty this does not seem to work.
5042 */
5043 if (pty_master_fd < 0)
5044 {
5045 for (i = ta_len; i < ta_len + len; ++i)
5046 {
5047 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5048 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 else if (has_mbyte)
5050 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005051 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052
5053 msg_outtrans_len(ta_buf + i, l);
5054 i += l - 1;
5055 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005056 else
5057 msg_outtrans_len(ta_buf + i, 1);
5058 }
5059 windgoto(msg_row, msg_col);
5060 out_flush();
5061 }
5062
5063 ta_len += len;
5064
5065 /*
5066 * Write the characters to the child, unless EOF has
5067 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005068 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005069 * When writing buffer lines, drop the typed
5070 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005072 if (options & SHELL_WRITE)
5073 ta_len = 0;
5074 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075 {
5076 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5077 if (len > 0)
5078 {
5079 ta_len -= len;
5080 mch_memmove(ta_buf, ta_buf + len, ta_len);
5081 }
5082 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005083 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 }
5085
Bram Moolenaardf177f62005-02-22 08:39:57 +00005086 if (got_int)
5087 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005088 // CTRL-C sends a signal to the child, we ignore it
5089 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005090# ifdef HAVE_SETSID
5091 kill(-pid, SIGINT);
5092# else
5093 kill(0, SIGINT);
5094# endif
5095 if (wpid > 0)
5096 kill(wpid, SIGINT);
5097 got_int = FALSE;
5098 }
5099
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 /*
5101 * Check if the child has any characters to be printed.
5102 * Read them and write them to our window. Repeat this as
5103 * long as there is something to do, avoid the 10ms wait
5104 * for mch_inchar(), or sending typeahead characters to
5105 * the external process.
5106 * TODO: This should handle escape sequences, compatible
5107 * to some terminal (vt52?).
5108 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005109 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005110 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005112 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005115 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005117
5118 noread_cnt = 0;
5119 if (options & SHELL_READ)
5120 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005121 // Do NUL -> NL translation, append NL separated
5122 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005123 for (i = 0; i < len; ++i)
5124 {
5125 if (buffer[i] == NL)
5126 append_ga_line(&ga);
5127 else if (buffer[i] == NUL)
5128 ga_append(&ga, NL);
5129 else
5130 ga_append(&ga, buffer[i]);
5131 }
5132 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005133 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 {
5135 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005136 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005137
Bram Moolenaardf177f62005-02-22 08:39:57 +00005138 len += buffer_off;
5139 buffer[len] = NUL;
5140
Bram Moolenaar0f873732019-12-05 20:28:46 +01005141 // Check if the last character in buffer[] is
5142 // incomplete, keep these bytes for the next
5143 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005144 for (p = buffer; p < buffer + len; p += l)
5145 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005146 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005148 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 else if (MB_BYTE2LEN(*p) != l)
5150 break;
5151 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005152 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005154 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155 if (len >= 12)
5156 ++p;
5157 else
5158 {
5159 buffer_off = len;
5160 continue;
5161 }
5162 }
5163 c = *p;
5164 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005165 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166 if (p < buffer + len)
5167 {
5168 *p = c;
5169 buffer_off = (buffer + len) - p;
5170 mch_memmove(buffer, p, buffer_off);
5171 continue;
5172 }
5173 buffer_off = 0;
5174 }
5175 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005176 {
5177 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005178 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 }
5180
5181 windgoto(msg_row, msg_col);
5182 cursor_on();
5183 out_flush();
5184 if (got_int)
5185 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005186
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005187# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005188 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005189 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005190 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005191
Bram Moolenaar0f873732019-12-05 20:28:46 +01005192 // Avoid that we keep looping here without
5193 // checking for a CTRL-C for a long time. Don't
5194 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005195 if (msec > 2000)
5196 {
5197 noread_cnt = 5;
5198 break;
5199 }
5200 }
5201# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005202 }
5203
Bram Moolenaar0f873732019-12-05 20:28:46 +01005204 // If we already detected the child has finished, continue
5205 // reading output for a short while. Some text may be
5206 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005207 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005208 {
5209 if (noread_cnt < 5)
5210 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005211 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005212 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005213
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214 /*
5215 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005216 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005218# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005219 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005220# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005222# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5224 || (wait_pid == pid && WIFEXITED(status)))
5225 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005226 // Don't break the loop yet, try reading more
5227 // characters from "fromshell_fd" first. When using
5228 // pipes there might still be something to read and
5229 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005231 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005232 else
5233 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005234
Bram Moolenaar95a51352013-03-21 22:53:50 +01005235# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005236 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005237 clip_update();
5238# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 }
5240finished:
5241 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005242 if (options & SHELL_READ)
5243 {
5244 if (ga.ga_len > 0)
5245 {
5246 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005247 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005248 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005249 }
5250 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005251 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005252 ga_clear(&ga);
5253 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255 /*
5256 * Give all typeahead that wasn't used back to ui_inchar().
5257 */
5258 if (ta_len)
5259 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260 State = old_State;
5261 if (toshell_fd >= 0)
5262 close(toshell_fd);
5263 close(fromshell_fd);
5264 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005265# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005266 else
5267 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005268 long delay_msec = 1;
5269
Bram Moolenaar0981c872020-08-23 14:28:37 +02005270 out_str(T_CTE); // possibly disables modifyOtherKeys, so that
5271 // the system can recognize CTRL-C
5272
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005273 /*
5274 * Similar to the loop above, but only handle X events, no
5275 * I/O.
5276 */
5277 for (;;)
5278 {
5279 if (got_int)
5280 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005281 // CTRL-C sends a signal to the child, we ignore it
5282 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005283# ifdef HAVE_SETSID
5284 kill(-pid, SIGINT);
5285# else
5286 kill(0, SIGINT);
5287# endif
5288 got_int = FALSE;
5289 }
5290# ifdef __NeXT__
5291 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5292# else
5293 wait_pid = waitpid(pid, &status, WNOHANG);
5294# endif
5295 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5296 || (wait_pid == pid && WIFEXITED(status)))
5297 {
5298 wait_pid = pid;
5299 break;
5300 }
5301
Bram Moolenaar0f873732019-12-05 20:28:46 +01005302 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005303 clip_update();
5304
Bram Moolenaar0f873732019-12-05 20:28:46 +01005305 // Wait for 1 to 10 msec. 1 is faster but gives the child
Bram Moolenaar0981c872020-08-23 14:28:37 +02005306 // less time, gradually wait longer.
5307 mch_delay(delay_msec,
5308 MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005309 if (++delay_msec > 10)
5310 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005311 }
Bram Moolenaar0981c872020-08-23 14:28:37 +02005312
5313 out_str(T_CTI); // possibly enables modifyOtherKeys again
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005314 }
5315# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005316
5317 /*
5318 * Wait until our child has exited.
5319 * Ignore wait() returning pids of other children and returning
5320 * because of some signal like SIGWINCH.
5321 * Don't wait if wait_pid was already set above, indicating the
5322 * child already exited.
5323 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005324 if (wait_pid != pid)
5325 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326
Bram Moolenaar624891f2010-10-13 16:22:09 +02005327# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005328 // Close slave side of pty. Only do this after the child has
5329 // exited, otherwise the child may hang when it tries to write on
5330 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005331 if (pty_master_fd >= 0)
5332 close(pty_slave_fd);
5333# endif
5334
Bram Moolenaar0f873732019-12-05 20:28:46 +01005335 // Make sure the child that writes to the external program is
5336 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005337 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005338 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005339 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005340 wait4pid(wpid, NULL);
5341 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005342
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005343# ifdef FEAT_JOB_CHANNEL
5344 --dont_check_job_ended;
5345# endif
5346
Bram Moolenaar071d4272004-06-13 20:20:40 +00005347 /*
5348 * Set to raw mode right now, otherwise a CTRL-C after
5349 * catch_signals() will kill Vim.
5350 */
5351 if (tmode == TMODE_RAW)
5352 settmode(TMODE_RAW);
5353 did_settmode = TRUE;
5354 set_signals();
5355
5356 if (WIFEXITED(status))
5357 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005358 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005359 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005360 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005361 {
5362 if (retval == EXEC_FAILED)
5363 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005364 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365 msg_outtrans(p_sh);
5366 msg_putchar('\n');
5367 }
5368 else if (!(options & SHELL_SILENT))
5369 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005370 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 msg_outnum((long)retval);
5372 msg_putchar('\n');
5373 }
5374 }
5375 }
5376 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005377 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 }
5379 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005380
5381error:
5382 if (!did_settmode)
5383 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005384 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005385# ifdef FEAT_TITLE
5386 resettitle();
5387# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005388 vim_free(argv);
5389 vim_free(tofree1);
5390 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005391
5392 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005393}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005394#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005395
5396 int
5397mch_call_shell(
5398 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005399 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005400{
5401#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5402 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5403 return mch_call_shell_terminal(cmd, options);
5404#endif
5405#ifdef USE_SYSTEM
5406 return mch_call_shell_system(cmd, options);
5407#else
5408 return mch_call_shell_fork(cmd, options);
5409#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005410}
5411
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005412#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005413 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005414mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005415{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005416 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005417 int fd_in[2] = {-1, -1}; // for stdin
5418 int fd_out[2] = {-1, -1}; // for stdout
5419 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005420 int pty_master_fd = -1;
5421 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005422 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005423 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5424 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5425 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005426 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005427 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5428 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005429 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005430 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005431 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005432
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005433 if (use_out_for_err && use_null_for_out)
5434 use_null_for_err = TRUE;
5435
Bram Moolenaar0f873732019-12-05 20:28:46 +01005436 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005437 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005438
Bram Moolenaarb2412082017-08-20 18:09:14 +02005439 if (options->jo_pty
5440 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005441 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005442 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005443 open_pty(&pty_master_fd, &pty_slave_fd,
5444 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005445
Bram Moolenaar0f873732019-12-05 20:28:46 +01005446 // TODO: without the channel feature connect the child to /dev/null?
5447 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005448 if (use_file_for_in)
5449 {
5450 char_u *fname = options->jo_io_name[PART_IN];
5451
5452 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5453 if (fd_in[0] < 0)
5454 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005455 semsg(_(e_notopen), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005456 goto failed;
5457 }
5458 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005459 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005460 // When writing buffer lines to the input don't use the pty, so that
5461 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005462 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5463 && pipe(fd_in) < 0)
5464 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005465
5466 if (use_file_for_out)
5467 {
5468 char_u *fname = options->jo_io_name[PART_OUT];
5469
5470 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5471 if (fd_out[1] < 0)
5472 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005473 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005474 goto failed;
5475 }
5476 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005477 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005478 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005479
5480 if (use_file_for_err)
5481 {
5482 char_u *fname = options->jo_io_name[PART_ERR];
5483
5484 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5485 if (fd_err[1] < 0)
5486 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005487 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005488 goto failed;
5489 }
5490 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005491 else if (!use_out_for_err && !use_null_for_err
5492 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005493 goto failed;
5494
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005495 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5496 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005497 if (options->jo_set & JO_CHANNEL)
5498 {
5499 channel = options->jo_channel;
5500 if (channel != NULL)
5501 ++channel->ch_refcount;
5502 }
5503 else
5504 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005505 if (channel == NULL)
5506 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005507 if (job->jv_tty_out != NULL)
5508 ch_log(channel, "using pty %s on fd %d",
5509 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005510 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005511
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005512 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005513 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005514 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005515 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005516 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005517 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005518 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005519 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005520 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005521 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005522 int null_fd = -1;
5523 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005524
Bram Moolenaar0f873732019-12-05 20:28:46 +01005525 // child
5526 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005527 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005528
Bram Moolenaar819524702018-02-27 19:10:00 +01005529# ifdef FEAT_JOB_CHANNEL
5530 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005531 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005532 ch_logfile((char_u *)"", (char_u *)"");
5533# endif
5534
Bram Moolenaar835dc632016-02-07 14:27:38 +01005535# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005536 // Create our own process group, so that the child and all its
5537 // children can be kill()ed. Don't do this when using pipes,
5538 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005539 (void)setsid();
5540# endif
5541
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005542# ifdef FEAT_TERMINAL
5543 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005544 {
5545 char *term = (char *)T_NAME;
5546
5547#ifdef FEAT_GUI
5548 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005549 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005550 term = getenv("TERM");
5551#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005552 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005553 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005554 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005555 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005556 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005557 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005558 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005559 else if (t_colors > 16)
5560 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005561 else
5562 term = "xterm";
5563 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005564 set_child_environment(
5565 (long)options->jo_term_rows,
5566 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005567 term,
5568 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005569 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005570 else
5571# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005572 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005573
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005574 if (options->jo_env != NULL)
5575 {
5576 dict_T *dict = options->jo_env;
5577 hashitem_T *hi;
5578 int todo = (int)dict->dv_hashtab.ht_used;
5579
5580 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5581 if (!HASHITEM_EMPTY(hi))
5582 {
5583 typval_T *item = &dict_lookup(hi)->di_tv;
5584
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005585 vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005586 --todo;
5587 }
5588 }
5589
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005590 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005591 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005592 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005593 if (null_fd < 0)
5594 {
5595 perror("opening /dev/null failed");
5596 _exit(OPEN_NULL_FAILED);
5597 }
5598 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005599
Bram Moolenaar223896d2017-08-02 22:33:28 +02005600 if (pty_slave_fd >= 0)
5601 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005602 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005603 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005604# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005605 // Try to become controlling tty (probably doesn't work,
5606 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005607 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5608# endif
5609 }
5610
Bram Moolenaar0f873732019-12-05 20:28:46 +01005611 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005612 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005613 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005614 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005615 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005616 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005617 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005618 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005619
Bram Moolenaar0f873732019-12-05 20:28:46 +01005620 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005621 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005622 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005623 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005624 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005625 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005626 }
5627 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005628 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005629 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005630 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005631 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005632 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005633
Bram Moolenaar0f873732019-12-05 20:28:46 +01005634 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005635 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005636 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005637 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005638 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005639 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005640 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005641 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005642
5643 if (fd_in[0] >= 0)
5644 close(fd_in[0]);
5645 if (fd_in[1] >= 0)
5646 close(fd_in[1]);
5647 if (fd_out[0] >= 0)
5648 close(fd_out[0]);
5649 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005650 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005651 if (fd_err[0] >= 0)
5652 close(fd_err[0]);
5653 if (fd_err[1] >= 0)
5654 close(fd_err[1]);
5655 if (pty_master_fd >= 0)
5656 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005657 close(pty_master_fd); // not used in the child
5658 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005659 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005660
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005661 if (null_fd >= 0)
5662 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005663
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005664 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5665 _exit(EXEC_FAILED);
5666
Bram Moolenaar0f873732019-12-05 20:28:46 +01005667 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005668 execvp(argv[0], argv);
5669
Bram Moolenaar4694a172016-04-21 14:05:23 +02005670 if (stderr_works)
5671 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005672# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005673 // calling free_all_mem() here causes problems. Ignore valgrind
5674 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005675# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005676 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005677 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005678
Bram Moolenaar0f873732019-12-05 20:28:46 +01005679 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005680 UNBLOCK_SIGNALS(&curset);
5681
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005682 job->jv_pid = pid;
5683 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005684 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005685
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005686 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005687 close(pty_slave_fd); // not used in the parent
5688 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005689 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005690 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005691 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005692 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005693 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005694 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005695 if (channel != NULL)
5696 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005697 int in_fd = INVALID_FD;
5698 int out_fd = INVALID_FD;
5699 int err_fd = INVALID_FD;
5700
5701 if (!(use_file_for_in || use_null_for_in))
5702 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5703
5704 if (!(use_file_for_out || use_null_for_out))
5705 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5706
5707 // When using pty_master_fd only set it for stdout, do not duplicate
5708 // it for stderr, it only needs to be read once.
5709 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5710 {
5711 if (fd_err[0] >= 0)
5712 err_fd = fd_err[0];
5713 else if (out_fd != pty_master_fd)
5714 err_fd = pty_master_fd;
5715 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005716
5717 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005718 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005719 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005720 else
5721 {
5722 if (fd_in[1] >= 0)
5723 close(fd_in[1]);
5724 if (fd_out[0] >= 0)
5725 close(fd_out[0]);
5726 if (fd_err[0] >= 0)
5727 close(fd_err[0]);
5728 if (pty_master_fd >= 0)
5729 close(pty_master_fd);
5730 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005731
Bram Moolenaar0f873732019-12-05 20:28:46 +01005732 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005733 return;
5734
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005735failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005736 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005737 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005738 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005739 if (fd_in[1] >= 0)
5740 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005741 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005742 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005743 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005744 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005745 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005746 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005747 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005748 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005749 if (pty_master_fd >= 0)
5750 close(pty_master_fd);
5751 if (pty_slave_fd >= 0)
5752 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005753}
5754
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005755 static char_u *
5756get_signal_name(int sig)
5757{
5758 int i;
5759 char_u numbuf[NUMBUFLEN];
5760
5761 if (sig == SIGKILL)
5762 return vim_strsave((char_u *)"kill");
5763
5764 for (i = 0; signal_info[i].sig != -1; i++)
5765 if (sig == signal_info[i].sig)
5766 return strlow_save((char_u *)signal_info[i].name);
5767
5768 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5769 return vim_strsave(numbuf);
5770}
5771
Bram Moolenaar835dc632016-02-07 14:27:38 +01005772 char *
5773mch_job_status(job_T *job)
5774{
5775# ifdef HAVE_UNION_WAIT
5776 union wait status;
5777# else
5778 int status = -1;
5779# endif
5780 pid_t wait_pid = 0;
5781
5782# ifdef __NeXT__
5783 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5784# else
5785 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5786# endif
5787 if (wait_pid == -1)
5788 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005789 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005790 if (job->jv_status < JOB_ENDED)
5791 ch_log(job->jv_channel, "Job no longer exists: %s",
5792 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005793 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005794 }
5795 if (wait_pid == 0)
5796 return "run";
5797 if (WIFEXITED(status))
5798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005799 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005800 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005801 if (job->jv_status < JOB_ENDED)
5802 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005803 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005804 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005805 if (WIFSIGNALED(status))
5806 {
5807 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005808 job->jv_termsig = get_signal_name(WTERMSIG(status));
5809 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5810 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5811 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005812 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005813 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005814 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005815
5816return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005817 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005818 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005819 return "dead";
5820}
5821
5822 job_T *
5823mch_detect_ended_job(job_T *job_list)
5824{
5825# ifdef HAVE_UNION_WAIT
5826 union wait status;
5827# else
5828 int status = -1;
5829# endif
5830 pid_t wait_pid = 0;
5831 job_T *job;
5832
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005833# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005834 // Do not do this when waiting for a shell command to finish, we would get
5835 // the exit value here (and discard it), the exit value obtained there
5836 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005837 if (dont_check_job_ended > 0)
5838 return NULL;
5839# endif
5840
Bram Moolenaar97792de2016-10-15 18:36:49 +02005841# ifdef __NeXT__
5842 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5843# else
5844 wait_pid = waitpid(-1, &status, WNOHANG);
5845# endif
5846 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005847 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005848 return NULL;
5849 for (job = job_list; job != NULL; job = job->jv_next)
5850 {
5851 if (job->jv_pid == wait_pid)
5852 {
5853 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005854 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005855 job->jv_exitval = WEXITSTATUS(status);
5856 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005857 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005858 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005859 job->jv_termsig = get_signal_name(WTERMSIG(status));
5860 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005861 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005862 {
5863 ch_log(job->jv_channel, "Job ended");
5864 job->jv_status = JOB_ENDED;
5865 }
5866 return job;
5867 }
5868 }
5869 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005870}
5871
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005872/*
5873 * Send a (deadly) signal to "job".
5874 * Return FAIL if "how" is not a valid name.
5875 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005876 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005877mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005878{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005879 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005880
Bram Moolenaar923d9262016-02-25 20:56:01 +01005881 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005882 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005883 else if (STRCMP(how, "hup") == 0)
5884 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005885 else if (STRCMP(how, "quit") == 0)
5886 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005887 else if (STRCMP(how, "int") == 0)
5888 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005889 else if (STRCMP(how, "kill") == 0)
5890 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005891#ifdef SIGWINCH
5892 else if (STRCMP(how, "winch") == 0)
5893 sig = SIGWINCH;
5894#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005895 else if (isdigit(*how))
5896 sig = atoi((char *)how);
5897 else
5898 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005899
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005900 // Never kill ourselves!
5901 if (job->jv_pid != 0)
5902 {
5903 // TODO: have an option to only kill the process, not the group?
5904 kill(-job->jv_pid, sig);
5905 kill(job->jv_pid, sig);
5906 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005907
Bram Moolenaar835dc632016-02-07 14:27:38 +01005908 return OK;
5909}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005910
5911/*
5912 * Clear the data related to "job".
5913 */
5914 void
5915mch_clear_job(job_T *job)
5916{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005917 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005918# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005919 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005920# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005921 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005922# endif
5923}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005924#endif
5925
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005926#if defined(FEAT_TERMINAL) || defined(PROTO)
5927 int
5928mch_create_pty_channel(job_T *job, jobopt_T *options)
5929{
5930 int pty_master_fd = -1;
5931 int pty_slave_fd = -1;
5932 channel_T *channel;
5933
Bram Moolenaar59386482019-02-10 22:43:46 +01005934 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaard0342202020-06-29 22:40:42 +02005935 if (pty_master_fd < 0 || pty_slave_fd < 0)
5936 return FAIL;
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005937 close(pty_slave_fd);
5938
5939 channel = add_channel();
5940 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005941 {
5942 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005943 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005944 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005945 if (job->jv_tty_out != NULL)
5946 ch_log(channel, "using pty %s on fd %d",
5947 job->jv_tty_out, pty_master_fd);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005948 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005949 channel->ch_keep_open = TRUE;
5950
Bram Moolenaar0f873732019-12-05 20:28:46 +01005951 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5952 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005953 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005954 channel_set_job(channel, job, options);
5955 return OK;
5956}
5957#endif
5958
Bram Moolenaar071d4272004-06-13 20:20:40 +00005959/*
5960 * Check for CTRL-C typed by reading all available characters.
5961 * In cooked mode we should get SIGINT, no need to check.
5962 */
5963 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005964mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965{
Bram Moolenaar26e86442020-05-17 14:06:16 +02005966 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005967 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005968 fill_input_buf(FALSE);
5969}
5970
5971/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005972 * Wait "msec" msec until a character is available from the mouse, keyboard,
5973 * from inbuf[].
5974 * "msec" == -1 will block forever.
5975 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005976 * When "ignore_input" is TRUE even check for pending input when input is
5977 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005978 * "interrupted" (if not NULL) is set to TRUE when no character is available
5979 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005980 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005981 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982 */
5983 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005984WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005985{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005986#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01005987 return ui_wait_for_chars_or_timer(
5988 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005989#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005990 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005991#endif
5992}
5993
5994/*
5995 * Wait "msec" msec until a character is available from the mouse or keyboard
5996 * or from inbuf[].
5997 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005998 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02005999 * "interrupted" (if not NULL) is set to TRUE when no character is available
6000 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006001 * When a GUI is being used, this will never get called -- webb
6002 */
6003 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006004WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006005{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006006#ifdef FEAT_MOUSE_GPM
6007 int gpm_process_wanted;
6008#endif
6009#ifdef FEAT_XCLIPBOARD
6010 int rest;
6011#endif
6012 int avail;
6013
Bram Moolenaar0f873732019-12-05 20:28:46 +01006014 if (!ignore_input && input_available()) // something in inbuf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015 return 1;
6016
6017#if defined(FEAT_MOUSE_DEC)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006018 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019 if (WantQueryMouse)
6020 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006021 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006022 if (!no_query_mouse_for_testing)
6023 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024 }
6025#endif
6026
6027 /*
6028 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6029 * events. This is a bit complicated, because they might both be defined.
6030 */
6031#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6032# ifdef FEAT_XCLIPBOARD
6033 rest = 0;
6034 if (do_xterm_trace())
6035 rest = msec;
6036# endif
6037 do
6038 {
6039# ifdef FEAT_XCLIPBOARD
6040 if (rest != 0)
6041 {
6042 msec = XT_TRACE_DELAY;
6043 if (rest >= 0 && rest < XT_TRACE_DELAY)
6044 msec = rest;
6045 if (rest >= 0)
6046 rest -= msec;
6047 }
6048# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006049# ifdef FEAT_SOUND_CANBERRA
6050 // Invoke any pending sound callbacks.
6051 if (has_sound_callback_in_queue())
6052 invoke_sound_callback();
6053# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006054# ifdef FEAT_MOUSE_GPM
6055 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006056 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006057 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006058 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006060 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006062# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006064 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006065 return 1;
6066# ifdef FEAT_XCLIPBOARD
6067 if (rest == 0 || !do_xterm_trace())
6068# endif
6069 break;
6070 }
6071 }
6072 while (FALSE
6073# ifdef FEAT_MOUSE_GPM
6074 || (gpm_process_wanted && mch_gpm_process() == 0)
6075# endif
6076# ifdef FEAT_XCLIPBOARD
6077 || (!avail && rest != 0)
6078# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006079 )
6080 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006081
6082#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006083 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084#endif
6085 return avail;
6086}
6087
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006088#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006089/*
6090 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006091 * "msec" == 0 will check for characters once.
6092 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006093 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006095 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006096 * "interrupted" (if not NULL) is set to TRUE when no character is available
6097 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 */
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006099 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02006100RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101{
6102 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006103 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006104#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006105 static int busy = FALSE;
6106
Bram Moolenaar0f873732019-12-05 20:28:46 +01006107 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006108# define MAY_LOOP
6109
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006110# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006111 // Remember at what time we started, so that we know how much longer we
6112 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006113 long start_msec = msec;
6114 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006115
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006116 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006117 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118# endif
6119
Bram Moolenaar0f873732019-12-05 20:28:46 +01006120 // Handle being called recursively. This may happen for the session
6121 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122 if (busy)
6123 return 0;
6124#endif
6125
6126#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006127 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006128#endif
6129 {
6130#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006131 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006132# ifdef FEAT_MZSCHEME
6133 int mzquantum_used = FALSE;
6134# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006135#endif
6136#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006137 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006138 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139 int nfd;
6140# ifdef FEAT_XCLIPBOARD
6141 int xterm_idx = -1;
6142# endif
6143# ifdef FEAT_MOUSE_GPM
6144 int gpm_idx = -1;
6145# endif
6146# ifdef USE_XSMP
6147 int xsmp_idx = -1;
6148# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006149 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006151# ifdef FEAT_MZSCHEME
6152 mzvim_check_threads();
6153 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6154 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006155 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006156 mzquantum_used = TRUE;
6157 }
6158# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006159 fds[0].fd = fd;
6160 fds[0].events = POLLIN;
6161 nfd = 1;
6162
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006164 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165 if (xterm_Shell != (Widget)0)
6166 {
6167 xterm_idx = nfd;
6168 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6169 fds[nfd].events = POLLIN;
6170 nfd++;
6171 }
6172# endif
6173# ifdef FEAT_MOUSE_GPM
6174 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6175 {
6176 gpm_idx = nfd;
6177 fds[nfd].fd = gpm_fd;
6178 fds[nfd].events = POLLIN;
6179 nfd++;
6180 }
6181# endif
6182# ifdef USE_XSMP
6183 if (xsmp_icefd != -1)
6184 {
6185 xsmp_idx = nfd;
6186 fds[nfd].fd = xsmp_icefd;
6187 fds[nfd].events = POLLIN;
6188 nfd++;
6189 }
6190# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006191#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006192 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006193#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006194 if (interrupted != NULL)
6195 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006197 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006198
6199 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006200 if (result == 0 && interrupted != NULL && ret > 0)
6201 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006202
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006203# ifdef FEAT_MZSCHEME
6204 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006205 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006206 finished = FALSE;
6207# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208
Bram Moolenaar071d4272004-06-13 20:20:40 +00006209# ifdef FEAT_XCLIPBOARD
6210 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6211 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006212 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006213 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006214 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006215 finished = FALSE;
6216 }
6217# endif
6218# ifdef FEAT_MOUSE_GPM
6219 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006220 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006221# endif
6222# ifdef USE_XSMP
6223 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6224 {
6225 if (fds[xsmp_idx].revents & POLLIN)
6226 {
6227 busy = TRUE;
6228 xsmp_handle_requests();
6229 busy = FALSE;
6230 }
6231 else if (fds[xsmp_idx].revents & POLLHUP)
6232 {
6233 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006234 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235 xsmp_close();
6236 }
6237 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006238 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239 }
6240# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006241#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006242 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006243 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006244 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006245#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246
Bram Moolenaar0f873732019-12-05 20:28:46 +01006247#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248
6249 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006250 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006251 // These are static because they can take 8 Kbyte each and cause the
6252 // signal stack to run out with -O3.
6253 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006255 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006257# ifdef FEAT_MZSCHEME
6258 mzvim_check_threads();
6259 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6260 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006261 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006262 mzquantum_used = TRUE;
6263 }
6264# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006265
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006266 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006267 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006268 tv.tv_sec = towait / 1000;
6269 tv.tv_usec = (towait % 1000) * (1000000/1000);
6270 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006272 else
6273 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006274
6275 /*
6276 * Select on ready for reading and exceptional condition (end of file).
6277 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006278select_eintr:
6279 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006280 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006281 FD_ZERO(&efds);
6282 FD_SET(fd, &rfds);
6283# if !defined(__QNX__) && !defined(__CYGWIN32__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006284 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006285 FD_SET(fd, &efds);
6286# endif
6287 maxfd = fd;
6288
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006290 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 if (xterm_Shell != (Widget)0)
6292 {
6293 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6294 if (maxfd < ConnectionNumber(xterm_dpy))
6295 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006296
Bram Moolenaar0f873732019-12-05 20:28:46 +01006297 // An event may have already been read but not handled. In
6298 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006299 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300 }
6301# endif
6302# ifdef FEAT_MOUSE_GPM
6303 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6304 {
6305 FD_SET(gpm_fd, &rfds);
6306 FD_SET(gpm_fd, &efds);
6307 if (maxfd < gpm_fd)
6308 maxfd = gpm_fd;
6309 }
6310# endif
6311# ifdef USE_XSMP
6312 if (xsmp_icefd != -1)
6313 {
6314 FD_SET(xsmp_icefd, &rfds);
6315 FD_SET(xsmp_icefd, &efds);
6316 if (maxfd < xsmp_icefd)
6317 maxfd = xsmp_icefd;
6318 }
6319# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006320# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006321 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006322# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006323 if (interrupted != NULL)
6324 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325
Bram Moolenaar643b6142018-09-12 20:29:09 +02006326 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6327 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006328 result = ret > 0 && FD_ISSET(fd, &rfds);
6329 if (result)
6330 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006331 else if (interrupted != NULL && ret > 0)
6332 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006333
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006334# ifdef EINTR
6335 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006336 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006337 // Check whether window has been resized, EINTR may be caused by
6338 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006339 if (do_resize)
6340 handle_resize();
6341
Bram Moolenaar0f873732019-12-05 20:28:46 +01006342 // Interrupted by a signal, need to try again. We ignore msec
6343 // here, because we do want to check even after a timeout if
6344 // characters are available. Needed for reading output of an
6345 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006346 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006347 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006348# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006349# ifdef __TANDEM
6350 if (ret == -1 && errno == ENOTSUP)
6351 {
6352 FD_ZERO(&rfds);
6353 FD_ZERO(&efds);
6354 ret = 0;
6355 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006356# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006357# ifdef FEAT_MZSCHEME
6358 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006359 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006360 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006361# endif
6362
Bram Moolenaar071d4272004-06-13 20:20:40 +00006363# ifdef FEAT_XCLIPBOARD
6364 if (ret > 0 && xterm_Shell != (Widget)0
6365 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6366 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006367 xterm_update(); // Maybe we should hand out clipboard
6368 // continue looping when we only got the X event and the input
6369 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006370 if (--ret == 0 && !input_available())
6371 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006372 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006373 finished = FALSE;
6374 }
6375 }
6376# endif
6377# ifdef FEAT_MOUSE_GPM
6378 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6379 {
6380 if (FD_ISSET(gpm_fd, &efds))
6381 gpm_close();
6382 else if (FD_ISSET(gpm_fd, &rfds))
6383 *check_for_gpm = 1;
6384 }
6385# endif
6386# ifdef USE_XSMP
6387 if (ret > 0 && xsmp_icefd != -1)
6388 {
6389 if (FD_ISSET(xsmp_icefd, &efds))
6390 {
6391 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006392 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006393 xsmp_close();
6394 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006395 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006396 }
6397 else if (FD_ISSET(xsmp_icefd, &rfds))
6398 {
6399 busy = TRUE;
6400 xsmp_handle_requests();
6401 busy = FALSE;
6402 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006403 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006404 }
6405 }
6406# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006407#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006408 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006409 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006410 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006411#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006412
Bram Moolenaar0f873732019-12-05 20:28:46 +01006413#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006414
6415#ifdef MAY_LOOP
6416 if (finished || msec == 0)
6417 break;
6418
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006419# ifdef FEAT_CLIENTSERVER
6420 if (server_waiting())
6421 break;
6422# endif
6423
Bram Moolenaar0f873732019-12-05 20:28:46 +01006424 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006425 if (msec > 0)
6426 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006427# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006428 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006429 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006430# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006431 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006432 msec = msec / 2;
6433# endif
6434 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006435 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006436 }
6437#endif
6438 }
6439
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006440 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441}
6442
Bram Moolenaar071d4272004-06-13 20:20:40 +00006443/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006444 * Expand a path into all matching files and/or directories. Handles "*",
6445 * "?", "[a-z]", "**", etc.
6446 * "path" has backslashes before chars that are not to be expanded.
6447 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448 */
6449 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006450mch_expandpath(
6451 garray_T *gap,
6452 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006453 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006454{
Bram Moolenaar02743632005-07-25 20:42:36 +00006455 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006456}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006457
6458/*
6459 * mch_expand_wildcards() - this code does wild-card pattern matching using
6460 * the shell
6461 *
6462 * return OK for success, FAIL for error (you may lose some memory) and put
6463 * an error message in *file.
6464 *
6465 * num_pat is number of input patterns
6466 * pat is array of pointers to input patterns
6467 * num_file is pointer to number of matched file names
6468 * file is pointer to array of pointers to matched file names
6469 */
6470
6471#ifndef SEEK_SET
6472# define SEEK_SET 0
6473#endif
6474#ifndef SEEK_END
6475# define SEEK_END 2
6476#endif
6477
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006478#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006479
Bram Moolenaar071d4272004-06-13 20:20:40 +00006480 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006481mch_expand_wildcards(
6482 int num_pat,
6483 char_u **pat,
6484 int *num_file,
6485 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006486 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006487{
6488 int i;
6489 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006490 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006491 char_u *p;
6492 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006493
Bram Moolenaarc7247912008-01-13 12:54:11 +00006494 /*
6495 * This is the non-OS/2 implementation (really Unix).
6496 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497 int j;
6498 char_u *tempname;
6499 char_u *command;
6500 FILE *fd;
6501 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006502#define STYLE_ECHO 0 // use "echo", the default
6503#define STYLE_GLOB 1 // use "glob", for csh
6504#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6505#define STYLE_PRINT 3 // use "print -N", for zsh
6506#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6507 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006508 int shell_style = STYLE_ECHO;
6509 int check_spaces;
6510 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006511 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006512 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006513 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514
Bram Moolenaar0f873732019-12-05 20:28:46 +01006515 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006516 *file = NULL;
6517
6518 /*
6519 * If there are no wildcards, just copy the names to allocated memory.
6520 * Saves a lot of time, because we don't have to start a new shell.
6521 */
6522 if (!have_wildcard(num_pat, pat))
6523 return save_patterns(num_pat, pat, num_file, file);
6524
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006525# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006526 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006527 if (sandbox != 0 && check_secure())
6528 return FAIL;
6529# endif
6530
Bram Moolenaar071d4272004-06-13 20:20:40 +00006531 /*
6532 * Don't allow the use of backticks in secure and restricted mode.
6533 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006534 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006535 for (i = 0; i < num_pat; ++i)
6536 if (vim_strchr(pat[i], '`') != NULL
6537 && (check_restricted() || check_secure()))
6538 return FAIL;
6539
6540 /*
6541 * get a name for the temp file
6542 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006543 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006544 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006545 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006546 return FAIL;
6547 }
6548
6549 /*
6550 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006551 * file.
6552 * STYLE_BT: NL separated
6553 * If expanding `cmd` execute it directly.
6554 * STYLE_GLOB: NUL separated
6555 * If we use *csh, "glob" will work better than "echo".
6556 * STYLE_PRINT: NL or NUL separated
6557 * If we use *zsh, "print -N" will work better than "glob".
6558 * STYLE_VIMGLOB: NL separated
6559 * If we use *sh*, we define "vimglob()".
6560 * STYLE_ECHO: space separated.
6561 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006562 */
6563 if (num_pat == 1 && *pat[0] == '`'
6564 && (len = STRLEN(pat[0])) > 2
6565 && *(pat[0] + len - 1) == '`')
6566 shell_style = STYLE_BT;
6567 else if ((len = STRLEN(p_sh)) >= 3)
6568 {
6569 if (STRCMP(p_sh + len - 3, "csh") == 0)
6570 shell_style = STYLE_GLOB;
6571 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6572 shell_style = STYLE_PRINT;
6573 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006574 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6575 "sh") != NULL)
6576 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577
Bram Moolenaar0f873732019-12-05 20:28:46 +01006578 // Compute the length of the command. We need 2 extra bytes: for the
6579 // optional '&' and for the NUL.
6580 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006581 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006582 if (shell_style == STYLE_VIMGLOB)
6583 len += STRLEN(sh_vimglob_func);
6584
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006585 for (i = 0; i < num_pat; ++i)
6586 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006587 // Count the length of the patterns in the same way as they are put in
6588 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006589#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006590 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006591#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006592 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006593 for (j = 0; pat[i][j] != NUL; ++j)
6594 {
6595 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006596 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006597 ++len;
6598 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006599#endif
6600 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006601 command = alloc(len);
6602 if (command == NULL)
6603 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006604 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605 vim_free(tempname);
6606 return FAIL;
6607 }
6608
6609 /*
6610 * Build the shell command:
6611 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6612 * recognizes this).
6613 * - Add the shell command to print the expanded names.
6614 * - Add the temp file name.
6615 * - Add the file name patterns.
6616 */
6617 if (shell_style == STYLE_BT)
6618 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006619 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006620 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006621 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006622 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006623 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006624 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006625 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006626 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006627 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006628 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006629 *p = ' ';
6630 }
6631 STRCAT(command, ">");
6632 }
6633 else
6634 {
6635 if (flags & EW_NOTFOUND)
6636 STRCPY(command, "set nonomatch; ");
6637 else
6638 STRCPY(command, "unset nonomatch; ");
6639 if (shell_style == STYLE_GLOB)
6640 STRCAT(command, "glob >");
6641 else if (shell_style == STYLE_PRINT)
6642 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006643 else if (shell_style == STYLE_VIMGLOB)
6644 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006645 else
6646 STRCAT(command, "echo >");
6647 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006648
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006650
Bram Moolenaar071d4272004-06-13 20:20:40 +00006651 if (shell_style != STYLE_BT)
6652 for (i = 0; i < num_pat; ++i)
6653 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006654 // When using system() always add extra quotes, because the shell
6655 // is started twice. Otherwise put a backslash before special
6656 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006657#ifdef USE_SYSTEM
6658 STRCAT(command, " \"");
6659 STRCAT(command, pat[i]);
6660 STRCAT(command, "\"");
6661#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006662 int intick = FALSE;
6663
Bram Moolenaar071d4272004-06-13 20:20:40 +00006664 p = command + STRLEN(command);
6665 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006666 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006667 {
6668 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006669 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006670 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6671 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006672 // Remove a backslash, take char literally. But keep
6673 // backslash inside backticks, before a special character
6674 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006675 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006676 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6677 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006678 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006679 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006680 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006681 else if (!intick
6682 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6683 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006684 // Put a backslash before a special character, but not
6685 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6686 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006687 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006688
Bram Moolenaar0f873732019-12-05 20:28:46 +01006689 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006690 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006691 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006692 *p = NUL;
6693#endif
6694 }
6695 if (flags & EW_SILENT)
6696 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006697 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006698 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006699
6700 /*
6701 * Using zsh -G: If a pattern has no matches, it is just deleted from
6702 * the argument list, otherwise zsh gives an error message and doesn't
6703 * expand any other pattern.
6704 */
6705 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006706 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006707
6708 /*
6709 * If we use -f then shell variables set in .cshrc won't get expanded.
6710 * vi can do it, so we will too, but it is only necessary if there is a "$"
6711 * in one of the patterns, otherwise we can still use the fast option.
6712 */
6713 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006714 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006715
6716 /*
6717 * execute the shell command
6718 */
6719 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6720
Bram Moolenaar0f873732019-12-05 20:28:46 +01006721 // When running in the background, give it some time to create the temp
6722 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006723 if (ampersand)
Bram Moolenaar0981c872020-08-23 14:28:37 +02006724 mch_delay(10L, MCH_DELAY_IGNOREINPUT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006725
Bram Moolenaar0f873732019-12-05 20:28:46 +01006726 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006727 show_shell_mess = TRUE;
6728 vim_free(command);
6729
Bram Moolenaar0f873732019-12-05 20:28:46 +01006730 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006731 {
6732 mch_remove(tempname);
6733 vim_free(tempname);
6734 /*
6735 * With interactive completion, the error message is not printed.
6736 * However with USE_SYSTEM, I don't know how to turn off error messages
6737 * from the shell, so screen may still get messed up -- webb.
6738 */
6739#ifndef USE_SYSTEM
6740 if (!(flags & EW_SILENT))
6741#endif
6742 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006743 redraw_later_clear(); // probably messed up screen
6744 msg_putchar('\n'); // clear bottom line quickly
6745 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006746#ifdef USE_SYSTEM
6747 if (!(flags & EW_SILENT))
6748#endif
6749 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006750 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006751 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006752 }
6753 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006754 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6755 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006756 if (shell_style == STYLE_BT)
6757 return FAIL;
6758 goto notfound;
6759 }
6760
6761 /*
6762 * read the names from the file into memory
6763 */
6764 fd = fopen((char *)tempname, READBIN);
6765 if (fd == NULL)
6766 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006767 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006768 if (!(flags & EW_SILENT))
6769 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006770 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006771 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006772 }
6773 vim_free(tempname);
6774 goto notfound;
6775 }
6776 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006777 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006778 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006779 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006780 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006781 buffer = NULL;
6782 else
6783 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006784 if (buffer == NULL)
6785 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006786 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006787 mch_remove(tempname);
6788 vim_free(tempname);
6789 fclose(fd);
6790 return FAIL;
6791 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006792 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006793 i = fread((char *)buffer, 1, len, fd);
6794 fclose(fd);
6795 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006796 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006797 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006798 // unexpected read error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006799 semsg(_(e_notread), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006800 vim_free(tempname);
6801 vim_free(buffer);
6802 return FAIL;
6803 }
6804 vim_free(tempname);
6805
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006806# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006807 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006808 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006809 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006810 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6811 *p++ = buffer[i];
6812 len = p - buffer;
6813# endif
6814
6815
Bram Moolenaar0f873732019-12-05 20:28:46 +01006816 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006817 if (shell_style == STYLE_ECHO)
6818 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006819 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006820 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006821 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006822 {
6823 while (*p != ' ' && *p != '\n')
6824 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006825 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 }
6827 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006828 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006829 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006830 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006831 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006832 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006833 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006834 {
6835 while (*p != '\n' && *p != NUL)
6836 ++p;
6837 if (*p != NUL)
6838 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006839 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006840 }
6841 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006842 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006843 else
6844 {
6845 /*
6846 * Some versions of zsh use spaces instead of NULs to separate
6847 * results. Only do this when there is no NUL before the end of the
6848 * buffer, otherwise we would never be able to use file names with
6849 * embedded spaces when zsh does use NULs.
6850 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6851 * don't check for spaces again.
6852 */
6853 check_spaces = FALSE;
6854 if (shell_style == STYLE_PRINT && !did_find_nul)
6855 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006856 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006857 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006858 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006859 did_find_nul = TRUE;
6860 else
6861 check_spaces = TRUE;
6862 }
6863
6864 /*
6865 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6866 * already is one, for STYLE_GLOB it needs to be added.
6867 */
6868 if (len && buffer[len - 1] == NUL)
6869 --len;
6870 else
6871 buffer[len] = NUL;
6872 i = 0;
6873 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006874 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006875 {
6876 ++i;
6877 *p = NUL;
6878 }
6879 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006880 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006881 }
6882 if (i == 0)
6883 {
6884 /*
6885 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6886 * /bin/sh will happily expand it to nothing rather than returning an
6887 * error; and hey, it's good to check anyway -- webb.
6888 */
6889 vim_free(buffer);
6890 goto notfound;
6891 }
6892 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006893 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006894 if (*file == NULL)
6895 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006896 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006897 vim_free(buffer);
6898 return FAIL;
6899 }
6900
6901 /*
6902 * Isolate the individual file names.
6903 */
6904 p = buffer;
6905 for (i = 0; i < *num_file; ++i)
6906 {
6907 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006908 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00006909 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6910 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006911 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006912 while (!(shell_style == STYLE_ECHO && *p == ' ')
6913 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006914 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006915 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006916 *p = NUL;
6917 else
6918 {
6919 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006920 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921 }
6922 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006923 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006925 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006927 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 }
6929 }
6930
6931 /*
6932 * Move the file names to allocated memory.
6933 */
6934 for (j = 0, i = 0; i < *num_file; ++i)
6935 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006936 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00006937 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6938 continue;
6939
Bram Moolenaar0f873732019-12-05 20:28:46 +01006940 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00006941 dir = (mch_isdir((*file)[i]));
6942 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6943 continue;
6944
Bram Moolenaar0f873732019-12-05 20:28:46 +01006945 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01006946 if (!dir && (flags & EW_EXEC)
6947 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006948 continue;
6949
Bram Moolenaar964b3742019-05-24 18:54:09 +02006950 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006951 if (p)
6952 {
6953 STRCPY(p, (*file)[i]);
6954 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006955 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00006956 (*file)[j++] = p;
6957 }
6958 }
6959 vim_free(buffer);
6960 *num_file = j;
6961
Bram Moolenaar0f873732019-12-05 20:28:46 +01006962 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006963 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006964 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006965 goto notfound;
6966 }
6967
6968 return OK;
6969
6970notfound:
6971 if (flags & EW_NOTFOUND)
6972 return save_patterns(num_pat, pat, num_file, file);
6973 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006974}
6975
Bram Moolenaar0f873732019-12-05 20:28:46 +01006976#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006977
Bram Moolenaar071d4272004-06-13 20:20:40 +00006978 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006979save_patterns(
6980 int num_pat,
6981 char_u **pat,
6982 int *num_file,
6983 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006984{
6985 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006986 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006987
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006988 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006989 if (*file == NULL)
6990 return FAIL;
6991 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006992 {
6993 s = vim_strsave(pat[i]);
6994 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006995 // Be compatible with expand_filename(): halve the number of
6996 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00006997 backslash_halve(s);
6998 (*file)[i] = s;
6999 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000 *num_file = num_pat;
7001 return OK;
7002}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004/*
7005 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7006 * expand.
7007 */
7008 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007009mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007010{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007011 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007012 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007013 if (*p == '\\' && p[1] != NUL)
7014 ++p;
7015 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016 if (vim_strchr((char_u *)
7017#ifdef VMS
7018 "*?%"
7019#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007021#endif
7022 , *p) != NULL)
7023 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007024 }
7025 return FALSE;
7026}
7027
7028/*
7029 * Return TRUE if the string "p" contains a wildcard.
7030 * Don't recognize '~' at the end as a wildcard.
7031 */
7032 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007033mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007035 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007036 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007037 if (*p == '\\' && p[1] != NUL)
7038 ++p;
7039 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007040 if (vim_strchr((char_u *)
7041#ifdef VMS
7042 "*?%$"
7043#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007044 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007045#endif
7046 , *p) != NULL
7047 || (*p == '~' && p[1] != NUL))
7048 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007049 }
7050 return FALSE;
7051}
7052
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007054have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055{
7056 int i;
7057
7058 for (i = 0; i < num; i++)
7059 if (mch_has_wildcard(file[i]))
7060 return 1;
7061 return 0;
7062}
7063
7064 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007065have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066{
7067 int i;
7068
7069 for (i = 0; i < num; i++)
7070 if (vim_strchr(file[i], '$') != NULL)
7071 return TRUE;
7072 return FALSE;
7073}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007075#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076/*
7077 * Scaled-down version of rename(), which is missing in Xenix.
7078 * This version can only move regular files and will fail if the
7079 * destination exists.
7080 */
7081 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007082mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007083{
7084 struct stat st;
7085
Bram Moolenaar0f873732019-12-05 20:28:46 +01007086 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007087 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007088 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007090 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007091 return 0;
7092 return -1;
7093}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007094#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007096#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007097/*
7098 * Initializes connection with gpm (if it isn't already opened)
7099 * Return 1 if succeeded (or connection already opened), 0 if failed
7100 */
7101 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007102gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007104 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007105
7106 if (!gpm_flag)
7107 {
7108 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7109 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007110 // Default handling for mouse move
7111 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112 gpm_connect.maxMod = 0xffff;
7113 if (Gpm_Open(&gpm_connect, 0) > 0)
7114 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007115 // gpm library tries to handling TSTP causes
7116 // problems. Anyways, we close connection to Gpm whenever
7117 // we are going to suspend or starting an external process
7118 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007119# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007121# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007122 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007123 }
7124 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007125 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 return 0;
7127 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007128 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007129}
7130
7131/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007132 * Returns TRUE if the GPM mouse is enabled.
7133 */
7134 int
7135gpm_enabled(void)
7136{
7137 return gpm_flag && gpm_fd >= 0;
7138}
7139
7140/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007142 */
7143 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007144gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007146 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007147 Gpm_Close();
7148}
7149
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007150/*
7151 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007153 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154 */
7155 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007156mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007157{
7158 int button;
7159 static Gpm_Event gpm_event;
7160 char_u string[6];
7161 int_u vim_modifiers;
7162 int row,col;
7163 unsigned char buttons_mask;
7164 unsigned char gpm_modifiers;
7165 static unsigned char old_buttons = 0;
7166
7167 Gpm_GetEvent(&gpm_event);
7168
7169#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007170 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007171 if (hold_gui_events)
7172 return 0;
7173#endif
7174
7175 row = gpm_event.y - 1;
7176 col = gpm_event.x - 1;
7177
Bram Moolenaar0f873732019-12-05 20:28:46 +01007178 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007179 string[1] = 'M';
7180 string[2] = 'G';
7181 switch (GPM_BARE_EVENTS(gpm_event.type))
7182 {
7183 case GPM_DRAG:
7184 string[3] = MOUSE_DRAG;
7185 break;
7186 case GPM_DOWN:
7187 buttons_mask = gpm_event.buttons & ~old_buttons;
7188 old_buttons = gpm_event.buttons;
7189 switch (buttons_mask)
7190 {
7191 case GPM_B_LEFT:
7192 button = MOUSE_LEFT;
7193 break;
7194 case GPM_B_MIDDLE:
7195 button = MOUSE_MIDDLE;
7196 break;
7197 case GPM_B_RIGHT:
7198 button = MOUSE_RIGHT;
7199 break;
7200 default:
7201 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007202 // Don't know what to do. Can more than one button be
7203 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007204 }
7205 string[3] = (char_u)(button | 0x20);
7206 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7207 break;
7208 case GPM_UP:
7209 string[3] = MOUSE_RELEASE;
7210 old_buttons &= ~gpm_event.buttons;
7211 break;
7212 default:
7213 return 0;
7214 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007215 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007216 gpm_modifiers = gpm_event.modifiers;
7217 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007218 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7219 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7220 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007221 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7222 vim_modifiers |= MOUSE_SHIFT;
7223
7224 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7225 vim_modifiers |= MOUSE_CTRL;
7226 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7227 vim_modifiers |= MOUSE_ALT;
7228 string[3] |= vim_modifiers;
7229 string[4] = (char_u)(col + ' ' + 1);
7230 string[5] = (char_u)(row + ' ' + 1);
7231 add_to_input_buf(string, 6);
7232 return 6;
7233}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007234#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007235
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007236#ifdef FEAT_SYSMOUSE
7237/*
7238 * Initialize connection with sysmouse.
7239 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7240 * output, any sysmouse output than will be processed via sig_sysmouse().
7241 * Return OK if succeeded, FAIL if failed.
7242 */
7243 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007244sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007245{
7246 struct mouse_info mouse;
7247
7248 mouse.operation = MOUSE_MODE;
7249 mouse.u.mode.mode = 0;
7250 mouse.u.mode.signal = SIGUSR2;
7251 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7252 {
7253 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7254 mouse.operation = MOUSE_SHOW;
7255 ioctl(1, CONS_MOUSECTL, &mouse);
7256 return OK;
7257 }
7258 return FAIL;
7259}
7260
7261/*
7262 * Stop processing SIGUSR2 signals, and also make sure that
7263 * virtual console do not send us any sysmouse related signal.
7264 */
7265 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007266sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007267{
7268 struct mouse_info mouse;
7269
7270 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7271 mouse.operation = MOUSE_MODE;
7272 mouse.u.mode.mode = 0;
7273 mouse.u.mode.signal = 0;
7274 ioctl(1, CONS_MOUSECTL, &mouse);
7275}
7276
7277/*
7278 * Gets info from sysmouse and adds special keys to input buf.
7279 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007280 static RETSIGTYPE
7281sig_sysmouse SIGDEFARG(sigarg)
7282{
7283 struct mouse_info mouse;
7284 struct video_info video;
7285 char_u string[6];
7286 int row, col;
7287 int button;
7288 int buttons;
7289 static int oldbuttons = 0;
7290
7291#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007292 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007293 if (hold_gui_events)
7294 return;
7295#endif
7296
7297 mouse.operation = MOUSE_GETINFO;
7298 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7299 && ioctl(1, FBIO_MODEINFO, &video) != -1
7300 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7301 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7302 {
7303 row = mouse.u.data.y / video.vi_cheight;
7304 col = mouse.u.data.x / video.vi_cwidth;
7305 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007306 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007307 string[1] = 'M';
7308 string[2] = 'S';
7309 if (oldbuttons == buttons && buttons != 0)
7310 {
7311 button = MOUSE_DRAG;
7312 }
7313 else
7314 {
7315 switch (buttons)
7316 {
7317 case 0:
7318 button = MOUSE_RELEASE;
7319 break;
7320 case 1:
7321 button = MOUSE_LEFT;
7322 break;
7323 case 2:
7324 button = MOUSE_MIDDLE;
7325 break;
7326 case 4:
7327 button = MOUSE_RIGHT;
7328 break;
7329 default:
7330 return;
7331 }
7332 oldbuttons = buttons;
7333 }
7334 string[3] = (char_u)(button);
7335 string[4] = (char_u)(col + ' ' + 1);
7336 string[5] = (char_u)(row + ' ' + 1);
7337 add_to_input_buf(string, 6);
7338 }
7339 return;
7340}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007341#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007342
Bram Moolenaar071d4272004-06-13 20:20:40 +00007343#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007344typedef char_u * (*STRPROCSTR)(char_u *);
7345typedef char_u * (*INTPROCSTR)(int);
7346typedef int (*STRPROCINT)(char_u *);
7347typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007348
7349/*
7350 * Call a DLL routine which takes either a string or int param
7351 * and returns an allocated string.
7352 */
7353 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007354mch_libcall(
7355 char_u *libname,
7356 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007357 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007358 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007359 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007360 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007361{
7362# if defined(USE_DLOPEN)
7363 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007364 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365# else
7366 shl_t hinstLib;
7367# endif
7368 STRPROCSTR ProcAdd;
7369 INTPROCSTR ProcAddI;
7370 char_u *retval_str = NULL;
7371 int retval_int = 0;
7372 int success = FALSE;
7373
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007374 /*
7375 * Get a handle to the DLL module.
7376 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007377# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007378 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007379 (void)dlerror();
7380
Bram Moolenaar071d4272004-06-13 20:20:40 +00007381 hinstLib = dlopen((char *)libname, RTLD_LAZY
7382# ifdef RTLD_LOCAL
7383 | RTLD_LOCAL
7384# endif
7385 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007386 if (hinstLib == NULL)
7387 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007388 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007389 dlerr = (char *)dlerror();
7390 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007391 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007392 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007393# else
7394 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7395# endif
7396
Bram Moolenaar0f873732019-12-05 20:28:46 +01007397 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007398 if (hinstLib != NULL)
7399 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007400# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007401 /*
7402 * Catch a crash when calling the library function. For example when
7403 * using a number where a string pointer is expected.
7404 */
7405 mch_startjmp();
7406 if (SETJMP(lc_jump_env) != 0)
7407 {
7408 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007409# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007410 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007411# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007412 mch_didjmp();
7413 }
7414 else
7415# endif
7416 {
7417 retval_str = NULL;
7418 retval_int = 0;
7419
7420 if (argstring != NULL)
7421 {
7422# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007423 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007424 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007425# else
7426 if (shl_findsym(&hinstLib, (const char *)funcname,
7427 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7428 ProcAdd = NULL;
7429# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007430 if ((success = (ProcAdd != NULL
7431# if defined(USE_DLOPEN)
7432 && dlerr == NULL
7433# endif
7434 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435 {
7436 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007437 retval_int = ((STRPROCINT)(void *)ProcAdd)(argstring);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007438 else
7439 retval_str = (ProcAdd)(argstring);
7440 }
7441 }
7442 else
7443 {
7444# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007445 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007446 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007447# else
7448 if (shl_findsym(&hinstLib, (const char *)funcname,
7449 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7450 ProcAddI = NULL;
7451# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007452 if ((success = (ProcAddI != NULL
7453# if defined(USE_DLOPEN)
7454 && dlerr == NULL
7455# endif
7456 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007457 {
7458 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007459 retval_int = ((INTPROCINT)(void *)ProcAddI)(argint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007460 else
7461 retval_str = (ProcAddI)(argint);
7462 }
7463 }
7464
Bram Moolenaar0f873732019-12-05 20:28:46 +01007465 // Save the string before we free the library.
7466 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007467 if (string_result == NULL)
7468 *number_result = retval_int;
7469 else if (retval_str != NULL
7470 && retval_str != (char_u *)1
7471 && retval_str != (char_u *)-1)
7472 *string_result = vim_strsave(retval_str);
7473 }
7474
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007475# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007476 mch_endjmp();
7477# ifdef SIGHASARG
7478 if (lc_signal != 0)
7479 {
7480 int i;
7481
Bram Moolenaar0f873732019-12-05 20:28:46 +01007482 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007483 for (i = 0; signal_info[i].sig != -1; i++)
7484 if (lc_signal == signal_info[i].sig)
7485 break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007486 semsg("E368: got SIG%s in libcall()", signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007487 }
7488# endif
7489# endif
7490
Bram Moolenaar071d4272004-06-13 20:20:40 +00007491# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007492 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007493 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007494 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007495
Bram Moolenaar0f873732019-12-05 20:28:46 +01007496 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007497 (void)dlclose(hinstLib);
7498# else
7499 (void)shl_unload(hinstLib);
7500# endif
7501 }
7502
7503 if (!success)
7504 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007505 semsg(_(e_libcall), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007506 return FAIL;
7507 }
7508
7509 return OK;
7510}
7511#endif
7512
7513#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007514static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007515static int xterm_button;
7516
7517/*
7518 * Setup a dummy window for X selections in a terminal.
7519 */
7520 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007521setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007522{
7523 int z = 0;
7524 char *strp = "";
7525 Widget AppShell;
7526
7527 if (!x_connect_to_server())
7528 return;
7529
7530 open_app_context();
7531 if (app_context != NULL && xterm_Shell == (Widget)0)
7532 {
7533 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007534# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007535 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007536# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007537# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007538 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007539
7540 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007541 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007542# endif
7543
Bram Moolenaar0f873732019-12-05 20:28:46 +01007544 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007545 oldhandler = XSetErrorHandler(x_error_check);
7546
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007547# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007548 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007549 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7550 mch_startjmp();
7551 if (SETJMP(lc_jump_env) != 0)
7552 {
7553 mch_didjmp();
7554 xterm_dpy = NULL;
7555 }
7556 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007557# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007558 {
7559 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7560 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007561 if (xterm_dpy != NULL)
7562 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007563# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007565# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007566 }
7567
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007568# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007569 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007570 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007571# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007572 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007573 (void)XSetErrorHandler(oldhandler);
7574
7575 if (xterm_dpy == NULL)
7576 {
7577 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007578 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007579 return;
7580 }
7581
Bram Moolenaar0f873732019-12-05 20:28:46 +01007582 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007583 (void)XSetIOErrorHandler(x_IOerror_handler);
7584
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007585# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007586 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007587 {
7588 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007589 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007590 verbose_leave();
7591 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007592# endif
7593
Bram Moolenaar0f873732019-12-05 20:28:46 +01007594 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007595 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7596 applicationShellWidgetClass, xterm_dpy,
7597 NULL);
7598 if (AppShell == (Widget)0)
7599 return;
7600 xterm_Shell = XtVaCreatePopupShell("VIM",
7601 topLevelShellWidgetClass, AppShell,
7602 XtNmappedWhenManaged, 0,
7603 XtNwidth, 1,
7604 XtNheight, 1,
7605 NULL);
7606 if (xterm_Shell == (Widget)0)
7607 return;
7608
7609 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007610 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007611 if (x11_display == NULL)
7612 x11_display = xterm_dpy;
7613
7614 XtRealizeWidget(xterm_Shell);
7615 XSync(xterm_dpy, False);
7616 xterm_update();
7617 }
7618 if (xterm_Shell != (Widget)0)
7619 {
7620 clip_init(TRUE);
7621 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7622 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007623 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007624 if (test_x11_window(xterm_dpy) == FAIL)
7625 x11_window = 0;
7626 if (x11_window != 0)
7627 xterm_trace = 0;
7628 }
7629}
7630
7631 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007632start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007633{
7634 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7635 return;
7636 xterm_trace = 1;
7637 xterm_button = button;
7638 do_xterm_trace();
7639}
7640
7641
7642 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007643stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007644{
7645 if (xterm_trace < 0)
7646 return;
7647 xterm_trace = 0;
7648}
7649
7650/*
7651 * Query the xterm pointer and generate mouse termcodes if necessary
7652 * return TRUE if dragging is active, else FALSE
7653 */
7654 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007655do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007656{
7657 Window root, child;
7658 int root_x, root_y;
7659 int win_x, win_y;
7660 int row, col;
7661 int_u mask_return;
7662 char_u buf[50];
7663 char_u *strp;
7664 long got_hints;
7665 static char_u *mouse_code;
7666 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7667 static int prev_row = 0, prev_col = 0;
7668 static XSizeHints xterm_hints;
7669
7670 if (xterm_trace <= 0)
7671 return FALSE;
7672
7673 if (xterm_trace == 1)
7674 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007675 // Get the hints just before tracking starts. The font size might
7676 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007677 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7678 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007679 || xterm_hints.width_inc <= 1
7680 || xterm_hints.height_inc <= 1)
7681 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007682 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007683 return FALSE;
7684 }
7685
Bram Moolenaar0f873732019-12-05 20:28:46 +01007686 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007687 mouse_code = find_termcode(mouse_name);
7688 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007689 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007690 xterm_trace = 2;
7691
Bram Moolenaar0f873732019-12-05 20:28:46 +01007692 // Find the offset of the chars, there might be a scrollbar on the
7693 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007694 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7695 &win_x, &win_y, &mask_return);
7696 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7697 - (xterm_hints.height_inc / 2);
7698 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7699 xterm_hints.y = 2;
7700 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7701 - (xterm_hints.width_inc / 2);
7702 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7703 xterm_hints.x = 2;
7704 return TRUE;
7705 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007706 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007707 {
7708 xterm_trace = 0;
7709 return FALSE;
7710 }
7711
7712 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7713 &win_x, &win_y, &mask_return);
7714
7715 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7716 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7717 if (row == prev_row && col == prev_col)
7718 return TRUE;
7719
7720 STRCPY(buf, mouse_code);
7721 strp = buf + STRLEN(buf);
7722 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7723 *strp++ = (char_u)(col + ' ' + 1);
7724 *strp++ = (char_u)(row + ' ' + 1);
7725 *strp = 0;
7726 add_to_input_buf(buf, STRLEN(buf));
7727
7728 prev_row = row;
7729 prev_col = col;
7730 return TRUE;
7731}
7732
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007733# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007734/*
7735 * Destroy the display, window and app_context. Required for GTK.
7736 */
7737 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007738clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007739{
7740 if (xterm_Shell != (Widget)0)
7741 {
7742 XtDestroyWidget(xterm_Shell);
7743 xterm_Shell = (Widget)0;
7744 }
7745 if (xterm_dpy != NULL)
7746 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007747# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007748 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007749 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007750# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007751 if (x11_display == xterm_dpy)
7752 x11_display = NULL;
7753 xterm_dpy = NULL;
7754 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007755# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007756 if (app_context != (XtAppContext)NULL)
7757 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007758 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007759 XtDestroyApplicationContext(app_context);
7760 app_context = (XtAppContext)NULL;
7761 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007762# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007763}
7764# endif
7765
7766/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007767 * Catch up with GUI or X events.
7768 */
7769 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007770clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007771{
7772# ifdef FEAT_GUI
7773 if (gui.in_use)
7774 gui_mch_update();
7775 else
7776# endif
7777 if (xterm_Shell != (Widget)0)
7778 xterm_update();
7779}
7780
7781/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007782 * Catch up with any queued X events. This may put keyboard input into the
7783 * input buffer, call resize call-backs, trigger timers etc. If there is
7784 * nothing in the X event queue (& no timers pending), then we return
7785 * immediately.
7786 */
7787 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007788xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007789{
7790 XEvent event;
7791
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007792 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007793 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007794 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007795
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007796 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007797 break;
7798
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007799 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007800 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007801 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007802 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007803#ifdef FEAT_CLIENTSERVER
7804 {
7805 XPropertyEvent *e = (XPropertyEvent *)&event;
7806
7807 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007808 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007809 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007810 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007811#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007812 XtDispatchEvent(&event);
7813 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007814 else
7815 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007816 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007817 XtAppProcessEvent(app_context, mask);
7818 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007819 }
7820}
7821
7822 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007823clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007824{
7825 if (xterm_Shell != (Widget)0)
7826 return clip_x11_own_selection(xterm_Shell, cbd);
7827 return FAIL;
7828}
7829
7830 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007831clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007832{
7833 if (xterm_Shell != (Widget)0)
7834 clip_x11_lose_selection(xterm_Shell, cbd);
7835}
7836
7837 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007838clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007839{
7840 if (xterm_Shell != (Widget)0)
7841 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7842}
7843
7844 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007845clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007846{
7847 clip_x11_set_selection(cbd);
7848}
7849#endif
7850
7851
7852#if defined(USE_XSMP) || defined(PROTO)
7853/*
7854 * Code for X Session Management Protocol.
7855 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007856
7857# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007858/*
7859 * This is our chance to ask the user if they want to save,
7860 * or abort the logout
7861 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007862 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007863xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007864{
7865 cmdmod_T save_cmdmod;
7866 int cancel_shutdown = False;
7867
7868 save_cmdmod = cmdmod;
7869 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007870 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01007871 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00007872 cancel_shutdown = True;
7873 cmdmod = save_cmdmod;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007874 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00007875 out_flush();
7876
Bram Moolenaar0f873732019-12-05 20:28:46 +01007877 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878 SmcInteractDone(smc_conn, cancel_shutdown);
7879
Bram Moolenaar0f873732019-12-05 20:28:46 +01007880 // Finish off
7881 // Only end save-yourself here if we're not cancelling shutdown;
7882 // we'll get a cancelled callback later in which we'll end it.
7883 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007884 if (!cancel_shutdown)
7885 {
7886 xsmp.save_yourself = False;
7887 SmcSaveYourselfDone(smc_conn, True);
7888 }
7889}
7890# endif
7891
7892/*
7893 * Callback that starts save-yourself.
7894 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007895 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007896xsmp_handle_save_yourself(
7897 SmcConn smc_conn,
7898 SmPointer client_data UNUSED,
7899 int save_type UNUSED,
7900 Bool shutdown,
7901 int interact_style UNUSED,
7902 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007903{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007904 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00007905 if (xsmp.save_yourself)
7906 SmcSaveYourselfDone(smc_conn, True);
7907 xsmp.save_yourself = True;
7908 xsmp.shutdown = shutdown;
7909
Bram Moolenaar0f873732019-12-05 20:28:46 +01007910 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007911 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01007912 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007913
7914 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007915 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007916
7917# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007918 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007919 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007920 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00007921 SmcInteractRequest(smc_conn, SmDialogError,
7922 xsmp_handle_interaction, client_data);
7923 else
7924# endif
7925 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007926 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00007927 SmcSaveYourselfDone(smc_conn, True);
7928 xsmp.save_yourself = False;
7929 }
7930}
7931
7932
7933/*
7934 * Callback to warn us of imminent death.
7935 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007937xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007938{
7939 xsmp_close();
7940
Bram Moolenaar0f873732019-12-05 20:28:46 +01007941 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00007942 getout_preserve_modified(0);
7943}
7944
7945
7946/*
7947 * Callback to tell us that save-yourself has completed.
7948 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007949 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007950xsmp_save_complete(
7951 SmcConn smc_conn UNUSED,
7952 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007953{
7954 xsmp.save_yourself = False;
7955}
7956
7957
7958/*
7959 * Callback to tell us that an instigated shutdown was cancelled
7960 * (maybe even by us)
7961 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007962 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007963xsmp_shutdown_cancelled(
7964 SmcConn smc_conn,
7965 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007966{
7967 if (xsmp.save_yourself)
7968 SmcSaveYourselfDone(smc_conn, True);
7969 xsmp.save_yourself = False;
7970 xsmp.shutdown = False;
7971}
7972
7973
7974/*
7975 * Callback to tell us that a new ICE connection has been established.
7976 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007977 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007978xsmp_ice_connection(
7979 IceConn iceConn,
7980 IcePointer clientData UNUSED,
7981 Bool opening,
7982 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007983{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007984 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00007985 if (opening)
7986 {
7987 xsmp_icefd = IceConnectionNumber(iceConn);
7988 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7989 }
7990}
7991
7992
Bram Moolenaar0f873732019-12-05 20:28:46 +01007993// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00007994 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007995xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007996{
7997 Bool rep;
7998
7999 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
8000 == IceProcessMessagesIOError)
8001 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008002 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00008003 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008004 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008005 xsmp_close();
8006 return FAIL;
8007 }
8008 else
8009 return OK;
8010}
8011
8012static int dummy;
8013
Bram Moolenaar0f873732019-12-05 20:28:46 +01008014// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00008015 void
8016xsmp_init(void)
8017{
8018 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008019 SmcCallbacks smcallbacks;
8020#if 0
8021 SmPropValue smname;
8022 SmProp smnameprop;
8023 SmProp *smprops[1];
8024#endif
8025
8026 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008027 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008028
8029 xsmp.save_yourself = xsmp.shutdown = False;
8030
Bram Moolenaar0f873732019-12-05 20:28:46 +01008031 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008032 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8033 smcallbacks.save_yourself.client_data = NULL;
8034 smcallbacks.die.callback = xsmp_die;
8035 smcallbacks.die.client_data = NULL;
8036 smcallbacks.save_complete.callback = xsmp_save_complete;
8037 smcallbacks.save_complete.client_data = NULL;
8038 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8039 smcallbacks.shutdown_cancelled.client_data = NULL;
8040
Bram Moolenaar0f873732019-12-05 20:28:46 +01008041 // Set up a watch on ICE connection creations. The "dummy" argument is
8042 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008043 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8044 {
8045 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008046 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008047 return;
8048 }
8049
Bram Moolenaar0f873732019-12-05 20:28:46 +01008050 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008051 xsmp.smcconn = SmcOpenConnection(
8052 NULL,
8053 NULL,
8054 SmProtoMajor,
8055 SmProtoMinor,
8056 SmcSaveYourselfProcMask | SmcDieProcMask
8057 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8058 &smcallbacks,
8059 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008060 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008061 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008062 errorstring);
8063 if (xsmp.smcconn == NULL)
8064 {
8065 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00008066
Bram Moolenaar071d4272004-06-13 20:20:40 +00008067 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008068 {
8069 vim_snprintf(errorreport, sizeof(errorreport),
8070 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008071 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008072 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008073 return;
8074 }
8075 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8076
8077#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008078 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008079 smname.value = "vim";
8080 smname.length = 3;
8081 smnameprop.name = "SmProgram";
8082 smnameprop.type = "SmARRAY8";
8083 smnameprop.num_vals = 1;
8084 smnameprop.vals = &smname;
8085
8086 smprops[0] = &smnameprop;
8087 SmcSetProperties(xsmp.smcconn, 1, smprops);
8088#endif
8089}
8090
8091
Bram Moolenaar0f873732019-12-05 20:28:46 +01008092// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008093 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008094xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008095{
8096 if (xsmp_icefd != -1)
8097 {
8098 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008099 if (xsmp.clientid != NULL)
8100 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008101 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008102 xsmp_icefd = -1;
8103 }
8104}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008105#endif // USE_XSMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008106
8107
8108#ifdef EBCDIC
Bram Moolenaar0f873732019-12-05 20:28:46 +01008109// Translate character to its CTRL- value
Bram Moolenaar071d4272004-06-13 20:20:40 +00008110char CtrlTable[] =
8111{
8112/* 00 - 5E */
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, 0,
8117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8119/* ^ */ 0x1E,
8120/* - */ 0x1F,
8121/* 61 - 6C */
8122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8123/* _ */ 0x1F,
8124/* 6E - 80 */
8125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8126/* a */ 0x01,
8127/* b */ 0x02,
8128/* c */ 0x03,
8129/* d */ 0x37,
8130/* e */ 0x2D,
8131/* f */ 0x2E,
8132/* g */ 0x2F,
8133/* h */ 0x16,
8134/* i */ 0x05,
8135/* 8A - 90 */
8136 0, 0, 0, 0, 0, 0, 0,
8137/* j */ 0x15,
8138/* k */ 0x0B,
8139/* l */ 0x0C,
8140/* m */ 0x0D,
8141/* n */ 0x0E,
8142/* o */ 0x0F,
8143/* p */ 0x10,
8144/* q */ 0x11,
8145/* r */ 0x12,
8146/* 9A - A1 */
8147 0, 0, 0, 0, 0, 0, 0, 0,
8148/* s */ 0x13,
8149/* t */ 0x3C,
8150/* u */ 0x3D,
8151/* v */ 0x32,
8152/* w */ 0x26,
8153/* x */ 0x18,
8154/* y */ 0x19,
8155/* z */ 0x3F,
8156/* AA - AC */
8157 0, 0, 0,
8158/* [ */ 0x27,
8159/* AE - BC */
8160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8161/* ] */ 0x1D,
8162/* BE - C0 */ 0, 0, 0,
8163/* A */ 0x01,
8164/* B */ 0x02,
8165/* C */ 0x03,
8166/* D */ 0x37,
8167/* E */ 0x2D,
8168/* F */ 0x2E,
8169/* G */ 0x2F,
8170/* H */ 0x16,
8171/* I */ 0x05,
8172/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8173/* J */ 0x15,
8174/* K */ 0x0B,
8175/* L */ 0x0C,
8176/* M */ 0x0D,
8177/* N */ 0x0E,
8178/* O */ 0x0F,
8179/* P */ 0x10,
8180/* Q */ 0x11,
8181/* R */ 0x12,
8182/* DA - DF */ 0, 0, 0, 0, 0, 0,
8183/* \ */ 0x1C,
8184/* E1 */ 0,
8185/* S */ 0x13,
8186/* T */ 0x3C,
8187/* U */ 0x3D,
8188/* V */ 0x32,
8189/* W */ 0x26,
8190/* X */ 0x18,
8191/* Y */ 0x19,
8192/* Z */ 0x3F,
8193/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8195};
8196
8197char MetaCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008198{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008199 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8200 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8201 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8202 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8203};
8204
8205
Bram Moolenaar0f873732019-12-05 20:28:46 +01008206// TODO: Use characters NOT numbers!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +00008207char CtrlCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008208{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008209 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8210 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8211 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8212 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8213};
8214
8215
8216#endif